Skip to content

Commit

Permalink
Merge pull request #801 from jonhoo/ffi-strings
Browse files Browse the repository at this point in the history
impls for null-terminated FFI string types
  • Loading branch information
dtolnay committed Mar 5, 2017
2 parents d70636f + d294a10 commit 2f988aa
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 0 deletions.
18 changes: 18 additions & 0 deletions serde/src/de/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use std::net;
#[cfg(feature = "std")]
use std::path;
use core::str;
#[cfg(feature = "std")]
use std::ffi::CString;

#[cfg(feature = "std")]
use std::rc::Rc;
Expand Down Expand Up @@ -53,6 +55,9 @@ use de::{Deserialize, Deserializer, EnumVisitor, Error, MapVisitor, SeqVisitor,
VariantVisitor, Visitor};
use de::from_primitive::FromPrimitive;

#[cfg(feature = "std")]
use bytes::ByteBuf;

///////////////////////////////////////////////////////////////////////////////

/// A visitor that produces a `()`.
Expand Down Expand Up @@ -295,6 +300,19 @@ impl Deserialize for String {

///////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "std")]
impl Deserialize for CString {
fn deserialize<D>(deserializer: D) -> Result<CString, D::Error>
where D: Deserializer
{
let v: Vec<u8> = try!(ByteBuf::deserialize(deserializer)).into();
CString::new(v)
.map_err(|e| Error::custom(format!("unexpected NULL at byte {}", e.nul_position())))
}
}

///////////////////////////////////////////////////////////////////////////////

struct OptionVisitor<T> {
marker: PhantomData<T>,
}
Expand Down
24 changes: 24 additions & 0 deletions serde/src/ser/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use core::ops;
#[cfg(feature = "std")]
use std::path;
#[cfg(feature = "std")]
use std::ffi::{CString, CStr};
#[cfg(feature = "std")]
use std::rc::Rc;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::rc::Rc;
Expand Down Expand Up @@ -98,6 +100,28 @@ impl Serialize for String {

///////////////////////////////////////////////////////////////////////////////

#[cfg(feature = "std")]
impl Serialize for CStr {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(self.to_bytes())
}
}

#[cfg(feature = "std")]
impl Serialize for CString {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(self.to_bytes())
}
}

///////////////////////////////////////////////////////////////////////////////

impl<T> Serialize for Option<T>
where T: Serialize
{
Expand Down
18 changes: 18 additions & 0 deletions test_suite/tests/test_de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::net;
use std::path::PathBuf;
use std::time::Duration;
use std::default::Default;
use std::ffi::CString;

extern crate serde;
use serde::Deserialize;
Expand Down Expand Up @@ -878,6 +879,11 @@ declare_tests! {
Token::String("/usr/local/lib".to_owned()),
],
}
test_cstring {
CString::new("abc").unwrap() => &[
Token::Bytes(b"abc"),
],
}
}

#[cfg(feature = "unstable")]
Expand Down Expand Up @@ -995,4 +1001,16 @@ declare_error_tests! {
],
Error::Message("invalid length 1, expected an array of length 3".into()),
}
test_cstring_internal_null<CString> {
&[
Token::Bytes(b"a\0c"),
],
Error::Message("unexpected NULL at byte 1".into()),
}
test_cstring_internal_null_end<CString> {
&[
Token::Bytes(b"ac\0"),
],
Error::Message("unexpected NULL at byte 2".into()),
}
}
11 changes: 11 additions & 0 deletions test_suite/tests/test_ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::net;
use std::path::{Path, PathBuf};
use std::str;
use std::time::Duration;
use std::ffi::CString;

extern crate serde;

Expand Down Expand Up @@ -389,6 +390,16 @@ declare_tests! {
Token::Str("/usr/local/lib"),
],
}
test_cstring {
CString::new("abc").unwrap() => &[
Token::Bytes(b"abc"),
],
}
test_cstr {
(&*CString::new("abc").unwrap()) => &[
Token::Bytes(b"abc"),
],
}
}


Expand Down

0 comments on commit 2f988aa

Please sign in to comment.