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;
102 //!
103 //!     let field_a;
104 //!     let field_b;
105 //!     let field_c;
106 //!
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 //!     }
117 //!
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))?;
121 //!
122 //!     let vallen = src.gread_with::<u16>(offset, ctx.endianess)? as usize;
123 //!     let value = &src[*offset..(*offset+vallen)];
124 //!
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 //!     }
129 //!
130 //!     Ok((Data { field_a, field_b, field_c, name, value }, *offset))
131 //!   }
132 //! }
133 //!
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";
138 //!
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();
145 //!
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]);
151 //!
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 //! };
157 //!
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());
161 //!
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];
165 //!
166 //! let data: Data = bytes_long.pread_with(0, contextB).unwrap();
167 //!
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]);
173 //!
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 //! ```
182 
183 use core::ptr::copy_nonoverlapping;
184 use core::mem::transmute;
185 use core::mem::size_of;
186 use core::str;
187 use core::result;
188 
189 #[cfg(feature = "std")]
190 use std::ffi::{CStr, CString};
191 
192 use crate::error;
193 use crate::endian::Endian;
194 
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`?
measure_with(&self, ctx: &Ctx) -> usize198     fn measure_with(&self, ctx: &Ctx) -> usize;
199 }
200 
201 impl<Ctx> MeasureWith<Ctx> for [u8] {
202     #[inline]
measure_with(&self, _ctx: &Ctx) -> usize203     fn measure_with(&self, _ctx: &Ctx) -> usize {
204         self.len()
205     }
206 }
207 
208 impl<Ctx, T: AsRef<[u8]>> MeasureWith<Ctx> for T {
209     #[inline]
measure_with(&self, _ctx: &Ctx) -> usize210     fn measure_with(&self, _ctx: &Ctx) -> usize {
211         self.as_ref().len()
212     }
213 }
214 
215 /// The parsing context for converting a byte sequence to a `&str`
216 ///
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),
223 }
224 
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;
233 
234 impl Default for StrCtx {
235     #[inline]
default() -> Self236     fn default() -> Self {
237         StrCtx::Delimiter(NULL)
238     }
239 }
240 
241 impl StrCtx {
len(&self) -> usize242     pub fn len(&self) -> usize {
243         match *self {
244             StrCtx::Delimiter(_) |
245             StrCtx::DelimiterUntil(_, _) => 1,
246             StrCtx::Length(_) => 0,
247         }
248     }
249 
is_empty(&self) -> bool250     pub fn is_empty(&self) -> bool {
251         if let StrCtx::Length(_) = *self { true } else { false }
252     }
253 }
254 
255 /// Reads `Self` from `This` using the context `Ctx`; must _not_ fail
256 pub trait FromCtx<Ctx: Copy = (), This: ?Sized = [u8]> {
from_ctx(this: &This, ctx: Ctx) -> Self257     fn from_ctx(this: &This, ctx: Ctx) -> Self;
258 }
259 
260 /// Tries to read `Self` from `This` using the context `Ctx`
261 ///
262 /// # Implementing Your Own Reader
263 /// If you want to implement your own reader for a type `Foo` from some kind of buffer (say
264 /// `[u8]`), then you need to implement this trait
265 ///
266 /// ```rust
267 /// use scroll::{self, ctx, Pread};
268 /// #[derive(Debug, PartialEq, Eq)]
269 /// pub struct Foo(u16);
270 ///
271 /// impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Foo {
272 ///      type Error = scroll::Error;
273 ///      fn try_from_ctx(this: &'a [u8], le: scroll::Endian) -> Result<(Self, usize), Self::Error> {
274 ///          if this.len() < 2 { return Err((scroll::Error::Custom("whatever".to_string())).into()) }
275 ///          let n = this.pread_with(0, le)?;
276 ///          Ok((Foo(n), 2))
277 ///      }
278 /// }
279 ///
280 /// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
281 /// let foo = bytes.pread_with::<Foo>(0, scroll::LE).unwrap();
282 /// assert_eq!(Foo(0xadde), foo);
283 ///
284 /// let foo2 = bytes.pread_with::<Foo>(0, scroll::BE).unwrap();
285 /// assert_eq!(Foo(0xdeadu16), foo2);
286 /// ```
287 ///
288 /// # Advanced: Using Your Own Error in `TryFromCtx`
289 /// ```rust
290 ///  use scroll::{self, ctx, Pread};
291 ///  use std::error;
292 ///  use std::fmt::{self, Display};
293 ///  // make some kind of normal error which also can transformed from a scroll error
294 ///  #[derive(Debug)]
295 ///  pub struct ExternalError {}
296 ///
297 ///  impl Display for ExternalError {
298 ///      fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
299 ///          write!(fmt, "ExternalError")
300 ///      }
301 ///  }
302 ///
303 ///  impl error::Error for ExternalError {
304 ///      fn description(&self) -> &str {
305 ///          "ExternalError"
306 ///      }
307 ///      fn cause(&self) -> Option<&error::Error> { None}
308 ///  }
309 ///
310 ///  impl From<scroll::Error> for ExternalError {
311 ///      fn from(err: scroll::Error) -> Self {
312 ///          match err {
313 ///              _ => ExternalError{},
314 ///          }
315 ///      }
316 ///  }
317 ///  #[derive(Debug, PartialEq, Eq)]
318 ///  pub struct Foo(u16);
319 ///
320 ///  impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Foo {
321 ///      type Error = ExternalError;
322 ///      fn try_from_ctx(this: &'a [u8], le: scroll::Endian) -> Result<(Self, usize), Self::Error> {
323 ///          if this.len() <= 2 { return Err((ExternalError {}).into()) }
324 ///          let offset = &mut 0;
325 ///          let n = this.gread_with(offset, le)?;
326 ///          Ok((Foo(n), *offset))
327 ///      }
328 ///  }
329 ///
330 /// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
331 /// let foo: Result<Foo, ExternalError> = bytes.pread(0);
332 /// ```
333 pub trait TryFromCtx<'a, Ctx: Copy = (), This: ?Sized = [u8]> where Self: 'a + Sized {
334     type Error;
try_from_ctx(from: &'a This, ctx: Ctx) -> Result<(Self, usize), Self::Error>335     fn try_from_ctx(from: &'a This, ctx: Ctx) -> Result<(Self, usize), Self::Error>;
336 }
337 
338 /// Writes `Self` into `This` using the context `Ctx`
339 pub trait IntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
into_ctx(self, _: &mut This, ctx: Ctx)340     fn into_ctx(self, _: &mut This, ctx: Ctx);
341 }
342 
343 /// Tries to write `Self` into `This` using the context `Ctx`
344 /// To implement writing into an arbitrary byte buffer, implement `TryIntoCtx`
345 /// # Example
346 /// ```rust
347 /// use scroll::{self, ctx, LE, Endian, Pwrite};
348 /// #[derive(Debug, PartialEq, Eq)]
349 /// pub struct Foo(u16);
350 ///
351 /// // this will use the default `DefaultCtx = scroll::Endian`
352 /// impl ctx::TryIntoCtx<Endian> for Foo {
353 ///     // you can use your own error here too, but you will then need to specify it in fn generic parameters
354 ///     type Error = scroll::Error;
355 ///     // you can write using your own context type, see `leb128.rs`
356 ///     fn try_into_ctx(self, this: &mut [u8], le: Endian) -> Result<usize, Self::Error> {
357 ///         if this.len() < 2 { return Err((scroll::Error::Custom("whatever".to_string())).into()) }
358 ///         this.pwrite_with(self.0, 0, le)?;
359 ///         Ok(2)
360 ///     }
361 /// }
362 /// // now we can write a `Foo` into some buffer (in this case, a byte buffer, because that's what we implemented it for above)
363 ///
364 /// let mut bytes: [u8; 4] = [0, 0, 0, 0];
365 /// bytes.pwrite_with(Foo(0x7f), 1, LE).unwrap();
366 /// ```
367 pub trait TryIntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
368     type Error;
try_into_ctx(self, _: &mut This, ctx: Ctx) -> Result<usize, Self::Error>369     fn try_into_ctx(self, _: &mut This, ctx: Ctx) -> Result<usize, Self::Error>;
370 }
371 
372 /// Gets the size of `Self` with a `Ctx`, and in `Self::Units`. Implementors can then call `Gread` related functions
373 ///
374 /// The rationale behind this trait is to:
375 ///
376 /// 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.
377 /// 2. Allow a context based size, which is useful for 32/64 bit variants for various containers, etc.
378 pub trait SizeWith<Ctx = ()> {
size_with(ctx: &Ctx) -> usize379     fn size_with(ctx: &Ctx) -> usize;
380 }
381 
382 macro_rules! signed_to_unsigned {
383     (i8) =>  {u8 };
384     (u8) =>  {u8 };
385     (i16) => {u16};
386     (u16) => {u16};
387     (i32) => {u32};
388     (u32) => {u32};
389     (i64) => {u64};
390     (u64) => {u64};
391     (i128) => {u128};
392     (u128) => {u128};
393     (f32) => {u32};
394     (f64) => {u64};
395 }
396 
397 macro_rules! write_into {
398     ($typ:ty, $size:expr, $n:expr, $dst:expr, $endian:expr) => ({
399         unsafe {
400             assert!($dst.len() >= $size);
401             let bytes = transmute::<$typ, [u8; $size]>(if $endian.is_little() { $n.to_le() } else { $n.to_be() });
402             copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size);
403         }
404     });
405 }
406 
407 macro_rules! into_ctx_impl {
408     ($typ:tt, $size:expr) => {
409         impl IntoCtx<Endian> for $typ {
410             #[inline]
411             fn into_ctx(self, dst: &mut [u8], le: Endian) {
412                 assert!(dst.len() >= $size);
413                 write_into!($typ, $size, self, dst, le);
414             }
415         }
416         impl<'a> IntoCtx<Endian> for &'a $typ {
417             #[inline]
418             fn into_ctx(self, dst: &mut [u8], le: Endian) {
419                 (*self).into_ctx(dst, le)
420             }
421         }
422         impl TryIntoCtx<Endian> for $typ where $typ: IntoCtx<Endian> {
423             type Error = error::Error;
424             #[inline]
425             fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
426                 if $size > dst.len () {
427                     Err(error::Error::TooBig{size: $size, len: dst.len()})
428                 } else {
429                     <$typ as IntoCtx<Endian>>::into_ctx(self, dst, le);
430                     Ok($size)
431                 }
432             }
433         }
434         impl<'a> TryIntoCtx<Endian> for &'a $typ {
435             type Error = error::Error;
436             #[inline]
437             fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
438                 (*self).try_into_ctx(dst, le)
439             }
440         }
441     }
442 }
443 
444 macro_rules! from_ctx_impl {
445     ($typ:tt, $size:expr) => {
446         impl<'a> FromCtx<Endian> for $typ {
447             #[inline]
448             fn from_ctx(src: &[u8], le: Endian) -> Self {
449                 assert!(src.len() >= $size);
450                 let mut data: signed_to_unsigned!($typ) = 0;
451                 unsafe {
452                     copy_nonoverlapping(
453                         src.as_ptr(),
454                         &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
455                         $size);
456                 }
457                 (if le.is_little() { data.to_le() } else { data.to_be() }) as $typ
458             }
459         }
460 
461         impl<'a> TryFromCtx<'a, Endian> for $typ where $typ: FromCtx<Endian> {
462             type Error = error::Error;
463             #[inline]
464             fn try_from_ctx(src: &'a [u8], le: Endian) -> result::Result<(Self, usize), Self::Error> {
465                 if $size > src.len () {
466                     Err(error::Error::TooBig{size: $size, len: src.len()})
467                 } else {
468                     Ok((FromCtx::from_ctx(&src, le), $size))
469                 }
470             }
471         }
472         // as ref
473         impl<'a, T> FromCtx<Endian, T> for $typ where T: AsRef<[u8]> {
474             #[inline]
475             fn from_ctx(src: &T, le: Endian) -> Self {
476                 let src = src.as_ref();
477                 assert!(src.len() >= $size);
478                 let mut data: signed_to_unsigned!($typ) = 0;
479                 unsafe {
480                     copy_nonoverlapping(
481                         src.as_ptr(),
482                         &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
483                         $size);
484                 }
485                 (if le.is_little() { data.to_le() } else { data.to_be() }) as $typ
486             }
487         }
488 
489         impl<'a, T> TryFromCtx<'a, Endian, T> for $typ where $typ: FromCtx<Endian, T>, T: AsRef<[u8]> {
490             type Error = error::Error;
491             #[inline]
492             fn try_from_ctx(src: &'a T, le: Endian) -> result::Result<(Self, usize), Self::Error> {
493                 let src = src.as_ref();
494                 Self::try_from_ctx(src, le)
495             }
496         }
497     };
498 }
499 
500 macro_rules! ctx_impl {
501     ($typ:tt, $size:expr) => {
502         from_ctx_impl!($typ, $size);
503      };
504 }
505 
506 ctx_impl!(u8,  1);
507 ctx_impl!(i8,  1);
508 ctx_impl!(u16, 2);
509 ctx_impl!(i16, 2);
510 ctx_impl!(u32, 4);
511 ctx_impl!(i32, 4);
512 ctx_impl!(u64, 8);
513 ctx_impl!(i64, 8);
514 ctx_impl!(u128, 16);
515 ctx_impl!(i128, 16);
516 
517 macro_rules! from_ctx_float_impl {
518     ($typ:tt, $size:expr) => {
519         impl<'a> FromCtx<Endian> for $typ {
520             #[inline]
521             fn from_ctx(src: &[u8], le: Endian) -> Self {
522                 assert!(src.len() >= ::core::mem::size_of::<Self>());
523                 let mut data: signed_to_unsigned!($typ) = 0;
524                 unsafe {
525                     copy_nonoverlapping(
526                         src.as_ptr(),
527                         &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
528                         $size);
529                     transmute(if le.is_little() { data.to_le() } else { data.to_be() })
530                 }
531             }
532         }
533         impl<'a> TryFromCtx<'a, Endian> for $typ where $typ: FromCtx<Endian> {
534             type Error = error::Error;
535             #[inline]
536             fn try_from_ctx(src: &'a [u8], le: Endian) -> result::Result<(Self, usize), Self::Error> {
537                 if $size > src.len () {
538                     Err(error::Error::TooBig{size: $size, len: src.len()})
539                 } else {
540                     Ok((FromCtx::from_ctx(src, le), $size))
541                 }
542             }
543         }
544     }
545 }
546 
547 from_ctx_float_impl!(f32, 4);
548 from_ctx_float_impl!(f64, 8);
549 
550 into_ctx_impl!(u8,  1);
551 into_ctx_impl!(i8,  1);
552 into_ctx_impl!(u16, 2);
553 into_ctx_impl!(i16, 2);
554 into_ctx_impl!(u32, 4);
555 into_ctx_impl!(i32, 4);
556 into_ctx_impl!(u64, 8);
557 into_ctx_impl!(i64, 8);
558 into_ctx_impl!(u128, 16);
559 into_ctx_impl!(i128, 16);
560 
561 macro_rules! into_ctx_float_impl {
562     ($typ:tt, $size:expr) => {
563         impl IntoCtx<Endian> for $typ {
564             #[inline]
565             fn into_ctx(self, dst: &mut [u8], le: Endian) {
566                 assert!(dst.len() >= $size);
567                 write_into!(signed_to_unsigned!($typ), $size, transmute::<$typ, signed_to_unsigned!($typ)>(self), dst, le);
568             }
569         }
570         impl<'a> IntoCtx<Endian> for &'a $typ {
571             #[inline]
572             fn into_ctx(self, dst: &mut [u8], le: Endian) {
573                 (*self).into_ctx(dst, le)
574             }
575         }
576         impl TryIntoCtx<Endian> for $typ where $typ: IntoCtx<Endian> {
577             type Error = error::Error;
578             #[inline]
579             fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
580                 if $size > dst.len () {
581                     Err(error::Error::TooBig{size: $size, len: dst.len()})
582                 } else {
583                     <$typ as IntoCtx<Endian>>::into_ctx(self, dst, le);
584                     Ok($size)
585                 }
586             }
587         }
588         impl<'a> TryIntoCtx<Endian> for &'a $typ {
589             type Error = error::Error;
590             #[inline]
591             fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
592                 (*self).try_into_ctx(dst, le)
593             }
594         }
595     }
596 }
597 
598 into_ctx_float_impl!(f32, 4);
599 into_ctx_float_impl!(f64, 8);
600 
601 impl<'a> TryFromCtx<'a, StrCtx> for &'a str {
602     type Error = error::Error;
603     #[inline]
604     /// Read a `&str` from `src` using `delimiter`
try_from_ctx(src: &'a [u8], ctx: StrCtx) -> Result<(Self, usize), Self::Error>605     fn try_from_ctx(src: &'a [u8], ctx: StrCtx) -> Result<(Self, usize), Self::Error> {
606         let len = match ctx {
607             StrCtx::Length(len) => len,
608             StrCtx::Delimiter(delimiter) => src.iter().take_while(|c| **c != delimiter).count(),
609             StrCtx::DelimiterUntil(delimiter, len) => {
610                 if len > src.len() {
611                     return Err(error::Error::TooBig{size: len, len: src.len()});
612                 };
613                 src
614                     .iter()
615                     .take_while(|c| **c != delimiter)
616                     .take(len)
617                     .count()
618             }
619         };
620 
621         if len > src.len() {
622             return Err(error::Error::TooBig{size: len, len: src.len()});
623         };
624 
625         match str::from_utf8(&src[..len]) {
626             Ok(res) => Ok((res, len + ctx.len())),
627             Err(_) => Err(error::Error::BadInput{size: src.len(), msg: "invalid utf8"})
628         }
629     }
630 }
631 
632 impl<'a, T> TryFromCtx<'a, StrCtx, T> for &'a str where T: AsRef<[u8]> {
633     type Error = error::Error;
634     #[inline]
try_from_ctx(src: &'a T, ctx: StrCtx) -> result::Result<(Self, usize), Self::Error>635     fn try_from_ctx(src: &'a T, ctx: StrCtx) -> result::Result<(Self, usize), Self::Error> {
636         let src = src.as_ref();
637         TryFromCtx::try_from_ctx(src, ctx)
638     }
639 }
640 
641 impl<'a> TryIntoCtx for &'a [u8] {
642     type Error = error::Error;
643     #[inline]
try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize>644     fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
645         let src_len = self.len() as isize;
646         let dst_len = dst.len() as isize;
647         // if src_len < 0 || dst_len < 0 || offset < 0 {
648         //     return Err(error::Error::BadOffset(format!("requested operation has negative casts: src len: {} dst len: {} offset: {}", src_len, dst_len, offset)).into())
649         // }
650         if src_len > dst_len {
651             Err(error::Error::TooBig{ size: self.len(), len: dst.len()})
652         } else {
653             unsafe { copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), src_len as usize) };
654             Ok(self.len())
655         }
656     }
657 }
658 
659 // TODO: make TryIntoCtx use StrCtx for awesomeness
660 impl<'a> TryIntoCtx for &'a str {
661     type Error = error::Error;
662     #[inline]
try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize>663     fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
664         let bytes = self.as_bytes();
665         TryIntoCtx::try_into_ctx(bytes, dst, ())
666     }
667 }
668 
669 // TODO: we can make this compile time without size_of call, but compiler probably does that anyway
670 macro_rules! sizeof_impl {
671     ($ty:ty) => {
672         impl SizeWith<Endian> for $ty {
673             #[inline]
674             fn size_with(_ctx: &Endian) -> usize {
675                 size_of::<$ty>()
676             }
677         }
678     }
679 }
680 
681 sizeof_impl!(u8);
682 sizeof_impl!(i8);
683 sizeof_impl!(u16);
684 sizeof_impl!(i16);
685 sizeof_impl!(u32);
686 sizeof_impl!(i32);
687 sizeof_impl!(u64);
688 sizeof_impl!(i64);
689 sizeof_impl!(u128);
690 sizeof_impl!(i128);
691 sizeof_impl!(f32);
692 sizeof_impl!(f64);
693 sizeof_impl!(usize);
694 sizeof_impl!(isize);
695 
696 impl FromCtx<Endian> for usize {
697     #[inline]
from_ctx(src: &[u8], le: Endian) -> Self698     fn from_ctx(src: &[u8], le: Endian) -> Self {
699         let size = ::core::mem::size_of::<Self>();
700         assert!(src.len() >= size);
701         let mut data: usize = 0;
702         unsafe {
703             copy_nonoverlapping(
704                 src.as_ptr(),
705                 &mut data as *mut usize as *mut u8,
706                 size);
707             if le.is_little() { data.to_le() } else { data.to_be() }
708         }
709     }
710 }
711 
712 impl<'a> TryFromCtx<'a, Endian> for usize where usize: FromCtx<Endian> {
713     type Error = error::Error;
714     #[inline]
try_from_ctx(src: &'a [u8], le: Endian) -> result::Result<(Self, usize), Self::Error>715     fn try_from_ctx(src: &'a [u8], le: Endian) -> result::Result<(Self, usize), Self::Error> {
716         let size = ::core::mem::size_of::<usize>();
717         if size > src.len () {
718             Err(error::Error::TooBig{size, len: src.len()})
719         } else {
720             Ok((FromCtx::from_ctx(src, le), size))
721         }
722     }
723 }
724 
725 impl<'a> TryFromCtx<'a, usize> for &'a[u8] {
726     type Error = error::Error;
727     #[inline]
try_from_ctx(src: &'a [u8], size: usize) -> result::Result<(Self, usize), Self::Error>728     fn try_from_ctx(src: &'a [u8], size: usize) -> result::Result<(Self, usize), Self::Error> {
729         if size > src.len () {
730             Err(error::Error::TooBig{size, len: src.len()})
731         } else {
732             Ok((&src[..size], size))
733         }
734     }
735 }
736 
737 impl IntoCtx<Endian> for usize {
738     #[inline]
into_ctx(self, dst: &mut [u8], le: Endian)739     fn into_ctx(self, dst: &mut [u8], le: Endian) {
740         let size = ::core::mem::size_of::<Self>();
741         assert!(dst.len() >= size);
742         let mut data = if le.is_little() { self.to_le() } else { self.to_be() };
743         let data = &mut data as *mut usize as *mut u8;
744         unsafe {
745             copy_nonoverlapping(data, dst.as_mut_ptr(), size);
746         }
747     }
748 }
749 
750 impl TryIntoCtx<Endian> for usize where usize: IntoCtx<Endian> {
751     type Error = error::Error;
752     #[inline]
try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize>753     fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
754         let size = ::core::mem::size_of::<usize>();
755         if size > dst.len() {
756             Err(error::Error::TooBig{size, len: dst.len()})
757         } else {
758             <usize as IntoCtx<Endian>>::into_ctx(self, dst, le);
759             Ok(size)
760         }
761     }
762 }
763 
764 #[cfg(feature = "std")]
765 impl<'a> TryFromCtx<'a> for &'a CStr {
766     type Error = error::Error;
767     #[inline]
try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error>768     fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
769         let null_byte = match src.iter().position(|b| *b == 0) {
770             Some(ix) => ix,
771             None => return Err(error::Error::BadInput {
772                 size: 0,
773                 msg: "The input doesn't contain a null byte",
774             })
775         };
776 
777         let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(&src[..=null_byte]) };
778         Ok((cstr, null_byte+1))
779     }
780 }
781 
782 #[cfg(feature = "std")]
783 impl<'a> TryFromCtx<'a> for CString {
784     type Error = error::Error;
785     #[inline]
try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error>786     fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
787         let (raw, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(src, _ctx)?;
788         Ok((raw.to_owned(), bytes_read))
789     }
790 }
791 
792 #[cfg(feature = "std")]
793 impl<'a> TryIntoCtx for &'a CStr {
794     type Error = error::Error;
795     #[inline]
try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize>796     fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
797         let data = self.to_bytes_with_nul();
798 
799         if dst.len() < data.len() {
800             Err(error::Error::TooBig {
801                 size: dst.len(),
802                 len: data.len(),
803             })
804         } else {
805             unsafe {
806                 copy_nonoverlapping(data.as_ptr(), dst.as_mut_ptr(), data.len());
807             }
808 
809             Ok(data.len())
810         }
811     }
812 }
813 
814 #[cfg(feature = "std")]
815 impl TryIntoCtx for CString {
816     type Error = error::Error;
817     #[inline]
try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize>818     fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
819         self.as_c_str().try_into_ctx(dst, ())
820     }
821 }
822 
823 
824 // example of marshalling to bytes, let's wait until const is an option
825 // impl FromCtx for [u8; 10] {
826 //     fn from_ctx(bytes: &[u8], _ctx: Endian) -> Self {
827 //         let mut dst: Self = [0; 10];
828 //         assert!(bytes.len() >= dst.len());
829 //         unsafe {
830 //             copy_nonoverlapping(bytes.as_ptr(), dst.as_mut_ptr(), dst.len());
831 //         }
832 //         dst
833 //     }
834 // }
835 
836 #[cfg(test)]
837 mod tests {
838     use super::*;
839 
840     #[test]
841     #[cfg(feature = "std")]
parse_a_cstr()842     fn parse_a_cstr() {
843         let src = CString::new("Hello World").unwrap();
844         let as_bytes = src.as_bytes_with_nul();
845 
846         let (got, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(as_bytes, ()).unwrap();
847 
848         assert_eq!(bytes_read, as_bytes.len());
849         assert_eq!(got, src.as_c_str());
850     }
851 
852     #[test]
853     #[cfg(feature = "std")]
round_trip_a_c_str()854     fn round_trip_a_c_str() {
855         let src = CString::new("Hello World").unwrap();
856         let src = src.as_c_str();
857         let as_bytes = src.to_bytes_with_nul();
858 
859         let mut buffer = vec![0; as_bytes.len()];
860         let bytes_written = src.try_into_ctx(&mut buffer, ()).unwrap();
861         assert_eq!(bytes_written, as_bytes.len());
862 
863         let (got, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(&buffer, ()).unwrap();
864 
865         assert_eq!(bytes_read, as_bytes.len());
866         assert_eq!(got, src);
867     }
868 }
869 
870 
871