From 749d82a33f6e4aa89542bbd6ca739501d9dd346c Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Thu, 30 Aug 2018 08:28:42 +0800 Subject: [PATCH 1/3] Added TryFromCtx impls for Cstr --- src/ctx.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/ctx.rs b/src/ctx.rs index 42f622c..4be6d93 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -50,6 +50,9 @@ use core::mem::size_of; use core::str; use core::result; +#[cfg(feature = "std")] +use std::ffi::{CStr, CString}; + use error; use endian::Endian; @@ -513,6 +516,38 @@ impl TryIntoCtx for usize where usize: IntoCtx { } } +#[cfg(feature = "std")] +impl<'a> TryFromCtx<'a> for &'a CStr { + type Error = error::Error; + type Size = usize; + #[inline] + fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, Self::Size), Self::Error> { + let null_byte = match src.iter().position(|b| *b == 0) { + Some(ix) => ix, + None => return Err(error::Error::BadInput { + size: 0, + msg: "The input doesn't contain a null byte", + }) + }; + + let data = src.get(..null_byte+1).unwrap(); + + let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(data) }; + Ok((cstr, null_byte+1)) + } +} + +#[cfg(feature = "std")] +impl<'a> TryFromCtx<'a> for CString { + type Error = error::Error; + type Size = usize; + #[inline] + fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, Self::Size), Self::Error> { + let (raw, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(src, _ctx)?; + Ok((raw.to_owned(), bytes_read)) + } +} + // example of marshalling to bytes, let's wait until const is an option // impl FromCtx for [u8; 10] { // fn from_ctx(bytes: &[u8], _ctx: Endian) -> Self { @@ -524,3 +559,21 @@ impl TryIntoCtx for usize where usize: IntoCtx { // dst // } // } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(feature = "std")] + fn parse_a_cstr() { + let src = CString::new("Hello World").unwrap(); + let as_bytes = src.as_bytes_with_nul(); + + let (got, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(as_bytes, ()).unwrap(); + + assert_eq!(bytes_read, as_bytes.len()); + assert_eq!(got, src.as_c_str()); + } +} + From 84c9438a27cee923944774f8ac92f9d13b66c287 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Thu, 30 Aug 2018 08:39:04 +0800 Subject: [PATCH 2/3] Added TryIntoCtx impls for CStr --- src/ctx.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/ctx.rs b/src/ctx.rs index 4be6d93..e386fbf 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -548,6 +548,40 @@ impl<'a> TryFromCtx<'a> for CString { } } +#[cfg(feature = "std")] +impl<'a> TryIntoCtx for &'a CStr { + type Error = error::Error; + type Size = usize; + #[inline] + fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result { + let data = self.to_bytes_with_nul(); + + if dst.len() < data.len() { + Err(error::Error::TooBig { + size: dst.len(), + len: data.len(), + }) + } else { + unsafe { + copy_nonoverlapping(data.as_ptr(), dst.as_mut_ptr(), data.len()); + } + + Ok(data.len()) + } + } +} + +#[cfg(feature = "std")] +impl TryIntoCtx for CString { + type Error = error::Error; + type Size = usize; + #[inline] + fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result { + self.as_c_str().try_into_ctx(dst, _ctx) + } +} + + // example of marshalling to bytes, let's wait until const is an option // impl FromCtx for [u8; 10] { // fn from_ctx(bytes: &[u8], _ctx: Endian) -> Self { @@ -575,5 +609,23 @@ mod tests { assert_eq!(bytes_read, as_bytes.len()); assert_eq!(got, src.as_c_str()); } + + #[test] + #[cfg(feature = "std")] + fn round_trip_a_c_str() { + let src = CString::new("Hello World").unwrap(); + let src = src.as_c_str(); + let as_bytes = src.to_bytes_with_nul(); + + let mut buffer = vec![0; as_bytes.len()]; + let bytes_written = src.try_into_ctx(&mut buffer, ()).unwrap(); + assert_eq!(bytes_written, as_bytes.len()); + + let (got, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(&buffer, ()).unwrap(); + + assert_eq!(bytes_read, as_bytes.len()); + assert_eq!(got, src); + } } + From 2d8166e8da6592fa331e9ba7300500653ce8569d Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Wed, 5 Sep 2018 20:48:20 +0800 Subject: [PATCH 3/3] Replaced the `get().unwrap()` with a normal `&src[..end]` --- src/ctx.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ctx.rs b/src/ctx.rs index e386fbf..1c5ffd4 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -530,9 +530,7 @@ impl<'a> TryFromCtx<'a> for &'a CStr { }) }; - let data = src.get(..null_byte+1).unwrap(); - - let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(data) }; + let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(&src[..null_byte+1]) }; Ok((cstr, null_byte+1)) } }