summaryrefslogtreecommitdiffstats
path: root/third_party/rust/scroll/src/lesser.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/scroll/src/lesser.rs178
1 files changed, 178 insertions, 0 deletions
diff --git a/third_party/rust/scroll/src/lesser.rs b/third_party/rust/scroll/src/lesser.rs
new file mode 100644
index 0000000000..46ef4c5b11
--- /dev/null
+++ b/third_party/rust/scroll/src/lesser.rs
@@ -0,0 +1,178 @@
+use crate::ctx::{FromCtx, IntoCtx, SizeWith};
+use std::io::{Read, Result, Write};
+
+/// An extension trait to `std::io::Read` streams; mainly targeted at reading primitive types with
+/// a known size.
+///
+/// Requires types to implement [`FromCtx`](ctx/trait.FromCtx.html) and [`SizeWith`](ctx/trait.SizeWith.html).
+///
+/// **NB** You should probably add `repr(C)` and be very careful how you implement
+/// [`SizeWith`](ctx/trait.SizeWith.html), otherwise you will get IO errors failing to fill entire
+/// buffer (the size you specified in `SizeWith`), or out of bound errors (depending on your impl)
+/// in `from_ctx`.
+///
+/// Warning: Currently ioread/write uses a small 256-byte buffer and can not read/write larger types
+///
+/// # Example
+/// ```rust
+/// use std::io::Cursor;
+/// use scroll::{self, ctx, LE, Pread, IOread};
+///
+/// #[repr(packed)]
+/// struct Foo {
+/// foo: i64,
+/// bar: u32,
+/// }
+///
+/// impl ctx::FromCtx<scroll::Endian> for Foo {
+/// fn from_ctx(bytes: &[u8], ctx: scroll::Endian) -> Self {
+/// Foo { foo: bytes.pread_with::<i64>(0, ctx).unwrap(), bar: bytes.pread_with::<u32>(8, ctx).unwrap() }
+/// }
+/// }
+///
+/// impl ctx::SizeWith<scroll::Endian> for Foo {
+/// // our parsing context doesn't influence our size
+/// fn size_with(_: &scroll::Endian) -> usize {
+/// ::std::mem::size_of::<Foo>()
+/// }
+/// }
+///
+/// let bytes_ = [0x0b,0x0b,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
+/// let mut bytes = Cursor::new(bytes_);
+/// let foo = bytes.ioread_with::<i64>(LE).unwrap();
+/// let bar = bytes.ioread_with::<u32>(LE).unwrap();
+/// assert_eq!(foo, 0xb0b);
+/// assert_eq!(bar, 0xbeef);
+/// let error = bytes.ioread_with::<f64>(LE);
+/// assert!(error.is_err());
+/// let mut bytes = Cursor::new(bytes_);
+/// let foo_ = bytes.ioread_with::<Foo>(LE).unwrap();
+/// // Remember that you need to copy out fields from packed structs
+/// // with a `{}` block instead of borrowing them directly
+/// // ref: https://github.com/rust-lang/rust/issues/46043
+/// assert_eq!({foo_.foo}, foo);
+/// assert_eq!({foo_.bar}, bar);
+/// ```
+///
+pub trait IOread<Ctx: Copy>: Read {
+ /// Reads the type `N` from `Self`, with a default parsing context.
+ /// For the primitive numeric types, this will be at the host machine's endianness.
+ ///
+ /// # Example
+ /// ```rust
+ /// use scroll::IOread;
+ /// use std::io::Cursor;
+ /// let bytes = [0xef, 0xbe];
+ /// let mut bytes = Cursor::new(&bytes[..]);
+ /// let beef = bytes.ioread::<u16>().unwrap();
+ ///
+ /// #[cfg(target_endian = "little")]
+ /// assert_eq!(0xbeef, beef);
+ /// #[cfg(target_endian = "big")]
+ /// assert_eq!(0xefbe, beef);
+ /// ```
+ #[inline]
+ fn ioread<N: FromCtx<Ctx> + SizeWith<Ctx>>(&mut self) -> Result<N>
+ where
+ Ctx: Default,
+ {
+ let ctx = Ctx::default();
+ self.ioread_with(ctx)
+ }
+
+ /// Reads the type `N` from `Self`, with the parsing context `ctx`.
+ /// **NB**: this will panic if the type you're reading has a size greater than 256. Plans are to have this allocate in larger cases.
+ ///
+ /// For the primitive numeric types, this will be at the host machine's endianness.
+ ///
+ /// # Example
+ /// ```rust
+ /// use scroll::{IOread, LE, BE};
+ /// use std::io::Cursor;
+ /// let bytes = [0xef, 0xbe, 0xb0, 0xb0, 0xfe, 0xed, 0xde, 0xad];
+ /// let mut bytes = Cursor::new(&bytes[..]);
+ /// let beef = bytes.ioread_with::<u16>(LE).unwrap();
+ /// assert_eq!(0xbeef, beef);
+ /// let b0 = bytes.ioread::<u8>().unwrap();
+ /// assert_eq!(0xb0, b0);
+ /// let b0 = bytes.ioread::<u8>().unwrap();
+ /// assert_eq!(0xb0, b0);
+ /// let feeddead = bytes.ioread_with::<u32>(BE).unwrap();
+ /// assert_eq!(0xfeeddead, feeddead);
+ /// ```
+ #[inline]
+ fn ioread_with<N: FromCtx<Ctx> + SizeWith<Ctx>>(&mut self, ctx: Ctx) -> Result<N> {
+ let mut scratch = [0u8; 256];
+ let size = N::size_with(&ctx);
+ let mut buf = &mut scratch[0..size];
+ self.read_exact(&mut buf)?;
+ Ok(N::from_ctx(buf, ctx))
+ }
+}
+
+/// Types that implement `Read` get methods defined in `IOread`
+/// for free.
+impl<Ctx: Copy, R: Read + ?Sized> IOread<Ctx> for R {}
+
+/// An extension trait to `std::io::Write` streams; this only serializes simple types, like `u8`, `i32`, `f32`, `usize`, etc.
+///
+/// To write custom types with a single `iowrite::<YourType>` call, implement [`IntoCtx`](ctx/trait.IntoCtx.html) and [`SizeWith`](ctx/trait.SizeWith.html) for `YourType`.
+pub trait IOwrite<Ctx: Copy>: Write {
+ /// Writes the type `N` into `Self`, with the parsing context `ctx`.
+ /// **NB**: this will panic if the type you're writing has a size greater than 256. Plans are to have this allocate in larger cases.
+ ///
+ /// For the primitive numeric types, this will be at the host machine's endianness.
+ ///
+ /// # Example
+ /// ```rust
+ /// use scroll::IOwrite;
+ /// use std::io::Cursor;
+ ///
+ /// let mut bytes = [0x0u8; 4];
+ /// let mut bytes = Cursor::new(&mut bytes[..]);
+ /// bytes.iowrite(0xdeadbeef as u32).unwrap();
+ ///
+ /// #[cfg(target_endian = "little")]
+ /// assert_eq!(bytes.into_inner(), [0xef, 0xbe, 0xad, 0xde,]);
+ /// #[cfg(target_endian = "big")]
+ /// assert_eq!(bytes.into_inner(), [0xde, 0xad, 0xbe, 0xef,]);
+ /// ```
+ #[inline]
+ fn iowrite<N: SizeWith<Ctx> + IntoCtx<Ctx>>(&mut self, n: N) -> Result<()>
+ where
+ Ctx: Default,
+ {
+ let ctx = Ctx::default();
+ self.iowrite_with(n, ctx)
+ }
+
+ /// Writes the type `N` into `Self`, with the parsing context `ctx`.
+ /// **NB**: this will panic if the type you're writing has a size greater than 256. Plans are to have this allocate in larger cases.
+ ///
+ /// For the primitive numeric types, this will be at the host machine's endianness.
+ ///
+ /// # Example
+ /// ```rust
+ /// use scroll::{IOwrite, LE, BE};
+ /// use std::io::{Write, Cursor};
+ ///
+ /// let mut bytes = [0x0u8; 10];
+ /// let mut cursor = Cursor::new(&mut bytes[..]);
+ /// cursor.write_all(b"hello").unwrap();
+ /// cursor.iowrite_with(0xdeadbeef as u32, BE).unwrap();
+ /// assert_eq!(cursor.into_inner(), [0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xde, 0xad, 0xbe, 0xef, 0x0]);
+ /// ```
+ #[inline]
+ fn iowrite_with<N: SizeWith<Ctx> + IntoCtx<Ctx>>(&mut self, n: N, ctx: Ctx) -> Result<()> {
+ let mut buf = [0u8; 256];
+ let size = N::size_with(&ctx);
+ let buf = &mut buf[0..size];
+ n.into_ctx(buf, ctx);
+ self.write_all(buf)?;
+ Ok(())
+ }
+}
+
+/// Types that implement `Write` get methods defined in `IOwrite`
+/// for free.
+impl<Ctx: Copy, W: Write + ?Sized> IOwrite<Ctx> for W {}