diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index ba0acae2..2946dcfe 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -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; @@ -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 `()`. @@ -295,6 +300,19 @@ impl Deserialize for String { /////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "std")] +impl Deserialize for CString { + fn deserialize(deserializer: D) -> Result + where D: Deserializer + { + let v: Vec = try!(ByteBuf::deserialize(deserializer)).into(); + CString::new(v) + .map_err(|e| Error::custom(format!("unexpected NULL at byte {}", e.nul_position()))) + } +} + +/////////////////////////////////////////////////////////////////////////////// + struct OptionVisitor { marker: PhantomData, } diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs index a7ac780f..4c7a263f 100644 --- a/serde/src/ser/impls.rs +++ b/serde/src/ser/impls.rs @@ -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; @@ -98,6 +100,28 @@ impl Serialize for String { /////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "std")] +impl Serialize for CStr { + #[inline] + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + serializer.serialize_bytes(self.to_bytes()) + } +} + +#[cfg(feature = "std")] +impl Serialize for CString { + #[inline] + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + serializer.serialize_bytes(self.to_bytes()) + } +} + +/////////////////////////////////////////////////////////////////////////////// + impl Serialize for Option where T: Serialize { diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index f4112428..8e79f1f1 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -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; @@ -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")] @@ -995,4 +1001,16 @@ declare_error_tests! { ], Error::Message("invalid length 1, expected an array of length 3".into()), } + test_cstring_internal_null { + &[ + Token::Bytes(b"a\0c"), + ], + Error::Message("unexpected NULL at byte 1".into()), + } + test_cstring_internal_null_end { + &[ + Token::Bytes(b"ac\0"), + ], + Error::Message("unexpected NULL at byte 2".into()), + } } diff --git a/test_suite/tests/test_ser.rs b/test_suite/tests/test_ser.rs index e1f298ea..72ed3f0c 100644 --- a/test_suite/tests/test_ser.rs +++ b/test_suite/tests/test_ser.rs @@ -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; @@ -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"), + ], + } }