summaryrefslogtreecommitdiffstats
path: root/third_party/rust/scroll/src/ctx.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/scroll/src/ctx.rs107
1 files changed, 74 insertions, 33 deletions
diff --git a/third_party/rust/scroll/src/ctx.rs b/third_party/rust/scroll/src/ctx.rs
index 1f982b82fa..e24d2dc506 100644
--- a/third_party/rust/scroll/src/ctx.rs
+++ b/third_party/rust/scroll/src/ctx.rs
@@ -180,17 +180,14 @@
//! }
//! ```
-use core::mem::size_of;
-use core::mem::transmute;
+use core::mem::{size_of, MaybeUninit};
use core::ptr::copy_nonoverlapping;
-use core::result;
-use core::str;
-
+use core::{result, str};
#[cfg(feature = "std")]
use std::ffi::{CStr, CString};
use crate::endian::Endian;
-use crate::error;
+use crate::{error, Pread, Pwrite};
/// A trait for measuring how large something is; for a byte sequence, it will be its length.
pub trait MeasureWith<Ctx> {
@@ -240,18 +237,14 @@ impl Default for StrCtx {
impl StrCtx {
pub fn len(&self) -> usize {
- match *self {
+ match self {
StrCtx::Delimiter(_) | StrCtx::DelimiterUntil(_, _) => 1,
StrCtx::Length(_) => 0,
}
}
pub fn is_empty(&self) -> bool {
- if let StrCtx::Length(_) = *self {
- true
- } else {
- false
- }
+ matches!(self, StrCtx::Length(_))
}
}
@@ -267,6 +260,7 @@ pub trait FromCtx<Ctx: Copy = (), This: ?Sized = [u8]> {
/// `[u8]`), then you need to implement this trait
///
/// ```rust
+/// ##[cfg(feature = "std")] {
/// use scroll::{self, ctx, Pread};
/// #[derive(Debug, PartialEq, Eq)]
/// pub struct Foo(u16);
@@ -286,6 +280,7 @@ pub trait FromCtx<Ctx: Copy = (), This: ?Sized = [u8]> {
///
/// let foo2 = bytes.pread_with::<Foo>(0, scroll::BE).unwrap();
/// assert_eq!(Foo(0xdeadu16), foo2);
+/// # }
/// ```
///
/// # Advanced: Using Your Own Error in `TryFromCtx`
@@ -350,6 +345,7 @@ pub trait IntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
/// To implement writing into an arbitrary byte buffer, implement `TryIntoCtx`
/// # Example
/// ```rust
+/// ##[cfg(feature = "std")] {
/// use scroll::{self, ctx, LE, Endian, Pwrite};
/// #[derive(Debug, PartialEq, Eq)]
/// pub struct Foo(u16);
@@ -369,6 +365,7 @@ pub trait IntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
///
/// let mut bytes: [u8; 4] = [0, 0, 0, 0];
/// bytes.pwrite_with(Foo(0x7f), 1, LE).unwrap();
+/// # }
/// ```
pub trait TryIntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
type Error;
@@ -403,13 +400,14 @@ macro_rules! signed_to_unsigned {
macro_rules! write_into {
($typ:ty, $size:expr, $n:expr, $dst:expr, $endian:expr) => {{
+ assert!($dst.len() >= $size);
+ let bytes = if $endian.is_little() {
+ $n.to_le()
+ } else {
+ $n.to_be()
+ }
+ .to_ne_bytes();
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);
}
}};
@@ -570,12 +568,12 @@ macro_rules! from_ctx_float_impl {
&mut data as *mut signed_to_unsigned!($typ) as *mut u8,
$size,
);
- transmute(if le.is_little() {
- data.to_le()
- } else {
- data.to_be()
- })
}
+ $typ::from_bits(if le.is_little() {
+ data.to_le()
+ } else {
+ data.to_be()
+ })
}
}
impl<'a> TryFromCtx<'a, Endian> for $typ
@@ -621,13 +619,7 @@ macro_rules! into_ctx_float_impl {
#[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
- );
+ write_into!(signed_to_unsigned!($typ), $size, self.to_bits(), dst, le);
}
}
impl<'a> IntoCtx<Endian> for &'a $typ {
@@ -725,7 +717,7 @@ impl<'a> TryIntoCtx for &'a [u8] {
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())
+ // return Err(error::Error::BadOffset(format!("requested operation has negative casts: src len: {src_len} dst len: {dst_len} offset: {offset}")).into())
// }
if src_len > dst_len {
Err(error::Error::TooBig {
@@ -789,6 +781,56 @@ impl<'a> TryFromCtx<'a, usize> for &'a [u8] {
}
}
+impl<'a, Ctx: Copy, T: TryFromCtx<'a, Ctx, Error = error::Error>, const N: usize>
+ TryFromCtx<'a, Ctx> for [T; N]
+{
+ type Error = error::Error;
+ fn try_from_ctx(src: &'a [u8], ctx: Ctx) -> Result<(Self, usize), Self::Error> {
+ let mut offset = 0;
+
+ let mut buf: [MaybeUninit<T>; N] = core::array::from_fn(|_| MaybeUninit::uninit());
+
+ let mut error_ctx = None;
+ for (idx, element) in buf.iter_mut().enumerate() {
+ match src.gread_with::<T>(&mut offset, ctx) {
+ Ok(val) => {
+ *element = MaybeUninit::new(val);
+ }
+ Err(e) => {
+ error_ctx = Some((e, idx));
+ break;
+ }
+ }
+ }
+ if let Some((e, idx)) = error_ctx {
+ for element in &mut buf[0..idx].iter_mut() {
+ // SAFETY: Any element upto idx must have already been initialized, since
+ // we iterate until we encounter an error.
+ unsafe {
+ element.assume_init_drop();
+ }
+ }
+ Err(e)
+ } else {
+ // SAFETY: we initialized each element above by preading them out, correctness
+ // of the initialized element is guaranted by pread itself
+ Ok((buf.map(|element| unsafe { element.assume_init() }), offset))
+ }
+ }
+}
+impl<Ctx: Copy, T: TryIntoCtx<Ctx, Error = error::Error>, const N: usize> TryIntoCtx<Ctx>
+ for [T; N]
+{
+ type Error = error::Error;
+ fn try_into_ctx(self, buf: &mut [u8], ctx: Ctx) -> Result<usize, Self::Error> {
+ let mut offset = 0;
+ for element in self {
+ buf.gwrite_with(element, &mut offset, ctx)?;
+ }
+ Ok(offset)
+ }
+}
+
#[cfg(feature = "std")]
impl<'a> TryFromCtx<'a> for &'a CStr {
type Error = error::Error;
@@ -863,11 +905,11 @@ impl TryIntoCtx for CString {
// }
#[cfg(test)]
+#[cfg(feature = "std")]
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();
@@ -879,7 +921,6 @@ mod tests {
}
#[test]
- #[cfg(feature = "std")]
fn round_trip_a_c_str() {
let src = CString::new("Hello World").unwrap();
let src = src.as_c_str();