1 //! Generic context-aware conversion traits, for automatic _downstream_ extension of `Pread`, et. al
3 //! The context traits are arguably the center piece of the scroll crate. In simple terms they
4 //! define how to actually read and write, respectively, a data type from a container, being able to
5 //! take context into account.
9 //! Types implementing [TryFromCtx](trait.TryFromCtx.html) and it's infallible cousin [FromCtx](trait.FromCtx.html)
10 //! allow a user of [Pread::pread](../trait.Pread.html#method.pread) or respectively
11 //! [Cread::cread](../trait.Cread.html#method.cread) and
12 //! [IOread::ioread](../trait.IOread.html#method.ioread) to read that data type from a data source one
13 //! of the `*read` traits has been implemented for.
15 //! Implementations of `TryFromCtx` specify a source (called `This`) and an `Error` type for failed
16 //! reads. The source defines the kind of container the type can be read from, and defaults to
17 //! `[u8]` for any type that implements `AsRef<[u8]>`.
19 //! `FromCtx` is slightly more restricted; it requires the implementer to use `[u8]` as source and
20 //! never fail, and thus does not have an `Error` type.
22 //! Types chosen here are of relevance to `Pread` implementations; of course only a container which
23 //! can produce a source of the type `This` can be used to read a `TryFromCtx` requiring it and the
24 //! `Error` type returned in `Err` of `Pread::pread`'s Result.
28 //! [TryIntoCtx](trait.TryIntoCtx.html) and the infallible [IntoCtx](trait.IntoCtx.html) work
29 //! similarly to the above traits, allowing [Pwrite::pwrite](../trait.Pwrite.html#method.pwrite) or
30 //! respectively [Cwrite::cwrite](../trait.Cwrite.html#method.cwrite) and
31 //! [IOwrite::iowrite](../trait.IOwrite.html#method.iowrite) to write data into a byte sink for
32 //! which one of the `*write` traits has been implemented for.
34 //! `IntoCtx` is similarly restricted as `FromCtx` is to `TryFromCtx`. And equally the types chosen
35 //! affect usable `Pwrite` implementation.
39 //! Each of the traits passes along a `Ctx` to the marshalling logic. This context type contains
40 //! any additional information that may be required to successfully parse or write the data:
41 //! Examples would be endianness to use, field lengths of a serialized struct, or delimiters to use
42 //! when reading/writing `&str`. The context type can be any type but must derive
43 //! [Copy](https://doc.rust-lang.org/std/marker/trait.Copy.html). In addition if you want to use
44 //! the `*read`-methods instead of the `*read_with` ones you must also implement
45 //! [default::Default](https://doc.rust-lang.org/std/default/trait.Default.html).
49 //! Let's expand on the [previous example](../index.html#complex-use-cases).
52 //! use scroll::{self, ctx, Pread, Endian};
53 //! use scroll::ctx::StrCtx;
55 //! #[derive(Copy, Clone, PartialEq, Eq)]
61 //! // Our custom context type. As said above it has to derive Copy.
62 //! #[derive(Copy, Clone)]
64 //! fieldsize: FieldSize,
65 //! endianess: Endian,
68 //! // Our custom data type
70 //! // These u64 are encoded either as 32-bit or 64-bit wide ints. Which one it is is defined in
72 //! // Also, let's imagine they have a strict relationship: A < B < C otherwise the struct is
78 //! // Both of these are marshalled with a prefixed length.
85 //! // We'll return this custom error if the field* relationship doesn't hold
87 //! Scroll(scroll::Error),
90 //! impl<'a> ctx::TryFromCtx<'a, Context> for Data<'a> {
91 //! type Error = Error;
93 //! // Using the explicit lifetime specification again you ensure that read data doesn't outlife
94 //! // its source buffer without having to resort to copying.
95 //! fn try_from_ctx (src: &'a [u8], ctx: Context)
96 //! // the `usize` returned here is the amount of bytes read.
97 //! -> Result<(Self, usize), Self::Error>
99 //! // The offset counter; gread and gread_with increment a given counter automatically so we
100 //! // don't have to manually care.
101 //! let offset = &mut 0;
107 //! // Switch the amount of bytes read depending on the parsing context
108 //! if ctx.fieldsize == FieldSize::U32 {
109 //! field_a = src.gread_with::<u32>(offset, ctx.endianess)? as u64;
110 //! field_b = src.gread_with::<u32>(offset, ctx.endianess)? as u64;
111 //! field_c = src.gread_with::<u32>(offset, ctx.endianess)? as u64;
113 //! field_a = src.gread_with::<u64>(offset, ctx.endianess)?;
114 //! field_b = src.gread_with::<u64>(offset, ctx.endianess)?;
115 //! field_c = src.gread_with::<u64>(offset, ctx.endianess)?;
118 //! // You can use type ascribition or turbofish operators, whichever you prefer.
119 //! let namelen = src.gread_with::<u16>(offset, ctx.endianess)? as usize;
120 //! let name: &str = src.gread_with(offset, scroll::ctx::StrCtx::Length(namelen))?;
122 //! let vallen = src.gread_with::<u16>(offset, ctx.endianess)? as usize;
123 //! let value = &src[*offset..(*offset+vallen)];
125 //! // Let's sanity check those fields, shall we?
126 //! if ! (field_a < field_b && field_b < field_c) {
127 //! return Err(Error::BadFieldMatchup);
130 //! Ok((Data { field_a, field_b, field_c, name, value }, *offset))
134 //! // In lieu of a complex byte buffer we hearken back to the venerable &[u8]; do note however
135 //! // that the implementation of TryFromCtx did not specify such. In fact any type that implements
136 //! // Pread can now read `Data` as it implements TryFromCtx.
137 //! let bytes = b"\x00\x02\x03\x04\x01\x02\x03\x04\xde\xad\xbe\xef\x00\x08UserName\x00\x02\xCA\xFE";
139 //! // We define an appropiate context, and get going
140 //! let contextA = Context {
141 //! fieldsize: FieldSize::U32,
142 //! endianess: Endian::Big,
144 //! let data: Data = bytes.pread_with(0, contextA).unwrap();
146 //! assert_eq!(data.field_a, 0x00020304);
147 //! assert_eq!(data.field_b, 0x01020304);
148 //! assert_eq!(data.field_c, 0xdeadbeef);
149 //! assert_eq!(data.name, "UserName");
150 //! assert_eq!(data.value, [0xCA, 0xFE]);
152 //! // Here we have a context with a different FieldSize, changing parsing information at runtime.
153 //! let contextB = Context {
154 //! fieldsize: FieldSize::U64,
155 //! endianess: Endian::Big,
158 //! // Which will of course error with a malformed input for the context
159 //! let err: Result<Data, Error> = bytes.pread_with(0, contextB);
160 //! assert!(err.is_err());
162 //! let bytes_long = [0x00,0x00,0x00,0x00,0x00,0x02,0x03,0x04,0x00,0x00,0x00,0x00,0x01,0x02,0x03,
163 //! 0x04,0x00,0x00,0x00,0x00,0xde,0xad,0xbe,0xef,0x00,0x08,0x55,0x73,0x65,0x72,
164 //! 0x4e,0x61,0x6d,0x65,0x00,0x02,0xCA,0xFE];
166 //! let data: Data = bytes_long.pread_with(0, contextB).unwrap();
168 //! assert_eq!(data.field_a, 0x00020304);
169 //! assert_eq!(data.field_b, 0x01020304);
170 //! assert_eq!(data.field_c, 0xdeadbeef);
171 //! assert_eq!(data.name, "UserName");
172 //! assert_eq!(data.value, [0xCA, 0xFE]);
174 //! // Ergonomic conversion, not relevant really.
175 //! use std::convert::From;
176 //! impl From<scroll::Error> for Error {
177 //! fn from(error: scroll::Error) -> Error {
178 //! Error::Scroll(error)
183 use core::mem::size_of;
184 use core::mem::transmute;
185 use core::ptr::copy_nonoverlapping;
189 #[cfg(feature = "std")]
190 use std::ffi::{CStr, CString};
192 use crate::endian::Endian;
195 /// A trait for measuring how large something is; for a byte sequence, it will be its length.
196 pub trait MeasureWith<Ctx> {
197 /// How large is `Self`, given the `ctx`?
198 fn measure_with(&self, ctx: &Ctx) -> usize;
201 impl<Ctx> MeasureWith<Ctx> for [u8] {
203 fn measure_with(&self, _ctx: &Ctx) -> usize {
208 impl<Ctx, T: AsRef<[u8]>> MeasureWith<Ctx> for T {
210 fn measure_with(&self, _ctx: &Ctx) -> usize {
215 /// The parsing context for converting a byte sequence to a `&str`
217 /// `StrCtx` specifies what byte delimiter to use, and defaults to C-style null terminators. Be careful.
218 #[derive(Debug, Copy, Clone)]
221 DelimiterUntil(u8, usize),
225 /// A C-style, null terminator based delimiter
226 pub const NULL: u8 = 0;
227 /// A space-based delimiter
228 pub const SPACE: u8 = 0x20;
229 /// A newline-based delimiter
230 pub const RET: u8 = 0x0a;
231 /// A tab-based delimiter
232 pub const TAB: u8 = 0x09;
234 impl Default for StrCtx {
236 fn default() -> Self {
237 StrCtx::Delimiter(NULL)
242 pub fn len(&self) -> usize {
244 StrCtx::Delimiter(_) | StrCtx::DelimiterUntil(_, _) => 1,
245 StrCtx::Length(_) => 0,
249 pub fn is_empty(&self) -> bool {
250 if let StrCtx::Length(_) = *self {
258 /// Reads `Self` from `This` using the context `Ctx`; must _not_ fail
259 pub trait FromCtx<Ctx: Copy = (), This: ?Sized = [u8]> {
260 fn from_ctx(this: &This, ctx: Ctx) -> Self;
263 /// Tries to read `Self` from `This` using the context `Ctx`
265 /// # Implementing Your Own Reader
266 /// If you want to implement your own reader for a type `Foo` from some kind of buffer (say
267 /// `[u8]`), then you need to implement this trait
270 /// use scroll::{self, ctx, Pread};
271 /// #[derive(Debug, PartialEq, Eq)]
272 /// pub struct Foo(u16);
274 /// impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Foo {
275 /// type Error = scroll::Error;
276 /// fn try_from_ctx(this: &'a [u8], le: scroll::Endian) -> Result<(Self, usize), Self::Error> {
277 /// if this.len() < 2 { return Err((scroll::Error::Custom("whatever".to_string())).into()) }
278 /// let n = this.pread_with(0, le)?;
283 /// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
284 /// let foo = bytes.pread_with::<Foo>(0, scroll::LE).unwrap();
285 /// assert_eq!(Foo(0xadde), foo);
287 /// let foo2 = bytes.pread_with::<Foo>(0, scroll::BE).unwrap();
288 /// assert_eq!(Foo(0xdeadu16), foo2);
291 /// # Advanced: Using Your Own Error in `TryFromCtx`
293 /// use scroll::{self, ctx, Pread};
295 /// use std::fmt::{self, Display};
296 /// // make some kind of normal error which also can transformed from a scroll error
298 /// pub struct ExternalError {}
300 /// impl Display for ExternalError {
301 /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
302 /// write!(fmt, "ExternalError")
306 /// impl error::Error for ExternalError {
307 /// fn description(&self) -> &str {
310 /// fn cause(&self) -> Option<&dyn error::Error> { None}
313 /// impl From<scroll::Error> for ExternalError {
314 /// fn from(err: scroll::Error) -> Self {
316 /// _ => ExternalError{},
320 /// #[derive(Debug, PartialEq, Eq)]
321 /// pub struct Foo(u16);
323 /// impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Foo {
324 /// type Error = ExternalError;
325 /// fn try_from_ctx(this: &'a [u8], le: scroll::Endian) -> Result<(Self, usize), Self::Error> {
326 /// if this.len() <= 2 { return Err((ExternalError {}).into()) }
327 /// let offset = &mut 0;
328 /// let n = this.gread_with(offset, le)?;
329 /// Ok((Foo(n), *offset))
333 /// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
334 /// let foo: Result<Foo, ExternalError> = bytes.pread(0);
336 pub trait TryFromCtx<'a, Ctx: Copy = (), This: ?Sized = [u8]>
341 fn try_from_ctx(from: &'a This, ctx: Ctx) -> Result<(Self, usize), Self::Error>;
344 /// Writes `Self` into `This` using the context `Ctx`
345 pub trait IntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
346 fn into_ctx(self, _: &mut This, ctx: Ctx);
349 /// Tries to write `Self` into `This` using the context `Ctx`
350 /// To implement writing into an arbitrary byte buffer, implement `TryIntoCtx`
353 /// use scroll::{self, ctx, LE, Endian, Pwrite};
354 /// #[derive(Debug, PartialEq, Eq)]
355 /// pub struct Foo(u16);
357 /// // this will use the default `DefaultCtx = scroll::Endian`
358 /// impl ctx::TryIntoCtx<Endian> for Foo {
359 /// // you can use your own error here too, but you will then need to specify it in fn generic parameters
360 /// type Error = scroll::Error;
361 /// // you can write using your own context type, see `leb128.rs`
362 /// fn try_into_ctx(self, this: &mut [u8], le: Endian) -> Result<usize, Self::Error> {
363 /// if this.len() < 2 { return Err((scroll::Error::Custom("whatever".to_string())).into()) }
364 /// this.pwrite_with(self.0, 0, le)?;
368 /// // now we can write a `Foo` into some buffer (in this case, a byte buffer, because that's what we implemented it for above)
370 /// let mut bytes: [u8; 4] = [0, 0, 0, 0];
371 /// bytes.pwrite_with(Foo(0x7f), 1, LE).unwrap();
373 pub trait TryIntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
375 fn try_into_ctx(self, _: &mut This, ctx: Ctx) -> Result<usize, Self::Error>;
378 /// Gets the size of `Self` with a `Ctx`, and in `Self::Units`. Implementors can then call `Gread` related functions
380 /// The rationale behind this trait is to:
382 /// 1. Prevent `gread` from being used, and the offset being modified based on simply the sizeof the value, which can be a misnomer, e.g., for Leb128, etc.
383 /// 2. Allow a context based size, which is useful for 32/64 bit variants for various containers, etc.
384 pub trait SizeWith<Ctx = ()> {
385 fn size_with(ctx: &Ctx) -> usize;
389 macro_rules! signed_to_unsigned {
404 macro_rules! write_into {
405 ($typ:ty, $size:expr, $n:expr, $dst:expr, $endian:expr) => {{
407 assert!($dst.len() >= $size);
408 let bytes = transmute::<$typ, [u8; $size]>(if $endian.is_little() {
413 copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size);
418 macro_rules! into_ctx_impl {
419 ($typ:tt, $size:expr) => {
420 impl IntoCtx<Endian> for $typ {
422 fn into_ctx(self, dst: &mut [u8], le: Endian) {
423 assert!(dst.len() >= $size);
424 write_into!($typ, $size, self, dst, le);
427 impl<'a> IntoCtx<Endian> for &'a $typ {
429 fn into_ctx(self, dst: &mut [u8], le: Endian) {
430 (*self).into_ctx(dst, le)
433 impl TryIntoCtx<Endian> for $typ
435 $typ: IntoCtx<Endian>,
437 type Error = error::Error;
439 fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
440 if $size > dst.len() {
441 Err(error::Error::TooBig {
446 <$typ as IntoCtx<Endian>>::into_ctx(self, dst, le);
451 impl<'a> TryIntoCtx<Endian> for &'a $typ {
452 type Error = error::Error;
454 fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
455 (*self).try_into_ctx(dst, le)
461 macro_rules! from_ctx_impl {
462 ($typ:tt, $size:expr) => {
463 impl<'a> FromCtx<Endian> for $typ {
465 fn from_ctx(src: &[u8], le: Endian) -> Self {
466 assert!(src.len() >= $size);
467 let mut data: signed_to_unsigned!($typ) = 0;
471 &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
483 impl<'a> TryFromCtx<'a, Endian> for $typ
485 $typ: FromCtx<Endian>,
487 type Error = error::Error;
492 ) -> result::Result<(Self, usize), Self::Error> {
493 if $size > src.len() {
494 Err(error::Error::TooBig {
499 Ok((FromCtx::from_ctx(&src, le), $size))
504 impl<'a, T> FromCtx<Endian, T> for $typ
509 fn from_ctx(src: &T, le: Endian) -> Self {
510 let src = src.as_ref();
511 assert!(src.len() >= $size);
512 let mut data: signed_to_unsigned!($typ) = 0;
516 &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
528 impl<'a, T> TryFromCtx<'a, Endian, T> for $typ
530 $typ: FromCtx<Endian, T>,
533 type Error = error::Error;
535 fn try_from_ctx(src: &'a T, le: Endian) -> result::Result<(Self, usize), Self::Error> {
536 let src = src.as_ref();
537 Self::try_from_ctx(src, le)
543 macro_rules! ctx_impl {
544 ($typ:tt, $size:expr) => {
545 from_ctx_impl!($typ, $size);
560 macro_rules! from_ctx_float_impl {
561 ($typ:tt, $size:expr) => {
562 impl<'a> FromCtx<Endian> for $typ {
564 fn from_ctx(src: &[u8], le: Endian) -> Self {
565 assert!(src.len() >= ::core::mem::size_of::<Self>());
566 let mut data: signed_to_unsigned!($typ) = 0;
570 &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
573 transmute(if le.is_little() {
581 impl<'a> TryFromCtx<'a, Endian> for $typ
583 $typ: FromCtx<Endian>,
585 type Error = error::Error;
590 ) -> result::Result<(Self, usize), Self::Error> {
591 if $size > src.len() {
592 Err(error::Error::TooBig {
597 Ok((FromCtx::from_ctx(src, le), $size))
604 from_ctx_float_impl!(f32, 4);
605 from_ctx_float_impl!(f64, 8);
607 into_ctx_impl!(u8, 1);
608 into_ctx_impl!(i8, 1);
609 into_ctx_impl!(u16, 2);
610 into_ctx_impl!(i16, 2);
611 into_ctx_impl!(u32, 4);
612 into_ctx_impl!(i32, 4);
613 into_ctx_impl!(u64, 8);
614 into_ctx_impl!(i64, 8);
615 into_ctx_impl!(u128, 16);
616 into_ctx_impl!(i128, 16);
618 macro_rules! into_ctx_float_impl {
619 ($typ:tt, $size:expr) => {
620 impl IntoCtx<Endian> for $typ {
622 fn into_ctx(self, dst: &mut [u8], le: Endian) {
623 assert!(dst.len() >= $size);
625 signed_to_unsigned!($typ),
627 transmute::<$typ, signed_to_unsigned!($typ)>(self),
633 impl<'a> IntoCtx<Endian> for &'a $typ {
635 fn into_ctx(self, dst: &mut [u8], le: Endian) {
636 (*self).into_ctx(dst, le)
639 impl TryIntoCtx<Endian> for $typ
641 $typ: IntoCtx<Endian>,
643 type Error = error::Error;
645 fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
646 if $size > dst.len() {
647 Err(error::Error::TooBig {
652 <$typ as IntoCtx<Endian>>::into_ctx(self, dst, le);
657 impl<'a> TryIntoCtx<Endian> for &'a $typ {
658 type Error = error::Error;
660 fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
661 (*self).try_into_ctx(dst, le)
667 into_ctx_float_impl!(f32, 4);
668 into_ctx_float_impl!(f64, 8);
670 impl<'a> TryFromCtx<'a, StrCtx> for &'a str {
671 type Error = error::Error;
673 /// Read a `&str` from `src` using `delimiter`
674 fn try_from_ctx(src: &'a [u8], ctx: StrCtx) -> Result<(Self, usize), Self::Error> {
675 let len = match ctx {
676 StrCtx::Length(len) => len,
677 StrCtx::Delimiter(delimiter) => src.iter().take_while(|c| **c != delimiter).count(),
678 StrCtx::DelimiterUntil(delimiter, len) => {
680 return Err(error::Error::TooBig {
686 .take_while(|c| **c != delimiter)
693 return Err(error::Error::TooBig {
699 match str::from_utf8(&src[..len]) {
700 Ok(res) => Ok((res, len + ctx.len())),
701 Err(_) => Err(error::Error::BadInput {
709 impl<'a, T> TryFromCtx<'a, StrCtx, T> for &'a str
713 type Error = error::Error;
715 fn try_from_ctx(src: &'a T, ctx: StrCtx) -> result::Result<(Self, usize), Self::Error> {
716 let src = src.as_ref();
717 TryFromCtx::try_from_ctx(src, ctx)
721 impl<'a> TryIntoCtx for &'a [u8] {
722 type Error = error::Error;
724 fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
725 let src_len = self.len() as isize;
726 let dst_len = dst.len() as isize;
727 // if src_len < 0 || dst_len < 0 || offset < 0 {
728 // return Err(error::Error::BadOffset(format!("requested operation has negative casts: src len: {} dst len: {} offset: {}", src_len, dst_len, offset)).into())
730 if src_len > dst_len {
731 Err(error::Error::TooBig {
736 unsafe { copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), src_len as usize) };
742 // TODO: make TryIntoCtx use StrCtx for awesomeness
743 impl<'a> TryIntoCtx for &'a str {
744 type Error = error::Error;
746 fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
747 let bytes = self.as_bytes();
748 TryIntoCtx::try_into_ctx(bytes, dst, ())
752 // TODO: we can make this compile time without size_of call, but compiler probably does that anyway
753 macro_rules! sizeof_impl {
755 impl SizeWith<Endian> for $ty {
757 fn size_with(_ctx: &Endian) -> usize {
777 impl<'a> TryFromCtx<'a, usize> for &'a [u8] {
778 type Error = error::Error;
780 fn try_from_ctx(src: &'a [u8], size: usize) -> result::Result<(Self, usize), Self::Error> {
781 if size > src.len() {
782 Err(error::Error::TooBig {
787 Ok((&src[..size], size))
792 #[cfg(feature = "std")]
793 impl<'a> TryFromCtx<'a> for &'a CStr {
794 type Error = error::Error;
796 fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
797 let null_byte = match src.iter().position(|b| *b == 0) {
800 return Err(error::Error::BadInput {
802 msg: "The input doesn't contain a null byte",
807 let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(&src[..=null_byte]) };
808 Ok((cstr, null_byte + 1))
812 #[cfg(feature = "std")]
813 impl<'a> TryFromCtx<'a> for CString {
814 type Error = error::Error;
816 fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
817 let (raw, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(src, _ctx)?;
818 Ok((raw.to_owned(), bytes_read))
822 #[cfg(feature = "std")]
823 impl<'a> TryIntoCtx for &'a CStr {
824 type Error = error::Error;
826 fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
827 let data = self.to_bytes_with_nul();
829 if dst.len() < data.len() {
830 Err(error::Error::TooBig {
836 copy_nonoverlapping(data.as_ptr(), dst.as_mut_ptr(), data.len());
844 #[cfg(feature = "std")]
845 impl TryIntoCtx for CString {
846 type Error = error::Error;
848 fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
849 self.as_c_str().try_into_ctx(dst, ())
853 // example of marshalling to bytes, let's wait until const is an option
854 // impl FromCtx for [u8; 10] {
855 // fn from_ctx(bytes: &[u8], _ctx: Endian) -> Self {
856 // let mut dst: Self = [0; 10];
857 // assert!(bytes.len() >= dst.len());
859 // copy_nonoverlapping(bytes.as_ptr(), dst.as_mut_ptr(), dst.len());
870 #[cfg(feature = "std")]
872 let src = CString::new("Hello World").unwrap();
873 let as_bytes = src.as_bytes_with_nul();
875 let (got, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(as_bytes, ()).unwrap();
877 assert_eq!(bytes_read, as_bytes.len());
878 assert_eq!(got, src.as_c_str());
882 #[cfg(feature = "std")]
883 fn round_trip_a_c_str() {
884 let src = CString::new("Hello World").unwrap();
885 let src = src.as_c_str();
886 let as_bytes = src.to_bytes_with_nul();
888 let mut buffer = vec![0; as_bytes.len()];
889 let bytes_written = src.try_into_ctx(&mut buffer, ()).unwrap();
890 assert_eq!(bytes_written, as_bytes.len());
892 let (got, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(&buffer, ()).unwrap();
894 assert_eq!(bytes_read, as_bytes.len());
895 assert_eq!(got, src);