summaryrefslogtreecommitdiffstats
path: root/third_party/rust/scroll/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/scroll/src
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/scroll/src')
-rw-r--r--third_party/rust/scroll/src/ctx.rs638
-rw-r--r--third_party/rust/scroll/src/endian.rs47
-rw-r--r--third_party/rust/scroll/src/error.rs68
-rw-r--r--third_party/rust/scroll/src/greater.rs151
-rw-r--r--third_party/rust/scroll/src/leb128.rs223
-rw-r--r--third_party/rust/scroll/src/lesser.rs169
-rw-r--r--third_party/rust/scroll/src/lib.rs526
-rw-r--r--third_party/rust/scroll/src/pread.rs203
-rw-r--r--third_party/rust/scroll/src/pwrite.rs79
9 files changed, 2104 insertions, 0 deletions
diff --git a/third_party/rust/scroll/src/ctx.rs b/third_party/rust/scroll/src/ctx.rs
new file mode 100644
index 0000000000..46bd835051
--- /dev/null
+++ b/third_party/rust/scroll/src/ctx.rs
@@ -0,0 +1,638 @@
+//! Generic context-aware conversion traits, for automatic _downstream_ extension of `Pread`, et. al
+//!
+//! # Discussion
+//!
+//! Implementors of `TryFromCtx` automatically grant any client user of `pread, pwrite, gread, gwrite` the ability to parse their structure out of the source it has been implemented for, typically `&[u8]`.
+//!
+//! The implementor only needs to specify the error type, and the type of their size, and then implement the parsing/marshalling logic given a byte sequence, starting at the offset `pread`, et. al was called at, with the context you have implemented it for.
+//!
+//! Returning the size allows dynamic content (e.g., `&str`s) to be parsed alongside fixed size content (e.g., `u64`). The parsing context is any information you the implementor need to correctly parse out your datatype - this could be the endianness of the type, more offsets, or other complex data. The only requirement is that your `Ctx` be `Copy`, and hence encourages lightweight contexts (but this isn't required of course).
+//!
+//!
+//! # Example
+//!
+//! Suppose we have a datatype and we want to specify how to parse or serialize this datatype out of some arbitrary
+//! byte buffer. In order to do this, we need to provide a `TryFromCtx` impl for our datatype. In particular, if we
+//! do this for the `[u8]` target, with a "parsing contex", `YourCtx`, you will automatically get access to
+//! calling `pread_with::<YourDatatype>(offset, your_ctx)` on arrays of bytes.
+//!
+//! In the example below, we implement `TryFromCtx` using the `Endian` parsing context provided by `scroll`, which is used to specifying the endianness at which numbers should be parsed, but you could provide anything, as long as it implements `Copy`.
+//!
+//! ```rust
+//! use scroll::{self, ctx, Endian, Pread, BE};
+//!
+//! struct Data<'a> {
+//! name: &'a str,
+//! id: u32,
+//! }
+//!
+//! impl<'a> ctx::TryFromCtx<'a, Endian> for Data<'a> {
+//! type Error = scroll::Error;
+//! fn try_from_ctx (src: &'a [u8], ctx: Endian)
+//! -> Result<(Self, usize), Self::Error> {
+//! let name = src.pread::<&str>(0)?;
+//! let id = src.pread_with(name.len() + 1, ctx)?;
+//! Ok((Data { name: name, id: id }, name.len() + 1 + 4))
+//! }
+//! }
+//!
+//! let bytes = b"UserName\x00\x01\x02\x03\x04";
+//! let data = bytes.pread_with::<Data>(0, BE).unwrap();
+//! assert_eq!(data.id, 0x01020304);
+//! assert_eq!(data.name.to_string(), "UserName".to_string());
+//!
+//! ```
+
+use core::ptr::copy_nonoverlapping;
+use core::mem::transmute;
+use core::mem::size_of;
+use core::str;
+use core::result;
+
+#[cfg(feature = "std")]
+use std::ffi::{CStr, CString};
+
+use crate::error;
+use crate::endian::Endian;
+
+/// A trait for measuring how large something is; for a byte sequence, it will be its length.
+pub trait MeasureWith<Ctx> {
+ /// How large is `Self`, given the `ctx`?
+ fn measure_with(&self, ctx: &Ctx) -> usize;
+}
+
+impl<Ctx> MeasureWith<Ctx> for [u8] {
+ #[inline]
+ fn measure_with(&self, _ctx: &Ctx) -> usize {
+ self.len()
+ }
+}
+
+impl<Ctx, T: AsRef<[u8]>> MeasureWith<Ctx> for T {
+ #[inline]
+ fn measure_with(&self, _ctx: &Ctx) -> usize {
+ self.as_ref().len()
+ }
+}
+
+/// The parsing context for converting a byte sequence to a `&str`
+///
+/// `StrCtx` specifies what byte delimiter to use, and defaults to C-style null terminators. Be careful.
+#[derive(Debug, Copy, Clone)]
+pub enum StrCtx {
+ Delimiter(u8),
+ DelimiterUntil(u8, usize),
+ Length(usize),
+}
+
+/// A C-style, null terminator based delimiter
+pub const NULL: u8 = 0;
+/// A space-based delimiter
+pub const SPACE: u8 = 0x20;
+/// A newline-based delimiter
+pub const RET: u8 = 0x0a;
+/// A tab-based delimiter
+pub const TAB: u8 = 0x09;
+
+impl Default for StrCtx {
+ #[inline]
+ fn default() -> Self {
+ StrCtx::Delimiter(NULL)
+ }
+}
+
+impl StrCtx {
+ pub fn len(&self) -> usize {
+ match *self {
+ StrCtx::Delimiter(_) |
+ StrCtx::DelimiterUntil(_, _) => 1,
+ StrCtx::Length(_) => 0,
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ if let StrCtx::Length(_) = *self { true } else { false }
+ }
+}
+
+/// Reads `Self` from `This` using the context `Ctx`; must _not_ fail
+pub trait FromCtx<Ctx: Copy = (), This: ?Sized = [u8]> {
+ fn from_ctx(this: &This, ctx: Ctx) -> Self;
+}
+
+/// Tries to read `Self` from `This` using the context `Ctx`
+pub trait TryFromCtx<'a, Ctx: Copy = (), This: ?Sized = [u8]> where Self: 'a + Sized {
+ type Error;
+ fn try_from_ctx(from: &'a This, ctx: Ctx) -> Result<(Self, usize), Self::Error>;
+}
+
+/// Writes `Self` into `This` using the context `Ctx`
+pub trait IntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
+ fn into_ctx(self, _: &mut This, ctx: Ctx);
+}
+
+/// Tries to write `Self` into `This` using the context `Ctx`
+pub trait TryIntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
+ type Error;
+ fn try_into_ctx(self, _: &mut This, ctx: Ctx) -> Result<usize, Self::Error>;
+}
+
+/// Gets the size of `Self` with a `Ctx`, and in `Self::Units`. Implementors can then call `Gread` related functions
+///
+/// The rationale behind this trait is to:
+///
+/// 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.
+/// 2. Allow a context based size, which is useful for 32/64 bit variants for various containers, etc.
+pub trait SizeWith<Ctx = ()> {
+ fn size_with(ctx: &Ctx) -> usize;
+}
+
+macro_rules! signed_to_unsigned {
+ (i8) => {u8 };
+ (u8) => {u8 };
+ (i16) => {u16};
+ (u16) => {u16};
+ (i32) => {u32};
+ (u32) => {u32};
+ (i64) => {u64};
+ (u64) => {u64};
+ (i128) => {u128};
+ (u128) => {u128};
+ (f32) => {u32};
+ (f64) => {u64};
+}
+
+macro_rules! write_into {
+ ($typ:ty, $size:expr, $n:expr, $dst:expr, $endian:expr) => ({
+ unsafe {
+ assert!($dst.len() >= $size);
+ let bytes = transmute::<$typ, [u8; $size]>(if $endian.is_little() { $n.to_le() } else { $n.to_be() });
+ copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size);
+ }
+ });
+}
+
+macro_rules! into_ctx_impl {
+ ($typ:tt, $size:expr) => {
+ impl IntoCtx<Endian> for $typ {
+ #[inline]
+ fn into_ctx(self, dst: &mut [u8], le: Endian) {
+ assert!(dst.len() >= $size);
+ write_into!($typ, $size, self, dst, le);
+ }
+ }
+ impl<'a> IntoCtx<Endian> for &'a $typ {
+ #[inline]
+ fn into_ctx(self, dst: &mut [u8], le: Endian) {
+ (*self).into_ctx(dst, le)
+ }
+ }
+ impl TryIntoCtx<Endian> for $typ where $typ: IntoCtx<Endian> {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
+ if $size > dst.len () {
+ Err(error::Error::TooBig{size: $size, len: dst.len()})
+ } else {
+ <$typ as IntoCtx<Endian>>::into_ctx(self, dst, le);
+ Ok($size)
+ }
+ }
+ }
+ impl<'a> TryIntoCtx<Endian> for &'a $typ {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
+ (*self).try_into_ctx(dst, le)
+ }
+ }
+ }
+}
+
+macro_rules! from_ctx_impl {
+ ($typ:tt, $size:expr) => {
+ impl<'a> FromCtx<Endian> for $typ {
+ #[inline]
+ fn from_ctx(src: &[u8], le: Endian) -> Self {
+ assert!(src.len() >= $size);
+ let mut data: signed_to_unsigned!($typ) = 0;
+ unsafe {
+ copy_nonoverlapping(
+ src.as_ptr(),
+ &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
+ $size);
+ }
+ (if le.is_little() { data.to_le() } else { data.to_be() }) as $typ
+ }
+ }
+
+ impl<'a> TryFromCtx<'a, Endian> for $typ where $typ: FromCtx<Endian> {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a [u8], le: Endian) -> result::Result<(Self, usize), Self::Error> {
+ if $size > src.len () {
+ Err(error::Error::TooBig{size: $size, len: src.len()})
+ } else {
+ Ok((FromCtx::from_ctx(&src, le), $size))
+ }
+ }
+ }
+ // as ref
+ impl<'a, T> FromCtx<Endian, T> for $typ where T: AsRef<[u8]> {
+ #[inline]
+ fn from_ctx(src: &T, le: Endian) -> Self {
+ let src = src.as_ref();
+ assert!(src.len() >= $size);
+ let mut data: signed_to_unsigned!($typ) = 0;
+ unsafe {
+ copy_nonoverlapping(
+ src.as_ptr(),
+ &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
+ $size);
+ }
+ (if le.is_little() { data.to_le() } else { data.to_be() }) as $typ
+ }
+ }
+
+ impl<'a, T> TryFromCtx<'a, Endian, T> for $typ where $typ: FromCtx<Endian, T>, T: AsRef<[u8]> {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a T, le: Endian) -> result::Result<(Self, usize), Self::Error> {
+ let src = src.as_ref();
+ Self::try_from_ctx(src, le)
+ }
+ }
+ };
+}
+
+macro_rules! ctx_impl {
+ ($typ:tt, $size:expr) => {
+ from_ctx_impl!($typ, $size);
+ };
+}
+
+ctx_impl!(u8, 1);
+ctx_impl!(i8, 1);
+ctx_impl!(u16, 2);
+ctx_impl!(i16, 2);
+ctx_impl!(u32, 4);
+ctx_impl!(i32, 4);
+ctx_impl!(u64, 8);
+ctx_impl!(i64, 8);
+ctx_impl!(u128, 16);
+ctx_impl!(i128, 16);
+
+macro_rules! from_ctx_float_impl {
+ ($typ:tt, $size:expr) => {
+ impl<'a> FromCtx<Endian> for $typ {
+ #[inline]
+ fn from_ctx(src: &[u8], le: Endian) -> Self {
+ assert!(src.len() >= ::core::mem::size_of::<Self>());
+ let mut data: signed_to_unsigned!($typ) = 0;
+ unsafe {
+ copy_nonoverlapping(
+ src.as_ptr(),
+ &mut data as *mut signed_to_unsigned!($typ) as *mut u8,
+ $size);
+ transmute(if le.is_little() { data.to_le() } else { data.to_be() })
+ }
+ }
+ }
+ impl<'a> TryFromCtx<'a, Endian> for $typ where $typ: FromCtx<Endian> {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a [u8], le: Endian) -> result::Result<(Self, usize), Self::Error> {
+ if $size > src.len () {
+ Err(error::Error::TooBig{size: $size, len: src.len()})
+ } else {
+ Ok((FromCtx::from_ctx(src, le), $size))
+ }
+ }
+ }
+ }
+}
+
+from_ctx_float_impl!(f32, 4);
+from_ctx_float_impl!(f64, 8);
+
+into_ctx_impl!(u8, 1);
+into_ctx_impl!(i8, 1);
+into_ctx_impl!(u16, 2);
+into_ctx_impl!(i16, 2);
+into_ctx_impl!(u32, 4);
+into_ctx_impl!(i32, 4);
+into_ctx_impl!(u64, 8);
+into_ctx_impl!(i64, 8);
+into_ctx_impl!(u128, 16);
+into_ctx_impl!(i128, 16);
+
+macro_rules! into_ctx_float_impl {
+ ($typ:tt, $size:expr) => {
+ impl IntoCtx<Endian> for $typ {
+ #[inline]
+ fn into_ctx(self, dst: &mut [u8], le: Endian) {
+ assert!(dst.len() >= $size);
+ write_into!(signed_to_unsigned!($typ), $size, transmute::<$typ, signed_to_unsigned!($typ)>(self), dst, le);
+ }
+ }
+ impl<'a> IntoCtx<Endian> for &'a $typ {
+ #[inline]
+ fn into_ctx(self, dst: &mut [u8], le: Endian) {
+ (*self).into_ctx(dst, le)
+ }
+ }
+ impl TryIntoCtx<Endian> for $typ where $typ: IntoCtx<Endian> {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
+ if $size > dst.len () {
+ Err(error::Error::TooBig{size: $size, len: dst.len()})
+ } else {
+ <$typ as IntoCtx<Endian>>::into_ctx(self, dst, le);
+ Ok($size)
+ }
+ }
+ }
+ impl<'a> TryIntoCtx<Endian> for &'a $typ {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
+ (*self).try_into_ctx(dst, le)
+ }
+ }
+ }
+}
+
+into_ctx_float_impl!(f32, 4);
+into_ctx_float_impl!(f64, 8);
+
+impl<'a> TryFromCtx<'a, StrCtx> for &'a str {
+ type Error = error::Error;
+ #[inline]
+ /// Read a `&str` from `src` using `delimiter`
+ fn try_from_ctx(src: &'a [u8], ctx: StrCtx) -> Result<(Self, usize), Self::Error> {
+ let len = match ctx {
+ StrCtx::Length(len) => len,
+ StrCtx::Delimiter(delimiter) => src.iter().take_while(|c| **c != delimiter).count(),
+ StrCtx::DelimiterUntil(delimiter, len) => {
+ if len > src.len() {
+ return Err(error::Error::TooBig{size: len, len: src.len()});
+ };
+ src
+ .iter()
+ .take_while(|c| **c != delimiter)
+ .take(len)
+ .count()
+ }
+ };
+
+ if len > src.len() {
+ return Err(error::Error::TooBig{size: len, len: src.len()});
+ };
+
+ match str::from_utf8(&src[..len]) {
+ Ok(res) => Ok((res, len + ctx.len())),
+ Err(_) => Err(error::Error::BadInput{size: src.len(), msg: "invalid utf8"})
+ }
+ }
+}
+
+impl<'a, T> TryFromCtx<'a, StrCtx, T> for &'a str where T: AsRef<[u8]> {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a T, ctx: StrCtx) -> result::Result<(Self, usize), Self::Error> {
+ let src = src.as_ref();
+ TryFromCtx::try_from_ctx(src, ctx)
+ }
+}
+
+impl<'a> TryIntoCtx for &'a [u8] {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
+ let src_len = self.len() as isize;
+ let dst_len = dst.len() as isize;
+ // if src_len < 0 || dst_len < 0 || offset < 0 {
+ // return Err(error::Error::BadOffset(format!("requested operation has negative casts: src len: {} dst len: {} offset: {}", src_len, dst_len, offset)).into())
+ // }
+ if src_len > dst_len {
+ Err(error::Error::TooBig{ size: self.len(), len: dst.len()})
+ } else {
+ unsafe { copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), src_len as usize) };
+ Ok(self.len())
+ }
+ }
+}
+
+// TODO: make TryIntoCtx use StrCtx for awesomeness
+impl<'a> TryIntoCtx for &'a str {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
+ let bytes = self.as_bytes();
+ TryIntoCtx::try_into_ctx(bytes, dst, ())
+ }
+}
+
+// TODO: we can make this compile time without size_of call, but compiler probably does that anyway
+macro_rules! sizeof_impl {
+ ($ty:ty) => {
+ impl SizeWith<Endian> for $ty {
+ #[inline]
+ fn size_with(_ctx: &Endian) -> usize {
+ size_of::<$ty>()
+ }
+ }
+ }
+}
+
+sizeof_impl!(u8);
+sizeof_impl!(i8);
+sizeof_impl!(u16);
+sizeof_impl!(i16);
+sizeof_impl!(u32);
+sizeof_impl!(i32);
+sizeof_impl!(u64);
+sizeof_impl!(i64);
+sizeof_impl!(u128);
+sizeof_impl!(i128);
+sizeof_impl!(f32);
+sizeof_impl!(f64);
+sizeof_impl!(usize);
+sizeof_impl!(isize);
+
+impl FromCtx<Endian> for usize {
+ #[inline]
+ fn from_ctx(src: &[u8], le: Endian) -> Self {
+ let size = ::core::mem::size_of::<Self>();
+ assert!(src.len() >= size);
+ let mut data: usize = 0;
+ unsafe {
+ copy_nonoverlapping(
+ src.as_ptr(),
+ &mut data as *mut usize as *mut u8,
+ size);
+ if le.is_little() { data.to_le() } else { data.to_be() }
+ }
+ }
+}
+
+impl<'a> TryFromCtx<'a, Endian> for usize where usize: FromCtx<Endian> {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a [u8], le: Endian) -> result::Result<(Self, usize), Self::Error> {
+ let size = ::core::mem::size_of::<usize>();
+ if size > src.len () {
+ Err(error::Error::TooBig{size, len: src.len()})
+ } else {
+ Ok((FromCtx::from_ctx(src, le), size))
+ }
+ }
+}
+
+impl<'a> TryFromCtx<'a, usize> for &'a[u8] {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a [u8], size: usize) -> result::Result<(Self, usize), Self::Error> {
+ if size > src.len () {
+ Err(error::Error::TooBig{size, len: src.len()})
+ } else {
+ Ok((&src[..size], size))
+ }
+ }
+}
+
+impl IntoCtx<Endian> for usize {
+ #[inline]
+ fn into_ctx(self, dst: &mut [u8], le: Endian) {
+ let size = ::core::mem::size_of::<Self>();
+ assert!(dst.len() >= size);
+ let mut data = if le.is_little() { self.to_le() } else { self.to_be() };
+ let data = &mut data as *mut usize as *mut u8;
+ unsafe {
+ copy_nonoverlapping(data, dst.as_mut_ptr(), size);
+ }
+ }
+}
+
+impl TryIntoCtx<Endian> for usize where usize: IntoCtx<Endian> {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
+ let size = ::core::mem::size_of::<usize>();
+ if size > dst.len() {
+ Err(error::Error::TooBig{size, len: dst.len()})
+ } else {
+ <usize as IntoCtx<Endian>>::into_ctx(self, dst, le);
+ Ok(size)
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'a> TryFromCtx<'a> for &'a CStr {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
+ let null_byte = match src.iter().position(|b| *b == 0) {
+ Some(ix) => ix,
+ None => return Err(error::Error::BadInput {
+ size: 0,
+ msg: "The input doesn't contain a null byte",
+ })
+ };
+
+ let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(&src[..=null_byte]) };
+ Ok((cstr, null_byte+1))
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'a> TryFromCtx<'a> for CString {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
+ let (raw, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(src, _ctx)?;
+ Ok((raw.to_owned(), bytes_read))
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'a> TryIntoCtx for &'a CStr {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
+ let data = self.to_bytes_with_nul();
+
+ if dst.len() < data.len() {
+ Err(error::Error::TooBig {
+ size: dst.len(),
+ len: data.len(),
+ })
+ } else {
+ unsafe {
+ copy_nonoverlapping(data.as_ptr(), dst.as_mut_ptr(), data.len());
+ }
+
+ Ok(data.len())
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl TryIntoCtx for CString {
+ type Error = error::Error;
+ #[inline]
+ fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
+ self.as_c_str().try_into_ctx(dst, ())
+ }
+}
+
+
+// example of marshalling to bytes, let's wait until const is an option
+// impl FromCtx for [u8; 10] {
+// fn from_ctx(bytes: &[u8], _ctx: Endian) -> Self {
+// let mut dst: Self = [0; 10];
+// assert!(bytes.len() >= dst.len());
+// unsafe {
+// copy_nonoverlapping(bytes.as_ptr(), dst.as_mut_ptr(), dst.len());
+// }
+// dst
+// }
+// }
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn parse_a_cstr() {
+ let src = CString::new("Hello World").unwrap();
+ let as_bytes = src.as_bytes_with_nul();
+
+ let (got, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(as_bytes, ()).unwrap();
+
+ assert_eq!(bytes_read, as_bytes.len());
+ assert_eq!(got, src.as_c_str());
+ }
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn round_trip_a_c_str() {
+ let src = CString::new("Hello World").unwrap();
+ let src = src.as_c_str();
+ let as_bytes = src.to_bytes_with_nul();
+
+ let mut buffer = vec![0; as_bytes.len()];
+ let bytes_written = src.try_into_ctx(&mut buffer, ()).unwrap();
+ assert_eq!(bytes_written, as_bytes.len());
+
+ let (got, bytes_read) = <&CStr as TryFromCtx>::try_from_ctx(&buffer, ()).unwrap();
+
+ assert_eq!(bytes_read, as_bytes.len());
+ assert_eq!(got, src);
+ }
+}
+
+
diff --git a/third_party/rust/scroll/src/endian.rs b/third_party/rust/scroll/src/endian.rs
new file mode 100644
index 0000000000..7652227998
--- /dev/null
+++ b/third_party/rust/scroll/src/endian.rs
@@ -0,0 +1,47 @@
+#[derive(PartialEq, Eq, Copy, Debug, Clone)]
+/// The endianness (byte order) of a stream of bytes
+pub enum Endian {
+ Little,
+ Big,
+}
+
+/// Little Endian byte order context
+pub const LE: Endian = Endian::Little;
+/// Big Endian byte order context
+pub const BE: Endian = Endian::Big;
+/// Network byte order context
+pub const NETWORK: Endian = Endian::Big;
+#[cfg(target_endian = "little")]
+/// The machine's native byte order
+pub const NATIVE: Endian = LE;
+#[cfg(target_endian = "big")]
+/// The machine's native byte order
+pub const NATIVE: Endian = BE;
+
+impl Default for Endian {
+ #[inline]
+ fn default() -> Self {
+ NATIVE
+ }
+}
+
+impl From<bool> for Endian {
+ #[inline]
+ fn from(little_endian: bool) -> Self {
+ if little_endian { LE } else { BE }
+ }
+}
+
+impl Endian {
+ #[inline]
+ pub fn network() -> Endian {
+ NETWORK
+ }
+ #[inline]
+ pub fn is_little(&self) -> bool {
+ match *self {
+ LE => true,
+ _ => false,
+ }
+ }
+}
diff --git a/third_party/rust/scroll/src/error.rs b/third_party/rust/scroll/src/error.rs
new file mode 100644
index 0000000000..0257544139
--- /dev/null
+++ b/third_party/rust/scroll/src/error.rs
@@ -0,0 +1,68 @@
+use core::fmt::{self, Display};
+use core::result;
+
+#[cfg(feature = "std")]
+use std::io;
+#[cfg(feature = "std")]
+use std::error;
+
+#[derive(Debug)]
+/// A custom Scroll error
+pub enum Error {
+ /// The type you tried to read was too big
+ TooBig { size: usize, len: usize },
+ /// The requested offset to read/write at is invalid
+ BadOffset(usize),
+ BadInput{ size: usize, msg: &'static str },
+ #[cfg(feature = "std")]
+ /// A custom Scroll error for reporting messages to clients
+ Custom(String),
+ #[cfg(feature = "std")]
+ /// Returned when IO based errors are encountered
+ IO(io::Error),
+}
+
+#[cfg(feature = "std")]
+impl error::Error for Error {
+ fn description(&self) -> &str {
+ match *self {
+ Error::TooBig{ .. } => { "TooBig" }
+ Error::BadOffset(_) => { "BadOffset" }
+ Error::BadInput{ .. } => { "BadInput" }
+ Error::Custom(_) => { "Custom" }
+ Error::IO(_) => { "IO" }
+ }
+ }
+ fn cause(&self) -> Option<&dyn error::Error> {
+ match *self {
+ Error::TooBig{ .. } => { None }
+ Error::BadOffset(_) => { None }
+ Error::BadInput{ .. } => { None }
+ Error::Custom(_) => { None }
+ Error::IO(ref io) => { io.source() }
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<io::Error> for Error {
+ fn from(err: io::Error) -> Error {
+ Error::IO(err)
+ }
+}
+
+impl Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Error::TooBig{ ref size, ref len } => { write! (fmt, "type is too big ({}) for {}", size, len) },
+ Error::BadOffset(ref offset) => { write! (fmt, "bad offset {}", offset) },
+ Error::BadInput{ ref msg, ref size } => { write! (fmt, "bad input {} ({})", msg, size) },
+ #[cfg(feature = "std")]
+ Error::Custom(ref msg) => { write! (fmt, "{}", msg) },
+ #[cfg(feature = "std")]
+ Error::IO(ref err) => { write!(fmt, "{}", err) },
+ }
+ }
+}
+
+pub type Result<T> = result::Result<T, Error>;
diff --git a/third_party/rust/scroll/src/greater.rs b/third_party/rust/scroll/src/greater.rs
new file mode 100644
index 0000000000..7a33051128
--- /dev/null
+++ b/third_party/rust/scroll/src/greater.rs
@@ -0,0 +1,151 @@
+use core::ops::{Index, IndexMut, RangeFrom};
+
+use crate::ctx::{FromCtx, IntoCtx};
+
+/// Core-read - core, no_std friendly trait for reading basic traits from byte buffers. Cannot fail unless the buffer is too small, in which case an assert fires and the program panics.
+///
+/// If your type implements [FromCtx](trait.FromCtx.html) then you can `cread::<YourType>(offset)`.
+///
+/// # Example
+///
+/// ```rust
+/// use scroll::{ctx, Cread, LE};
+///
+/// #[repr(packed)]
+/// struct Bar {
+/// foo: i32,
+/// bar: u32,
+/// }
+///
+/// impl ctx::FromCtx<scroll::Endian> for Bar {
+/// fn from_ctx(bytes: &[u8], ctx: scroll::Endian) -> Self {
+/// use scroll::Cread;
+/// Bar { foo: bytes.cread_with(0, ctx), bar: bytes.cread_with(4, ctx) }
+/// }
+/// }
+///
+/// let bytes = [0xff, 0xff, 0xff, 0xff, 0xef,0xbe,0xad,0xde,];
+/// let bar = bytes.cread_with::<Bar>(0, LE);
+/// // 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!({bar.foo}, -1);
+/// assert_eq!({bar.bar}, 0xdeadbeef);
+/// ```
+pub trait Cread<Ctx, I = usize> : Index<I> + Index<RangeFrom<I>>
+ where
+ Ctx: Copy,
+{
+ /// Reads a value from `Self` at `offset` with `ctx`. Cannot fail.
+ /// If the buffer is too small for the value requested, this will panic.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use scroll::{Cread, BE, LE};
+ /// use std::i64::MAX;
+ ///
+ /// let bytes = [0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xef,0xbe,0xad,0xde,];
+ /// let foo = bytes.cread_with::<i64>(0, BE);
+ /// let bar = bytes.cread_with::<u32>(8, LE);
+ /// assert_eq!(foo, MAX);
+ /// assert_eq!(bar, 0xdeadbeef);
+ /// ```
+ #[inline]
+ fn cread_with<N: FromCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&self, offset: I, ctx: Ctx) -> N {
+ N::from_ctx(&self[offset..], ctx)
+ }
+ /// Reads a value implementing `FromCtx` from `Self` at `offset`,
+ /// with the **target machine**'s endianness.
+ /// For the primitive types, this will be the **target machine**'s endianness.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use scroll::Cread;
+ ///
+ /// let bytes = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
+ /// let foo = bytes.cread::<i64>(0);
+ /// let bar = bytes.cread::<u32>(8);
+ /// #[cfg(target_endian = "little")]
+ /// assert_eq!(foo, 1);
+ /// #[cfg(target_endian = "big")]
+ /// assert_eq!(foo, 0x100_0000_0000_0000);
+ ///
+ /// #[cfg(target_endian = "little")]
+ /// assert_eq!(bar, 0xbeef);
+ /// #[cfg(target_endian = "big")]
+ /// assert_eq!(bar, 0xefbe0000);
+ /// ```
+ #[inline]
+ fn cread<N: FromCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&self, offset: I) -> N where Ctx: Default {
+ let ctx = Ctx::default();
+ N::from_ctx(&self[offset..], ctx)
+ }
+}
+
+impl<Ctx: Copy, I, R: ?Sized + Index<I> + Index<RangeFrom<I>>> Cread<Ctx, I> for R {}
+
+/// Core-write - core, no_std friendly trait for writing basic types into byte buffers. Cannot fail unless the buffer is too small, in which case an assert fires and the program panics.
+/// Similar to [Cread](trait.Cread.html), if your type implements [IntoCtx](trait.IntoCtx.html) then you can `cwrite(your_type, offset)`.
+///
+/// # Example
+///
+/// ```rust
+/// use scroll::{ctx, Cwrite};
+///
+/// #[repr(packed)]
+/// struct Bar {
+/// foo: i32,
+/// bar: u32,
+/// }
+///
+/// impl ctx::IntoCtx<scroll::Endian> for Bar {
+/// fn into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) {
+/// use scroll::Cwrite;
+/// bytes.cwrite_with(self.foo, 0, ctx);
+/// bytes.cwrite_with(self.bar, 4, ctx);
+/// }
+/// }
+///
+/// let bar = Bar { foo: -1, bar: 0xdeadbeef };
+/// let mut bytes = [0x0; 16];
+/// bytes.cwrite::<Bar>(bar, 0);
+/// ```
+pub trait Cwrite<Ctx: Copy, I = usize>: Index<I> + IndexMut<RangeFrom<I>> {
+ /// Writes `n` into `Self` at `offset`; uses default context.
+ /// For the primitive types, this will be the **target machine**'s endianness.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use scroll::{Cwrite, Cread};
+ /// let mut bytes = [0x0; 16];
+ /// bytes.cwrite::<i64>(42, 0);
+ /// bytes.cwrite::<u32>(0xdeadbeef, 8);
+ ///
+ /// assert_eq!(bytes.cread::<i64>(0), 42);
+ /// assert_eq!(bytes.cread::<u32>(8), 0xdeadbeef);
+ #[inline]
+ fn cwrite<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: N, offset: I) where Ctx: Default {
+ let ctx = Ctx::default();
+ n.into_ctx(self.index_mut(offset..), ctx)
+ }
+ /// Writes `n` into `Self` at `offset` with `ctx`
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use scroll::{Cwrite, Cread, LE, BE};
+ /// let mut bytes = [0x0; 0x10];
+ /// bytes.cwrite_with::<i64>(42, 0, LE);
+ /// bytes.cwrite_with::<u32>(0xdeadbeef, 8, BE);
+ /// assert_eq!(bytes.cread_with::<i64>(0, LE), 42);
+ /// assert_eq!(bytes.cread_with::<u32>(8, LE), 0xefbeadde);
+ #[inline]
+ fn cwrite_with<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: N, offset: I, ctx: Ctx) {
+ n.into_ctx(self.index_mut(offset..), ctx)
+ }
+}
+
+impl<Ctx: Copy, I, W: ?Sized + Index<I> + IndexMut<RangeFrom<I>>> Cwrite<Ctx, I> for W {}
diff --git a/third_party/rust/scroll/src/leb128.rs b/third_party/rust/scroll/src/leb128.rs
new file mode 100644
index 0000000000..657b4400a7
--- /dev/null
+++ b/third_party/rust/scroll/src/leb128.rs
@@ -0,0 +1,223 @@
+use core::u8;
+use core::convert::{From, AsRef};
+use core::result;
+use crate::Pread;
+use crate::ctx::TryFromCtx;
+use crate::error;
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+/// An unsigned leb128 integer
+pub struct Uleb128 {
+ value: u64,
+ count: usize,
+}
+
+impl Uleb128 {
+ #[inline]
+ /// Return how many bytes this Uleb128 takes up in memory
+ pub fn size(&self) -> usize {
+ self.count
+ }
+ #[inline]
+ /// Read a variable length u64 from `bytes` at `offset`
+ pub fn read(bytes: &[u8], offset: &mut usize) -> error::Result<u64> {
+ let tmp = bytes.pread::<Uleb128>(*offset)?;
+ *offset += tmp.size();
+ Ok(tmp.into())
+ }
+}
+
+impl AsRef<u64> for Uleb128 {
+ fn as_ref(&self) -> &u64 {
+ &self.value
+ }
+}
+
+impl From<Uleb128> for u64 {
+ #[inline]
+ fn from(uleb128: Uleb128) -> u64 {
+ uleb128.value
+ }
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+/// An signed leb128 integer
+pub struct Sleb128 {
+ value: i64,
+ count: usize,
+}
+
+impl Sleb128 {
+ #[inline]
+ /// Return how many bytes this Sleb128 takes up in memory
+ pub fn size(&self) -> usize {
+ self.count
+ }
+ #[inline]
+ /// Read a variable length i64 from `bytes` at `offset`
+ pub fn read(bytes: &[u8], offset: &mut usize) -> error::Result<i64> {
+ let tmp = bytes.pread::<Sleb128>(*offset)?;
+ *offset += tmp.size();
+ Ok(tmp.into())
+ }
+}
+
+impl AsRef<i64> for Sleb128 {
+ fn as_ref(&self) -> &i64 {
+ &self.value
+ }
+}
+
+impl From<Sleb128> for i64 {
+ #[inline]
+ fn from(sleb128: Sleb128) -> i64 {
+ sleb128.value
+ }
+}
+
+// Below implementation heavily adapted from: https://github.com/fitzgen/leb128
+const CONTINUATION_BIT: u8 = 1 << 7;
+const SIGN_BIT: u8 = 1 << 6;
+
+#[inline]
+fn mask_continuation(byte: u8) -> u8 {
+ byte & !CONTINUATION_BIT
+}
+
+// #[inline]
+// fn mask_continuation_u64(val: u64) -> u8 {
+// let byte = val & (u8::MAX as u64);
+// mask_continuation(byte as u8)
+// }
+
+impl<'a> TryFromCtx<'a> for Uleb128 {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
+ let mut result = 0;
+ let mut shift = 0;
+ let mut count = 0;
+ loop {
+ let byte: u8 = src.pread(count)?;
+
+ if shift == 63 && byte != 0x00 && byte != 0x01 {
+ return Err(error::Error::BadInput{ size: src.len(), msg: "failed to parse"})
+ }
+
+ let low_bits = u64::from(mask_continuation(byte));
+ result |= low_bits << shift;
+
+ count += 1;
+ shift += 7;
+
+ if byte & CONTINUATION_BIT == 0 {
+ return Ok((Uleb128 { value: result, count }, count));
+ }
+ }
+ }
+}
+
+impl<'a> TryFromCtx<'a> for Sleb128 {
+ type Error = error::Error;
+ #[inline]
+ fn try_from_ctx(src: &'a [u8], _ctx: ()) -> result::Result<(Self, usize), Self::Error> {
+ let o = 0;
+ let offset = &mut 0;
+ let mut result = 0;
+ let mut shift = 0;
+ let size = 64;
+ let mut byte: u8;
+ loop {
+ byte = src.gread(offset)?;
+
+ if shift == 63 && byte != 0x00 && byte != 0x7f {
+ return Err(error::Error::BadInput{size: src.len(), msg: "failed to parse"})
+ }
+
+ let low_bits = i64::from(mask_continuation(byte));
+ result |= low_bits << shift;
+ shift += 7;
+
+ if byte & CONTINUATION_BIT == 0 {
+ break;
+ }
+ }
+
+ if shift < size && (SIGN_BIT & byte) == SIGN_BIT {
+ // Sign extend the result.
+ result |= !0 << shift;
+ }
+ let count = *offset - o;
+ Ok((Sleb128{ value: result, count }, count))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{Uleb128, Sleb128};
+ use super::super::LE;
+
+ const CONTINUATION_BIT: u8 = 1 << 7;
+ //const SIGN_BIT: u8 = 1 << 6;
+
+ #[test]
+ fn uleb_size() {
+ use super::super::Pread;
+ let buf = [2u8 | CONTINUATION_BIT, 1];
+ let bytes = &buf[..];
+ let num = bytes.pread::<Uleb128>(0).unwrap();
+ println!("num: {:?}", &num);
+ assert_eq!(130u64, num.into());
+ assert_eq!(num.size(), 2);
+
+ let buf = [0x00,0x01];
+ let bytes = &buf[..];
+ let num = bytes.pread::<Uleb128>(0).unwrap();
+ println!("num: {:?}", &num);
+ assert_eq!(0u64, num.into());
+ assert_eq!(num.size(), 1);
+
+ let buf = [0x21];
+ let bytes = &buf[..];
+ let num = bytes.pread::<Uleb128>(0).unwrap();
+ println!("num: {:?}", &num);
+ assert_eq!(0x21u64, num.into());
+ assert_eq!(num.size(), 1);
+ }
+
+ #[test]
+ fn uleb128() {
+ use super::super::Pread;
+ let buf = [2u8 | CONTINUATION_BIT, 1];
+ let bytes = &buf[..];
+ let num = bytes.pread::<Uleb128>(0).expect("Should read Uleb128");
+ assert_eq!(130u64, num.into());
+ assert_eq!(386, bytes.pread_with::<u16>(0, LE).expect("Should read number"));
+ }
+
+ #[test]
+ fn uleb128_overflow() {
+ use super::super::Pread;
+ let buf = [2u8 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 2 | CONTINUATION_BIT,
+ 1];
+ let bytes = &buf[..];
+ assert!(bytes.pread::<Uleb128>(0).is_err());
+ }
+
+ #[test]
+ fn sleb128() {
+ use super::super::Pread;
+ let bytes = [0x7fu8 | CONTINUATION_BIT, 0x7e];
+ let num: i64 = bytes.pread::<Sleb128>(0).expect("Should read Sleb128").into();
+ assert_eq!(-129, num);
+ }
+}
diff --git a/third_party/rust/scroll/src/lesser.rs b/third_party/rust/scroll/src/lesser.rs
new file mode 100644
index 0000000000..84cb000135
--- /dev/null
+++ b/third_party/rust/scroll/src/lesser.rs
@@ -0,0 +1,169 @@
+use std::io::{Result, Read, Write};
+use crate::ctx::{FromCtx, IntoCtx, SizeWith};
+
+/// An extension trait to `std::io::Read` streams; this only deserializes simple types, like `u8`, `i32`, `f32`, `usize`, etc.
+///
+/// If you implement [`FromCtx`](trait.FromCtx.html) and [`SizeWith`](ctx/trait.SizeWith.html) for your type, you can then `ioread::<YourType>()` on a `Read`. Note: [`FromCtx`](trait.FromCtx.html) is only meant for very simple types, and should _never_ fail.
+///
+/// **NB** You should probably add `repr(packed)` or `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`
+///
+/// # 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`](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 {}
diff --git a/third_party/rust/scroll/src/lib.rs b/third_party/rust/scroll/src/lib.rs
new file mode 100644
index 0000000000..f16f153810
--- /dev/null
+++ b/third_party/rust/scroll/src/lib.rs
@@ -0,0 +1,526 @@
+//! # Scroll
+//!
+//! ```text, no_run
+//! _______________
+//! ()==( (@==()
+//! '______________'|
+//! | |
+//! | ἀρετή |
+//! __)_____________|
+//! ()==( (@==()
+//! '--------------'
+//!
+//! ```
+//!
+//! Scroll is a library for efficiently and easily reading/writing types from byte arrays. All the builtin types are supported, e.g., `u32`, `i8`, etc., where the type is specified as a type parameter, or type inferred when possible. In addition, it supports zero-copy reading of string slices, or any other kind of slice. The library can be used in a no_std context as well; the [Error](enum.Error.html) type only has the `IO` and `String` variants if the default features are used, and is `no_std` safe when compiled without default features.
+//!
+//! There are 3 traits for reading that you can import:
+//!
+//! 1. [Pread](trait.Pread.html), for reading (immutable) data at an offset;
+//! 2. [Gread](trait.Gread.html), for reading data at an offset which automatically gets incremented by the size;
+//! 3. [IOread](trait.IOread.html), for reading _simple_ data out of a `std::io::Read` based interface, e.g., a stream. (**Note**: only available when compiled with `std`)
+//!
+//! Each of these interfaces also have their corresponding writer versions as well, e.g., [Pwrite](trait.Pwrite.html), [Gwrite](trait.Gwrite.html), and [IOwrite](trait.IOwrite.html), respectively.
+//!
+//! Most familiar will likely be the `Pread` trait (inspired from the C function), which in our case takes an immutable reference to self, an immutable offset to read at, (and _optionally_ a parsing context, more on that later), and then returns the deserialized value.
+//!
+//! Because self is immutable, _**all** reads can be performed in parallel_ and hence are trivially parallelizable.
+//!
+//! For most usecases, you can use [scroll_derive](https://docs.rs/scroll_derive) to annotate your types with `derive(Pread, Pwrite, IOread, IOwrite, SizeWith)` to automatically add sensible derive defaults, and you should be ready to roll. For more complex usescases, you can implement the conversion traits yourself, see the [context module](ctx/index.html) for more information.
+//!
+//! # Example
+//!
+//! A simple example demonstrates its flexibility:
+//!
+//! ```rust
+//! use scroll::{ctx, Pread, LE};
+//! let bytes: [u8; 4] = [0xde, 0xad, 0xbe, 0xef];
+//!
+//! // reads a u32 out of `b` with the endianness of the host machine, at offset 0, turbofish-style
+//! let number: u32 = bytes.pread::<u32>(0).unwrap();
+//! // ...or a byte, with type ascription on the binding.
+//! let byte: u8 = bytes.pread(0).unwrap();
+//!
+//! //If the type is known another way by the compiler, say reading into a struct field, we can omit the turbofish, and type ascription altogether!
+//!
+//! // If we want, we can explicitly add a endianness to read with by calling `pread_with`.
+//! // The following reads a u32 out of `b` with Big Endian byte order, at offset 0
+//! let be_number: u32 = bytes.pread_with(0, scroll::BE).unwrap();
+//! // or a u16 - specify the type either on the variable or with the beloved turbofish
+//! let be_number2 = bytes.pread_with::<u16>(2, scroll::BE).unwrap();
+//!
+//! // Scroll has core friendly errors (no allocation). This will have the type `scroll::Error::BadOffset` because it tried to read beyond the bound
+//! let byte: scroll::Result<i64> = bytes.pread(0);
+//!
+//! // Scroll is extensible: as long as the type implements `TryWithCtx`, then you can read your type out of the byte array!
+//!
+//! // We can parse out custom datatypes, or types with lifetimes
+//! // if they implement the conversion trait `TryFromCtx`; here we parse a C-style \0 delimited &str (safely)
+//! let hello: &[u8] = b"hello_world\0more words";
+//! let hello_world: &str = hello.pread(0).unwrap();
+//! assert_eq!("hello_world", hello_world);
+//!
+//! // ... and this parses the string if its space separated!
+//! use scroll::ctx::*;
+//! let spaces: &[u8] = b"hello world some junk";
+//! let world: &str = spaces.pread_with(6, StrCtx::Delimiter(SPACE)).unwrap();
+//! assert_eq!("world", world);
+//! ```
+//!
+//! # `std::io` API
+//!
+//! Scroll can also read/write simple types from a `std::io::Read` or `std::io::Write` implementor. The built-in numeric types are taken care of for you. If you want to read a custom type, you need to implement the [FromCtx](trait.FromCtx.html) (_how_ to parse) and [SizeWith](ctx/trait.SizeWith.html) (_how_ big the parsed thing will be) traits. You must compile with default features. For example:
+//!
+//! ```rust
+//! use std::io::Cursor;
+//! use scroll::IOread;
+//! let bytes_ = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,];
+//! let mut bytes = Cursor::new(bytes_);
+//!
+//! // this will bump the cursor's Seek
+//! let foo = bytes.ioread::<u64>().unwrap();
+//! // ..ditto
+//! let bar = bytes.ioread::<u32>().unwrap();
+//! ```
+//!
+//! Similarly, we can write to anything that implements `std::io::Write` quite naturally:
+//!
+//! ```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]);
+//! ```
+//!
+//! # Advanced Uses
+//!
+//! Scroll is designed to be highly configurable - it allows you to implement various context (`Ctx`) sensitive traits, which then grants the implementor _automatic_ uses of the `Pread` and/or `Pwrite` traits.
+//!
+//! For example, suppose we have a datatype and we want to specify how to parse or serialize this datatype out of some arbitrary
+//! byte buffer. In order to do this, we need to provide a [TryFromCtx](trait.TryFromCtx.html) impl for our datatype.
+//!
+//! In particular, if we do this for the `[u8]` target, using the convention `(usize, YourCtx)`, you will automatically get access to
+//! calling `pread_with::<YourDatatype>` on arrays of bytes.
+//!
+//! ```rust
+//! use scroll::{self, ctx, Pread, BE, Endian};
+//!
+//! struct Data<'a> {
+//! name: &'a str,
+//! id: u32,
+//! }
+//!
+//! // note the lifetime specified here
+//! impl<'a> ctx::TryFromCtx<'a, Endian> for Data<'a> {
+//! type Error = scroll::Error;
+//! // and the lifetime annotation on `&'a [u8]` here
+//! fn try_from_ctx (src: &'a [u8], endian: Endian)
+//! -> Result<(Self, usize), Self::Error> {
+//! let offset = &mut 0;
+//! let name = src.gread::<&str>(offset)?;
+//! let id = src.gread_with(offset, endian)?;
+//! Ok((Data { name: name, id: id }, *offset))
+//! }
+//! }
+//!
+//! let bytes = b"UserName\x00\x01\x02\x03\x04";
+//! let data = bytes.pread_with::<Data>(0, BE).unwrap();
+//! assert_eq!(data.id, 0x01020304);
+//! assert_eq!(data.name.to_string(), "UserName".to_string());
+//! ```
+//!
+//! Please see the [Pread documentation examples](trait.Pread.html#implementing-your-own-reader)
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+#[cfg(feature = "derive")]
+#[allow(unused_imports)]
+pub use scroll_derive::{Pread, Pwrite, SizeWith, IOread, IOwrite};
+
+#[cfg(feature = "std")]
+extern crate core;
+
+pub mod ctx;
+mod pread;
+mod pwrite;
+mod greater;
+mod error;
+mod endian;
+mod leb128;
+#[cfg(feature = "std")]
+mod lesser;
+
+pub use crate::endian::*;
+pub use crate::pread::*;
+pub use crate::pwrite::*;
+pub use crate::greater::*;
+pub use crate::error::*;
+pub use crate::leb128::*;
+#[cfg(feature = "std")]
+pub use crate::lesser::*;
+
+#[doc(hidden)]
+pub mod export {
+ pub use ::core::result;
+ pub use ::core::mem;
+}
+
+#[cfg(test)]
+mod tests {
+ #[allow(overflowing_literals)]
+ use super::{LE};
+
+ #[test]
+ fn test_measure_with_bytes() {
+ use super::ctx::MeasureWith;
+ let bytes: [u8; 4] = [0xef, 0xbe, 0xad, 0xde];
+ assert_eq!(bytes.measure_with(&()), 4);
+ }
+
+ #[test]
+ fn test_measurable() {
+ use super::ctx::SizeWith;
+ assert_eq!(8, u64::size_with(&LE));
+ }
+
+ //////////////////////////////////////////////////////////////
+ // begin pread_with
+ //////////////////////////////////////////////////////////////
+
+ macro_rules! pwrite_test {
+ ($write:ident, $read:ident, $deadbeef:expr) => {
+ #[test]
+ fn $write() {
+ use super::{Pwrite, Pread, BE};
+ let mut bytes: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
+ let b = &mut bytes[..];
+ b.pwrite_with::<$read>($deadbeef, 0, LE).unwrap();
+ assert_eq!(b.pread_with::<$read>(0, LE).unwrap(), $deadbeef);
+ b.pwrite_with::<$read>($deadbeef, 0, BE).unwrap();
+ assert_eq!(b.pread_with::<$read>(0, BE).unwrap(), $deadbeef);
+ }
+ }
+ }
+
+ pwrite_test!(pwrite_and_pread_roundtrip_u16, u16, 0xbeef);
+ pwrite_test!(pwrite_and_pread_roundtrip_i16, i16, 0x7eef);
+ pwrite_test!(pwrite_and_pread_roundtrip_u32, u32, 0xbeefbeef);
+ pwrite_test!(pwrite_and_pread_roundtrip_i32, i32, 0x7eefbeef);
+ pwrite_test!(pwrite_and_pread_roundtrip_u64, u64, 0xbeefbeef7eef7eef);
+ pwrite_test!(pwrite_and_pread_roundtrip_i64, i64, 0x7eefbeef7eef7eef);
+
+ #[test]
+ fn pread_with_be() {
+ use super::{Pread};
+ let bytes: [u8; 2] = [0x7e, 0xef];
+ let b = &bytes[..];
+ let byte: u16 = b.pread_with(0, super::BE).unwrap();
+ assert_eq!(0x7eef, byte);
+ let bytes: [u8; 2] = [0xde, 0xad];
+ let dead: u16 = bytes.pread_with(0, super::BE).unwrap();
+ assert_eq!(0xdead, dead);
+ }
+
+ #[test]
+ fn pread() {
+ use super::{Pread};
+ let bytes: [u8; 2] = [0x7e, 0xef];
+ let b = &bytes[..];
+ let byte: u16 = b.pread(0).unwrap();
+ #[cfg(target_endian = "little")]
+ assert_eq!(0xef7e, byte);
+ #[cfg(target_endian = "big")]
+ assert_eq!(0x7eef, byte);
+ }
+
+ #[test]
+ fn pread_slice() {
+ use super::{Pread};
+ use super::ctx::StrCtx;
+ let bytes: [u8; 2] = [0x7e, 0xef];
+ let b = &bytes[..];
+ let iserr: Result<&str, _> = b.pread_with(0, StrCtx::Length(3));
+ assert!(iserr.is_err());
+ // let bytes2: &[u8] = b.pread_with(0, 2).unwrap();
+ // assert_eq!(bytes2.len(), bytes[..].len());
+ // for i in 0..bytes2.len() {
+ // assert_eq!(bytes2[i], bytes[i])
+ // }
+ }
+
+ #[test]
+ fn pread_str() {
+ use super::Pread;
+ use super::ctx::*;
+ let bytes: [u8; 2] = [0x2e, 0x0];
+ let b = &bytes[..];
+ let s: &str = b.pread(0).unwrap();
+ println!("str: {}", s);
+ assert_eq!(s.len(), bytes[..].len() - 1);
+ let bytes: &[u8] = b"hello, world!\0some_other_things";
+ let hello_world: &str = bytes.pread_with(0, StrCtx::Delimiter(NULL)).unwrap();
+ println!("{:?}", &hello_world);
+ assert_eq!(hello_world.len(), 13);
+ let hello: &str = bytes.pread_with(0, StrCtx::Delimiter(SPACE)).unwrap();
+ println!("{:?}", &hello);
+ assert_eq!(hello.len(), 6);
+ // this could result in underflow so we just try it
+ let _error = bytes.pread_with::<&str>(6, StrCtx::Delimiter(SPACE));
+ let error = bytes.pread_with::<&str>(7, StrCtx::Delimiter(SPACE));
+ println!("{:?}", &error);
+ assert!(error.is_ok());
+ }
+
+ #[test]
+ fn pread_str_weird() {
+ use super::Pread;
+ use super::ctx::*;
+ let bytes: &[u8] = b"";
+ let hello_world = bytes.pread_with::<&str>(0, StrCtx::Delimiter(NULL));
+ println!("1 {:?}", &hello_world);
+ assert_eq!(hello_world.is_err(), true);
+ let error = bytes.pread_with::<&str>(7, StrCtx::Delimiter(SPACE));
+ println!("2 {:?}", &error);
+ assert!(error.is_err());
+ let bytes: &[u8] = b"\0";
+ let null = bytes.pread::<&str>(0).unwrap();
+ println!("3 {:?}", &null);
+ assert_eq!(null.len(), 0);
+ }
+
+ #[test]
+ fn pwrite_str_and_bytes() {
+ use super::{Pread, Pwrite};
+ use super::ctx::*;
+ let astring: &str = "lol hello_world lal\0ala imabytes";
+ let mut buffer = [0u8; 33];
+ buffer.pwrite(astring, 0).unwrap();
+ {
+ let hello_world = buffer.pread_with::<&str>(4, StrCtx::Delimiter(SPACE)).unwrap();
+ assert_eq!(hello_world, "hello_world");
+ }
+ let bytes: &[u8] = b"more\0bytes";
+ buffer.pwrite(bytes, 0).unwrap();
+ let more = bytes.pread_with::<&str>(0, StrCtx::Delimiter(NULL)).unwrap();
+ assert_eq!(more, "more");
+ let bytes = bytes.pread_with::<&str>(more.len() + 1, StrCtx::Delimiter(NULL)).unwrap();
+ assert_eq!(bytes, "bytes");
+ }
+
+ use std::error;
+ use std::fmt::{self, Display};
+
+ #[derive(Debug)]
+ pub struct ExternalError {}
+
+ impl Display for ExternalError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "ExternalError")
+ }
+ }
+
+ impl error::Error for ExternalError {
+ fn description(&self) -> &str {
+ "ExternalError"
+ }
+ fn cause(&self) -> Option<&dyn error::Error> { None}
+ }
+
+ impl From<super::Error> for ExternalError {
+ fn from(err: super::Error) -> Self {
+ //use super::Error::*;
+ match err {
+ _ => ExternalError{},
+ }
+ }
+ }
+
+ #[derive(Debug, PartialEq, Eq)]
+ pub struct Foo(u16);
+
+ impl super::ctx::TryIntoCtx<super::Endian> for Foo {
+ type Error = ExternalError;
+ fn try_into_ctx(self, this: &mut [u8], le: super::Endian) -> Result<usize, Self::Error> {
+ use super::Pwrite;
+ if this.len() < 2 { return Err((ExternalError {}).into()) }
+ this.pwrite_with(self.0, 0, le)?;
+ Ok(2)
+ }
+ }
+
+ impl<'a> super::ctx::TryFromCtx<'a, super::Endian> for Foo {
+ type Error = ExternalError;
+ fn try_from_ctx(this: &'a [u8], le: super::Endian) -> Result<(Self, usize), Self::Error> {
+ use super::Pread;
+ if this.len() > 2 { return Err((ExternalError {}).into()) }
+ let n = this.pread_with(0, le)?;
+ Ok((Foo(n), 2))
+ }
+ }
+
+ #[test]
+ fn pread_with_iter_bytes() {
+ use super::{Pread};
+ let mut bytes_to: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
+ let bytes_from: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
+ let bytes_to = &mut bytes_to[..];
+ let bytes_from = &bytes_from[..];
+ for i in 0..bytes_from.len() {
+ bytes_to[i] = bytes_from.pread(i).unwrap();
+ }
+ assert_eq!(bytes_to, bytes_from);
+ }
+
+ //////////////////////////////////////////////////////////////
+ // end pread_with
+ //////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////
+ // begin gread_with
+ //////////////////////////////////////////////////////////////
+ macro_rules! g_test {
+ ($read:ident, $deadbeef:expr, $typ:ty) => {
+ #[test]
+ fn $read() {
+ use super::Pread;
+ let bytes: [u8; 8] = [0xf, 0xe, 0xe, 0xb, 0xd, 0xa, 0xe, 0xd];
+ let mut offset = 0;
+ let deadbeef: $typ = bytes.gread_with(&mut offset, LE).unwrap();
+ assert_eq!(deadbeef, $deadbeef as $typ);
+ assert_eq!(offset, ::std::mem::size_of::<$typ>());
+ }
+ }
+ }
+
+ g_test!(simple_gread_u16, 0xe0f, u16);
+ g_test!(simple_gread_u32, 0xb0e0e0f, u32);
+ g_test!(simple_gread_u64, 0xd0e0a0d0b0e0e0f, u64);
+ g_test!(simple_gread_i64, 940700423303335439, i64);
+
+ macro_rules! simple_float_test {
+ ($read:ident, $deadbeef:expr, $typ:ty) => {
+ #[test]
+ fn $read() {
+ use super::Pread;
+ let bytes: [u8; 8] = [0u8, 0, 0, 0, 0, 0, 224, 63];
+ let mut offset = 0;
+ let deadbeef: $typ = bytes.gread_with(&mut offset, LE).unwrap();
+ assert_eq!(deadbeef, $deadbeef as $typ);
+ assert_eq!(offset, ::std::mem::size_of::<$typ>());
+ }
+ };
+ }
+
+ simple_float_test!(gread_f32, 0.0, f32);
+ simple_float_test!(gread_f64, 0.5, f64);
+
+ macro_rules! g_read_write_test {
+ ($read:ident, $val:expr, $typ:ty) => {
+ #[test]
+ fn $read() {
+ use super::{LE, BE, Pread, Pwrite};
+ let mut buffer = [0u8; 16];
+ let offset = &mut 0;
+ buffer.gwrite_with($val.clone(), offset, LE).unwrap();
+ let o2 = &mut 0;
+ let val: $typ = buffer.gread_with(o2, LE).unwrap();
+ assert_eq!(val, $val);
+ assert_eq!(*offset, ::std::mem::size_of::<$typ>());
+ assert_eq!(*o2, ::std::mem::size_of::<$typ>());
+ assert_eq!(*o2, *offset);
+ buffer.gwrite_with($val.clone(), offset, BE).unwrap();
+ let val: $typ = buffer.gread_with(o2, BE).unwrap();
+ assert_eq!(val, $val);
+ }
+ };
+ }
+
+ g_read_write_test!(gread_gwrite_f64_1, 0.25f64, f64);
+ g_read_write_test!(gread_gwrite_f64_2, 0.5f64, f64);
+ g_read_write_test!(gread_gwrite_f64_3, 0.064, f64);
+
+ g_read_write_test!(gread_gwrite_f32_1, 0.25f32, f32);
+ g_read_write_test!(gread_gwrite_f32_2, 0.5f32, f32);
+ g_read_write_test!(gread_gwrite_f32_3, 0.0f32, f32);
+
+ g_read_write_test!(gread_gwrite_i64_1, 0i64, i64);
+ g_read_write_test!(gread_gwrite_i64_2, -1213213211111i64, i64);
+ g_read_write_test!(gread_gwrite_i64_3, -3000i64, i64);
+
+ g_read_write_test!(gread_gwrite_i32_1, 0i32, i32);
+ g_read_write_test!(gread_gwrite_i32_2, -1213213232, i32);
+ g_read_write_test!(gread_gwrite_i32_3, -3000i32, i32);
+
+ // useful for ferreting out problems with impls
+ #[test]
+ fn gread_with_iter_bytes() {
+ use super::{Pread};
+ let mut bytes_to: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
+ let bytes_from: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
+ let bytes_to = &mut bytes_to[..];
+ let bytes_from = &bytes_from[..];
+ let mut offset = &mut 0;
+ for i in 0..bytes_from.len() {
+ bytes_to[i] = bytes_from.gread(&mut offset).unwrap();
+ }
+ assert_eq!(bytes_to, bytes_from);
+ assert_eq!(*offset, bytes_to.len());
+ }
+
+ #[test]
+ fn gread_inout() {
+ use super::{Pread};
+ let mut bytes_to: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
+ let bytes_from: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
+ let bytes = &bytes_from[..];
+ let offset = &mut 0;
+ bytes.gread_inout(offset, &mut bytes_to[..]).unwrap();
+ assert_eq!(bytes_to, bytes_from);
+ assert_eq!(*offset, bytes_to.len());
+ }
+
+ #[test]
+ fn gread_with_byte() {
+ use super::{Pread};
+ let bytes: [u8; 1] = [0x7f];
+ let b = &bytes[..];
+ let offset = &mut 0;
+ let byte: u8 = b.gread(offset).unwrap();
+ assert_eq!(0x7f, byte);
+ assert_eq!(*offset, 1);
+ }
+
+ #[test]
+ fn gread_slice() {
+ use super::{Pread};
+ use super::ctx::{StrCtx};
+ let bytes: [u8; 2] = [0x7e, 0xef];
+ let b = &bytes[..];
+ let offset = &mut 0;
+ let res = b.gread_with::<&str>(offset, StrCtx::Length(3));
+ assert!(res.is_err());
+ *offset = 0;
+ let astring: [u8; 3] = [0x45, 042, 0x44];
+ let string = astring.gread_with::<&str>(offset, StrCtx::Length(2));
+ match &string {
+ &Ok(_) => {},
+ &Err(ref err) => {println!("{}", &err); panic!();}
+ }
+ assert_eq!(string.unwrap(), "E*");
+ *offset = 0;
+ let bytes2: &[u8] = b.gread_with(offset, 2).unwrap();
+ assert_eq!(*offset, 2);
+ assert_eq!(bytes2.len(), bytes[..].len());
+ for i in 0..bytes2.len() {
+ assert_eq!(bytes2[i], bytes[i])
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////
+ // end gread_with
+ /////////////////////////////////////////////////////////////////
+}
diff --git a/third_party/rust/scroll/src/pread.rs b/third_party/rust/scroll/src/pread.rs
new file mode 100644
index 0000000000..64f85d4476
--- /dev/null
+++ b/third_party/rust/scroll/src/pread.rs
@@ -0,0 +1,203 @@
+use core::result;
+use core::ops::{Index, RangeFrom};
+
+use crate::ctx::{TryFromCtx, MeasureWith};
+use crate::error;
+
+/// A very generic, contextual pread interface in Rust. Allows completely parallelized reads, as `Self` is immutable
+///
+/// Don't be scared! The `Pread` definition _is_ terrifying, but it is definitely tractable. Essentially, `E` is the error, `Ctx` the parsing context, `I` is the indexing type, `TryCtx` is the "offset + ctx" Context given to the `TryFromCtx` trait bounds, and `SliceCtx` is the "offset + size + ctx" context given to the `TryRefFromCtx` trait bound.
+///
+/// # Implementing Your Own Reader
+/// If you want to implement your own reader for a type `Foo` from some kind of buffer (say `[u8]`), then you need to implement [TryFromCtx](trait.TryFromCtx.html)
+///
+/// ```rust
+/// use scroll::{self, ctx, Pread};
+/// #[derive(Debug, PartialEq, Eq)]
+/// pub struct Foo(u16);
+///
+/// impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Foo {
+/// type Error = scroll::Error;
+/// fn try_from_ctx(this: &'a [u8], le: scroll::Endian) -> Result<(Self, usize), Self::Error> {
+/// if this.len() < 2 { return Err((scroll::Error::Custom("whatever".to_string())).into()) }
+/// let n = this.pread_with(0, le)?;
+/// Ok((Foo(n), 2))
+/// }
+/// }
+///
+/// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
+/// let foo = bytes.pread_with::<Foo>(0, scroll::LE).unwrap();
+/// assert_eq!(Foo(0xadde), foo);
+///
+/// let foo2 = bytes.pread_with::<Foo>(0, scroll::BE).unwrap();
+/// assert_eq!(Foo(0xdeadu16), foo2);
+/// ```
+///
+/// # Advanced: Using Your Own Error in `TryFromCtx`
+/// ```rust
+/// use scroll::{self, ctx, Pread};
+/// use std::error;
+/// use std::fmt::{self, Display};
+/// // make some kind of normal error which also can transform a scroll error ideally (quick_error, error_chain allow this automatically nowadays)
+/// #[derive(Debug)]
+/// pub struct ExternalError {}
+///
+/// impl Display for ExternalError {
+/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+/// write!(fmt, "ExternalError")
+/// }
+/// }
+///
+/// impl error::Error for ExternalError {
+/// fn description(&self) -> &str {
+/// "ExternalError"
+/// }
+/// fn cause(&self) -> Option<&error::Error> { None}
+/// }
+///
+/// impl From<scroll::Error> for ExternalError {
+/// fn from(err: scroll::Error) -> Self {
+/// match err {
+/// _ => ExternalError{},
+/// }
+/// }
+/// }
+/// #[derive(Debug, PartialEq, Eq)]
+/// pub struct Foo(u16);
+///
+/// impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Foo {
+/// type Error = ExternalError;
+/// fn try_from_ctx(this: &'a [u8], le: scroll::Endian) -> Result<(Self, usize), Self::Error> {
+/// if this.len() <= 2 { return Err((ExternalError {}).into()) }
+/// let offset = &mut 0;
+/// let n = this.gread_with(offset, le)?;
+/// Ok((Foo(n), *offset))
+/// }
+/// }
+///
+/// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
+/// let foo: Result<Foo, ExternalError> = bytes.pread(0);
+/// ```
+pub trait Pread<Ctx, E> : Index<usize> + Index<RangeFrom<usize>> + MeasureWith<Ctx>
+ where
+ Ctx: Copy,
+ E: From<error::Error>,
+{
+ #[inline]
+ /// Reads a value from `self` at `offset` with a default `Ctx`. For the primitive numeric values, this will read at the machine's endianness.
+ /// # Example
+ /// ```rust
+ /// use scroll::Pread;
+ /// let bytes = [0x7fu8; 0x01];
+ /// let byte = bytes.pread::<u8>(0).unwrap();
+ fn pread<'a, N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&'a self, offset: usize) -> result::Result<N, E> where <Self as Index<RangeFrom<usize>>>::Output: 'a, Ctx: Default {
+ self.pread_with(offset, Ctx::default())
+ }
+ #[inline]
+ /// Reads a value from `self` at `offset` with the given `ctx`
+ /// # Example
+ /// ```rust
+ /// use scroll::Pread;
+ /// let bytes: [u8; 2] = [0xde, 0xad];
+ /// let dead: u16 = bytes.pread_with(0, scroll::BE).unwrap();
+ /// assert_eq!(dead, 0xdeadu16);
+ fn pread_with<'a, N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&'a self, offset: usize, ctx: Ctx) -> result::Result<N, E> where <Self as Index<RangeFrom<usize>>>::Output: 'a {
+ let len = self.measure_with(&ctx);
+ if offset >= len {
+ return Err(error::Error::BadOffset(offset).into())
+ }
+ N::try_from_ctx(&self[offset..], ctx).and_then(|(n, _)| Ok(n))
+ }
+ #[inline]
+ /// Reads a value from `self` at `offset` with a default `Ctx`. For the primitive numeric values, this will read at the machine's endianness. Updates the offset
+ /// # Example
+ /// ```rust
+ /// use scroll::Pread;
+ /// let offset = &mut 0;
+ /// let bytes = [0x7fu8; 0x01];
+ /// let byte = bytes.gread::<u8>(offset).unwrap();
+ /// assert_eq!(*offset, 1);
+ fn gread<'a, N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&'a self, offset: &mut usize) -> result::Result<N, E> where Ctx: Default, <Self as Index<RangeFrom<usize>>>::Output: 'a {
+ let ctx = Ctx::default();
+ self.gread_with(offset, ctx)
+ }
+ /// Reads a value from `self` at `offset` with the given `ctx`, and updates the offset.
+ /// # Example
+ /// ```rust
+ /// use scroll::Pread;
+ /// let offset = &mut 0;
+ /// let bytes: [u8; 2] = [0xde, 0xad];
+ /// let dead: u16 = bytes.gread_with(offset, scroll::BE).unwrap();
+ /// assert_eq!(dead, 0xdeadu16);
+ /// assert_eq!(*offset, 2);
+ #[inline]
+ fn gread_with<'a, N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>
+ (&'a self, offset: &mut usize, ctx: Ctx) ->
+ result::Result<N, E>
+ where <Self as Index<RangeFrom<usize>>>::Output: 'a
+ {
+ let o = *offset;
+ // self.pread_with(o, ctx).and_then(|(n, size)| {
+ // *offset += size;
+ // Ok(n)
+ // })
+ let len = self.measure_with(&ctx);
+ if o >= len {
+ return Err(error::Error::BadOffset(o).into())
+ }
+ N::try_from_ctx(&self[o..], ctx).and_then(|(n, size)| {
+ *offset += size;
+ Ok(n)
+ })
+ }
+
+ /// Trys to write `inout.len()` `N`s into `inout` from `Self` starting at `offset`, using the default context for `N`, and updates the offset.
+ /// # Example
+ /// ```rust
+ /// use scroll::Pread;
+ /// let mut bytes: Vec<u8> = vec![0, 0];
+ /// let offset = &mut 0;
+ /// let bytes_from: [u8; 2] = [0x48, 0x49];
+ /// bytes_from.gread_inout(offset, &mut bytes).unwrap();
+ /// assert_eq!(&bytes, &bytes_from);
+ /// assert_eq!(*offset, 2);
+ #[inline]
+ fn gread_inout<'a, N>(&'a self, offset: &mut usize, inout: &mut [N]) -> result::Result<(), E>
+ where
+ N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>,
+ Ctx: Default,
+ <Self as Index<RangeFrom<usize>>>::Output: 'a
+ {
+ for i in inout.iter_mut() {
+ *i = self.gread(offset)?;
+ }
+ Ok(())
+ }
+
+ /// Trys to write `inout.len()` `N`s into `inout` from `Self` starting at `offset`, using the context `ctx`
+ /// # Example
+ /// ```rust
+ /// use scroll::{ctx, LE, Pread};
+ /// let mut bytes: Vec<u8> = vec![0, 0];
+ /// let offset = &mut 0;
+ /// let bytes_from: [u8; 2] = [0x48, 0x49];
+ /// bytes_from.gread_inout_with(offset, &mut bytes, LE).unwrap();
+ /// assert_eq!(&bytes, &bytes_from);
+ /// assert_eq!(*offset, 2);
+ #[inline]
+ fn gread_inout_with<'a, N>(&'a self, offset: &mut usize, inout: &mut [N], ctx: Ctx) -> result::Result<(), E>
+ where
+ N: TryFromCtx<'a, Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>,
+ <Self as Index<RangeFrom<usize>>>::Output: 'a
+ {
+ for i in inout.iter_mut() {
+ *i = self.gread_with(offset, ctx)?;
+ }
+ Ok(())
+ }
+}
+
+impl<Ctx: Copy,
+ E: From<error::Error>,
+ R: ?Sized + Index<usize> + Index<RangeFrom<usize>> + MeasureWith<Ctx>>
+ Pread<Ctx, E> for R {}
diff --git a/third_party/rust/scroll/src/pwrite.rs b/third_party/rust/scroll/src/pwrite.rs
new file mode 100644
index 0000000000..08aa82913c
--- /dev/null
+++ b/third_party/rust/scroll/src/pwrite.rs
@@ -0,0 +1,79 @@
+use core::result;
+use core::ops::{Index, IndexMut, RangeFrom};
+
+use crate::ctx::{TryIntoCtx, MeasureWith};
+use crate::error;
+
+/// Writes into `Self` at an offset of type `I` using a `Ctx`
+///
+/// To implement writing into an arbitrary byte buffer, implement `TryIntoCtx`
+/// # Example
+/// ```rust
+/// use scroll::{self, ctx, LE, Endian, Pwrite};
+/// #[derive(Debug, PartialEq, Eq)]
+/// pub struct Foo(u16);
+///
+/// // this will use the default `DefaultCtx = scroll::Endian` and `I = usize`...
+/// impl ctx::TryIntoCtx<Endian> for Foo {
+/// // you can use your own error here too, but you will then need to specify it in fn generic parameters
+/// type Error = scroll::Error;
+/// // you can write using your own context too... see `leb128.rs`
+/// fn try_into_ctx(self, this: &mut [u8], le: Endian) -> Result<usize, Self::Error> {
+/// if this.len() < 2 { return Err((scroll::Error::Custom("whatever".to_string())).into()) }
+/// this.pwrite_with(self.0, 0, le)?;
+/// Ok(2)
+/// }
+/// }
+/// // now we can write a `Foo` into some buffer (in this case, a byte buffer, because that's what we implemented it for above)
+///
+/// let mut bytes: [u8; 4] = [0, 0, 0, 0];
+/// bytes.pwrite_with(Foo(0x7f), 1, LE).unwrap();
+///
+pub trait Pwrite<Ctx, E> : Index<usize> + IndexMut<RangeFrom<usize>> + MeasureWith<Ctx>
+ where
+ Ctx: Copy,
+ E: From<error::Error>,
+{
+ fn pwrite<N: TryIntoCtx<Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&mut self, n: N, offset: usize) -> result::Result<usize, E> where Ctx: Default {
+ self.pwrite_with(n, offset, Ctx::default())
+ }
+ /// Write `N` at offset `I` with context `Ctx`
+ /// # Example
+ /// ```
+ /// use scroll::{Pwrite, Pread, LE};
+ /// let mut bytes: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
+ /// bytes.pwrite_with::<u32>(0xbeefbeef, 0, LE).unwrap();
+ /// assert_eq!(bytes.pread_with::<u32>(0, LE).unwrap(), 0xbeefbeef);
+ fn pwrite_with<N: TryIntoCtx<Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&mut self, n: N, offset: usize, ctx: Ctx) -> result::Result<usize, E> {
+ let len = self.measure_with(&ctx);
+ if offset >= len {
+ return Err(error::Error::BadOffset(offset).into())
+ }
+ let dst = &mut self[offset..];
+ n.try_into_ctx(dst, ctx)
+ }
+ /// Write `n` into `self` at `offset`, with a default `Ctx`. Updates the offset.
+ #[inline]
+ fn gwrite<N: TryIntoCtx<Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&mut self, n: N, offset: &mut usize) -> result::Result<usize, E> where
+ Ctx: Default {
+ let ctx = Ctx::default();
+ self.gwrite_with(n, offset, ctx)
+ }
+ /// Write `n` into `self` at `offset`, with the `ctx`. Updates the offset.
+ #[inline]
+ fn gwrite_with<N: TryIntoCtx<Ctx, <Self as Index<RangeFrom<usize>>>::Output, Error = E>>(&mut self, n: N, offset: &mut usize, ctx: Ctx) -> result::Result<usize, E> {
+ let o = *offset;
+ match self.pwrite_with(n, o, ctx) {
+ Ok(size) => {
+ *offset += size;
+ Ok(size)
+ },
+ err => err
+ }
+ }
+}
+
+impl<Ctx: Copy,
+ E: From<error::Error>,
+ R: ?Sized + Index<usize> + IndexMut<RangeFrom<usize>> + MeasureWith<Ctx>>
+ Pwrite<Ctx, E> for R {}