From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- third_party/rust/scroll/src/ctx.rs | 107 +++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 33 deletions(-) (limited to 'third_party/rust/scroll/src/ctx.rs') 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 { @@ -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 { /// `[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 { /// /// let foo2 = bytes.pread_with::(0, scroll::BE).unwrap(); /// assert_eq!(Foo(0xdeadu16), foo2); +/// # } /// ``` /// /// # Advanced: Using Your Own Error in `TryFromCtx` @@ -350,6 +345,7 @@ pub trait IntoCtx: 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: Sized { /// /// let mut bytes: [u8; 4] = [0, 0, 0, 0]; /// bytes.pwrite_with(Foo(0x7f), 1, LE).unwrap(); +/// # } /// ``` pub trait TryIntoCtx: 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 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; N] = core::array::from_fn(|_| MaybeUninit::uninit()); + + let mut error_ctx = None; + for (idx, element) in buf.iter_mut().enumerate() { + match src.gread_with::(&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, const N: usize> TryIntoCtx + for [T; N] +{ + type Error = error::Error; + fn try_into_ctx(self, buf: &mut [u8], ctx: Ctx) -> Result { + 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(); -- cgit v1.2.3