Backed out 5 changesets (bug 1890092, bug 1888683) for causing build bustages & crash...
[gecko.git] / third_party / rust / scroll / src / ctx.rs
blob1f982b82fa405300fa592e23b050531bddfbacb4
1 //! Generic context-aware conversion traits, for automatic _downstream_ extension of `Pread`, et. al
2 //!
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.
6 //!
7 //! ### Reading
8 //!
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.
14 //!
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]>`.
18 //!
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.
21 //!
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.
25 //!
26 //! ### Writing
27 //!
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.
33 //!
34 //! `IntoCtx` is similarly restricted as `FromCtx` is to `TryFromCtx`. And equally the types chosen
35 //! affect usable `Pwrite` implementation.
36 //!
37 //! ### Context
38 //!
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).
46 //!
47 //! # Example
48 //!
49 //! Let's expand on the [previous example](../index.html#complex-use-cases).
50 //!
51 //! ```rust
52 //! use scroll::{self, ctx, Pread, Endian};
53 //! use scroll::ctx::StrCtx;
54 //!
55 //! #[derive(Copy, Clone, PartialEq, Eq)]
56 //! enum FieldSize {
57 //!     U32,
58 //!     U64
59 //! }
60 //!
61 //! // Our custom context type. As said above it has to derive Copy.
62 //! #[derive(Copy, Clone)]
63 //! struct Context {
64 //!     fieldsize: FieldSize,
65 //!     endianess: Endian,
66 //! }
67 //!
68 //! // Our custom data type
69 //! struct Data<'b> {
70 //!   // These u64 are encoded either as 32-bit or 64-bit wide ints. Which one it is is defined in
71 //!   // the Context.
72 //!   // Also, let's imagine they have a strict relationship: A < B < C otherwise the struct is
73 //!   // invalid.
74 //!   field_a: u64,
75 //!   field_b: u64,
76 //!   field_c: u64,
77 //!
78 //!   // Both of these are marshalled with a prefixed length.
79 //!   name: &'b str,
80 //!   value: &'b [u8],
81 //! }
82 //!
83 //! #[derive(Debug)]
84 //! enum Error {
85 //!     // We'll return this custom error if the field* relationship doesn't hold
86 //!     BadFieldMatchup,
87 //!     Scroll(scroll::Error),
88 //! }
89 //!
90 //! impl<'a> ctx::TryFromCtx<'a, Context> for Data<'a> {
91 //!   type Error = Error;
92 //!
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>
98 //!   {
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;
103 //!     let field_a;
104 //!     let field_b;
105 //!     let field_c;
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;
112 //!     } else {
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)?;
116 //!     }
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);
128 //!     }
130 //!     Ok((Data { field_a, field_b, field_c, name, value }, *offset))
131 //!   }
132 //! }
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,
143 //! };
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,
156 //! };
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)
179 //!   }
180 //! }
181 //! ```
183 use core::mem::size_of;
184 use core::mem::transmute;
185 use core::ptr::copy_nonoverlapping;
186 use core::result;
187 use core::str;
189 #[cfg(feature = "std")]
190 use std::ffi::{CStr, CString};
192 use crate::endian::Endian;
193 use crate::error;
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] {
202     #[inline]
203     fn measure_with(&self, _ctx: &Ctx) -> usize {
204         self.len()
205     }
208 impl<Ctx, T: AsRef<[u8]>> MeasureWith<Ctx> for T {
209     #[inline]
210     fn measure_with(&self, _ctx: &Ctx) -> usize {
211         self.as_ref().len()
212     }
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)]
219 pub enum StrCtx {
220     Delimiter(u8),
221     DelimiterUntil(u8, usize),
222     Length(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 {
235     #[inline]
236     fn default() -> Self {
237         StrCtx::Delimiter(NULL)
238     }
241 impl StrCtx {
242     pub fn len(&self) -> usize {
243         match *self {
244             StrCtx::Delimiter(_) | StrCtx::DelimiterUntil(_, _) => 1,
245             StrCtx::Length(_) => 0,
246         }
247     }
249     pub fn is_empty(&self) -> bool {
250         if let StrCtx::Length(_) = *self {
251             true
252         } else {
253             false
254         }
255     }
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
269 /// ```rust
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)?;
279 ///          Ok((Foo(n), 2))
280 ///      }
281 /// }
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);
289 /// ```
291 /// # Advanced: Using Your Own Error in `TryFromCtx`
292 /// ```rust
293 ///  use scroll::{self, ctx, Pread};
294 ///  use std::error;
295 ///  use std::fmt::{self, Display};
296 ///  // make some kind of normal error which also can transformed from a scroll error
297 ///  #[derive(Debug)]
298 ///  pub struct ExternalError {}
300 ///  impl Display for ExternalError {
301 ///      fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
302 ///          write!(fmt, "ExternalError")
303 ///      }
304 ///  }
306 ///  impl error::Error for ExternalError {
307 ///      fn description(&self) -> &str {
308 ///          "ExternalError"
309 ///      }
310 ///      fn cause(&self) -> Option<&dyn error::Error> { None}
311 ///  }
313 ///  impl From<scroll::Error> for ExternalError {
314 ///      fn from(err: scroll::Error) -> Self {
315 ///          match err {
316 ///              _ => ExternalError{},
317 ///          }
318 ///      }
319 ///  }
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))
330 ///      }
331 ///  }
333 /// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
334 /// let foo: Result<Foo, ExternalError> = bytes.pread(0);
335 /// ```
336 pub trait TryFromCtx<'a, Ctx: Copy = (), This: ?Sized = [u8]>
337 where
338     Self: 'a + Sized,
340     type Error;
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`
351 /// # Example
352 /// ```rust
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)?;
365 ///         Ok(2)
366 ///     }
367 /// }
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();
372 /// ```
373 pub trait TryIntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
374     type Error;
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;
388 #[rustfmt::skip]
389 macro_rules! signed_to_unsigned {
390     (i8) =>  {u8 };
391     (u8) =>  {u8 };
392     (i16) => {u16};
393     (u16) => {u16};
394     (i32) => {u32};
395     (u32) => {u32};
396     (i64) => {u64};
397     (u64) => {u64};
398     (i128) => {u128};
399     (u128) => {u128};
400     (f32) => {u32};
401     (f64) => {u64};
404 macro_rules! write_into {
405     ($typ:ty, $size:expr, $n:expr, $dst:expr, $endian:expr) => {{
406         unsafe {
407             assert!($dst.len() >= $size);
408             let bytes = transmute::<$typ, [u8; $size]>(if $endian.is_little() {
409                 $n.to_le()
410             } else {
411                 $n.to_be()
412             });
413             copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size);
414         }
415     }};
418 macro_rules! into_ctx_impl {
419     ($typ:tt, $size:expr) => {
420         impl IntoCtx<Endian> for $typ {
421             #[inline]
422             fn into_ctx(self, dst: &mut [u8], le: Endian) {
423                 assert!(dst.len() >= $size);
424                 write_into!($typ, $size, self, dst, le);
425             }
426         }
427         impl<'a> IntoCtx<Endian> for &'a $typ {
428             #[inline]
429             fn into_ctx(self, dst: &mut [u8], le: Endian) {
430                 (*self).into_ctx(dst, le)
431             }
432         }
433         impl TryIntoCtx<Endian> for $typ
434         where
435             $typ: IntoCtx<Endian>,
436         {
437             type Error = error::Error;
438             #[inline]
439             fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
440                 if $size > dst.len() {
441                     Err(error::Error::TooBig {
442                         size: $size,
443                         len: dst.len(),
444                     })
445                 } else {
446                     <$typ as IntoCtx<Endian>>::into_ctx(self, dst, le);
447                     Ok($size)
448                 }
449             }
450         }
451         impl<'a> TryIntoCtx<Endian> for &'a $typ {
452             type Error = error::Error;
453             #[inline]
454             fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
455                 (*self).try_into_ctx(dst, le)
456             }
457         }
458     };
461 macro_rules! from_ctx_impl {
462     ($typ:tt, $size:expr) => {
463         impl<'a> FromCtx<Endian> for $typ {
464             #[inline]
465             fn from_ctx(src: &[u8], le: Endian) -> Self {
466                 assert!(src.len() >= $size);
467                 let mut data: signed_to_unsigned!($typ) = 0;
468                 unsafe {
469                     copy_nonoverlapping(
470                         src.as_ptr(),
471                         &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
472                         $size,
473                     );
474                 }
475                 (if le.is_little() {
476                     data.to_le()
477                 } else {
478                     data.to_be()
479                 }) as $typ
480             }
481         }
483         impl<'a> TryFromCtx<'a, Endian> for $typ
484         where
485             $typ: FromCtx<Endian>,
486         {
487             type Error = error::Error;
488             #[inline]
489             fn try_from_ctx(
490                 src: &'a [u8],
491                 le: Endian,
492             ) -> result::Result<(Self, usize), Self::Error> {
493                 if $size > src.len() {
494                     Err(error::Error::TooBig {
495                         size: $size,
496                         len: src.len(),
497                     })
498                 } else {
499                     Ok((FromCtx::from_ctx(&src, le), $size))
500                 }
501             }
502         }
503         // as ref
504         impl<'a, T> FromCtx<Endian, T> for $typ
505         where
506             T: AsRef<[u8]>,
507         {
508             #[inline]
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;
513                 unsafe {
514                     copy_nonoverlapping(
515                         src.as_ptr(),
516                         &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
517                         $size,
518                     );
519                 }
520                 (if le.is_little() {
521                     data.to_le()
522                 } else {
523                     data.to_be()
524                 }) as $typ
525             }
526         }
528         impl<'a, T> TryFromCtx<'a, Endian, T> for $typ
529         where
530             $typ: FromCtx<Endian, T>,
531             T: AsRef<[u8]>,
532         {
533             type Error = error::Error;
534             #[inline]
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)
538             }
539         }
540     };
543 macro_rules! ctx_impl {
544     ($typ:tt, $size:expr) => {
545         from_ctx_impl!($typ, $size);
546     };
549 ctx_impl!(u8, 1);
550 ctx_impl!(i8, 1);
551 ctx_impl!(u16, 2);
552 ctx_impl!(i16, 2);
553 ctx_impl!(u32, 4);
554 ctx_impl!(i32, 4);
555 ctx_impl!(u64, 8);
556 ctx_impl!(i64, 8);
557 ctx_impl!(u128, 16);
558 ctx_impl!(i128, 16);
560 macro_rules! from_ctx_float_impl {
561     ($typ:tt, $size:expr) => {
562         impl<'a> FromCtx<Endian> for $typ {
563             #[inline]
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;
567                 unsafe {
568                     copy_nonoverlapping(
569                         src.as_ptr(),
570                         &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
571                         $size,
572                     );
573                     transmute(if le.is_little() {
574                         data.to_le()
575                     } else {
576                         data.to_be()
577                     })
578                 }
579             }
580         }
581         impl<'a> TryFromCtx<'a, Endian> for $typ
582         where
583             $typ: FromCtx<Endian>,
584         {
585             type Error = error::Error;
586             #[inline]
587             fn try_from_ctx(
588                 src: &'a [u8],
589                 le: Endian,
590             ) -> result::Result<(Self, usize), Self::Error> {
591                 if $size > src.len() {
592                     Err(error::Error::TooBig {
593                         size: $size,
594                         len: src.len(),
595                     })
596                 } else {
597                     Ok((FromCtx::from_ctx(src, le), $size))
598                 }
599             }
600         }
601     };
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 {
621             #[inline]
622             fn into_ctx(self, dst: &mut [u8], le: Endian) {
623                 assert!(dst.len() >= $size);
624                 write_into!(
625                     signed_to_unsigned!($typ),
626                     $size,
627                     transmute::<$typ, signed_to_unsigned!($typ)>(self),
628                     dst,
629                     le
630                 );
631             }
632         }
633         impl<'a> IntoCtx<Endian> for &'a $typ {
634             #[inline]
635             fn into_ctx(self, dst: &mut [u8], le: Endian) {
636                 (*self).into_ctx(dst, le)
637             }
638         }
639         impl TryIntoCtx<Endian> for $typ
640         where
641             $typ: IntoCtx<Endian>,
642         {
643             type Error = error::Error;
644             #[inline]
645             fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
646                 if $size > dst.len() {
647                     Err(error::Error::TooBig {
648                         size: $size,
649                         len: dst.len(),
650                     })
651                 } else {
652                     <$typ as IntoCtx<Endian>>::into_ctx(self, dst, le);
653                     Ok($size)
654                 }
655             }
656         }
657         impl<'a> TryIntoCtx<Endian> for &'a $typ {
658             type Error = error::Error;
659             #[inline]
660             fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
661                 (*self).try_into_ctx(dst, le)
662             }
663         }
664     };
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;
672     #[inline]
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) => {
679                 if len > src.len() {
680                     return Err(error::Error::TooBig {
681                         size: len,
682                         len: src.len(),
683                     });
684                 };
685                 src.iter()
686                     .take_while(|c| **c != delimiter)
687                     .take(len)
688                     .count()
689             }
690         };
692         if len > src.len() {
693             return Err(error::Error::TooBig {
694                 size: len,
695                 len: src.len(),
696             });
697         };
699         match str::from_utf8(&src[..len]) {
700             Ok(res) => Ok((res, len + ctx.len())),
701             Err(_) => Err(error::Error::BadInput {
702                 size: src.len(),
703                 msg: "invalid utf8",
704             }),
705         }
706     }
709 impl<'a, T> TryFromCtx<'a, StrCtx, T> for &'a str
710 where
711     T: AsRef<[u8]>,
713     type Error = error::Error;
714     #[inline]
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)
718     }
721 impl<'a> TryIntoCtx for &'a [u8] {
722     type Error = error::Error;
723     #[inline]
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())
729         // }
730         if src_len > dst_len {
731             Err(error::Error::TooBig {
732                 size: self.len(),
733                 len: dst.len(),
734             })
735         } else {
736             unsafe { copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), src_len as usize) };
737             Ok(self.len())
738         }
739     }
742 // TODO: make TryIntoCtx use StrCtx for awesomeness
743 impl<'a> TryIntoCtx for &'a str {
744     type Error = error::Error;
745     #[inline]
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, ())
749     }
752 // TODO: we can make this compile time without size_of call, but compiler probably does that anyway
753 macro_rules! sizeof_impl {
754     ($ty:ty) => {
755         impl SizeWith<Endian> for $ty {
756             #[inline]
757             fn size_with(_ctx: &Endian) -> usize {
758                 size_of::<$ty>()
759             }
760         }
761     };
764 sizeof_impl!(u8);
765 sizeof_impl!(i8);
766 sizeof_impl!(u16);
767 sizeof_impl!(i16);
768 sizeof_impl!(u32);
769 sizeof_impl!(i32);
770 sizeof_impl!(u64);
771 sizeof_impl!(i64);
772 sizeof_impl!(u128);
773 sizeof_impl!(i128);
774 sizeof_impl!(f32);
775 sizeof_impl!(f64);
777 impl<'a> TryFromCtx<'a, usize> for &'a [u8] {
778     type Error = error::Error;
779     #[inline]
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 {
783                 size,
784                 len: src.len(),
785             })
786         } else {
787             Ok((&src[..size], size))
788         }
789     }
792 #[cfg(feature = "std")]
793 impl<'a> TryFromCtx<'a> for &'a CStr {
794     type Error = error::Error;
795     #[inline]
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) {
798             Some(ix) => ix,
799             None => {
800                 return Err(error::Error::BadInput {
801                     size: 0,
802                     msg: "The input doesn't contain a null byte",
803                 })
804             }
805         };
807         let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(&src[..=null_byte]) };
808         Ok((cstr, null_byte + 1))
809     }
812 #[cfg(feature = "std")]
813 impl<'a> TryFromCtx<'a> for CString {
814     type Error = error::Error;
815     #[inline]
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))
819     }
822 #[cfg(feature = "std")]
823 impl<'a> TryIntoCtx for &'a CStr {
824     type Error = error::Error;
825     #[inline]
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 {
831                 size: dst.len(),
832                 len: data.len(),
833             })
834         } else {
835             unsafe {
836                 copy_nonoverlapping(data.as_ptr(), dst.as_mut_ptr(), data.len());
837             }
839             Ok(data.len())
840         }
841     }
844 #[cfg(feature = "std")]
845 impl TryIntoCtx for CString {
846     type Error = error::Error;
847     #[inline]
848     fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
849         self.as_c_str().try_into_ctx(dst, ())
850     }
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());
858 //         unsafe {
859 //             copy_nonoverlapping(bytes.as_ptr(), dst.as_mut_ptr(), dst.len());
860 //         }
861 //         dst
862 //     }
863 // }
865 #[cfg(test)]
866 mod tests {
867     use super::*;
869     #[test]
870     #[cfg(feature = "std")]
871     fn parse_a_cstr() {
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());
879     }
881     #[test]
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);
896     }