From dcc8c4e8e1c25c8d33417c488e868cab9daff889 Mon Sep 17 00:00:00 2001 From: Kaido Kert Date: Sun, 22 Sep 2024 20:36:19 -0700 Subject: [PATCH] Working design --- Cargo.toml | 3 +- src/fixeduint.rs | 103 ++++++++++++++++++++++++++--------- src/machineword.rs | 133 --------------------------------------------- 3 files changed, 78 insertions(+), 161 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f3d9054..496bcd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ default-features = false [dependencies.zeroize] version = "1.8.1" +optional = true [profile.dev] opt-level = 0 @@ -39,4 +40,4 @@ codegen-units = 16 [features] use-unsafe = [] -default = ["use-unsafe"] +default = [] diff --git a/src/fixeduint.rs b/src/fixeduint.rs index b0d8b74..0501444 100644 --- a/src/fixeduint.rs +++ b/src/fixeduint.rs @@ -13,19 +13,21 @@ // limitations under the License. use num_traits::ops::overflowing::{OverflowingAdd, OverflowingMul, OverflowingSub}; -use num_traits::{Bounded, FromBytes, One, PrimInt, ToBytes, ToPrimitive, Zero}; +use num_traits::{Bounded, One, PrimInt, ToPrimitive, Zero}; use num_integer; +#[cfg(feature = "use-unsafe")] use core::borrow::{Borrow, BorrowMut}; use core::convert::TryFrom; use core::fmt::Write; +#[cfg(feature = "use-unsafe")] use core::hash::Hash; -use core::marker::PhantomData; -use crate::machineword::{Endianness, MachineWord}; +use crate::machineword::MachineWord; use crate::patch_num_traits::{OverflowingShl, OverflowingShr}; +#[cfg(feature = "zeroize")] use zeroize::DefaultIsZeroes; #[allow(unused_imports)] @@ -1395,58 +1397,70 @@ impl num_integer::Integer for FixedUInt { // #endregion num-integer::Integer +#[cfg(feature = "zeroize")] impl DefaultIsZeroes for FixedUInt {} -// Helper trait to provide byte size - -// Holds an owned copy of returned bytes +// Helper, holds an owned copy of returned bytes #[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Debug)] pub struct BytesHolder { array: [T; N], - endianness: Endianness, } + +#[cfg(feature = "use-unsafe")] impl BytesHolder { - fn new(input: [T; N], bigendian: bool) -> Self { - let mut array = input.clone(); - if cfg!(target_endian = "little") && bigendian { - array.reverse(); - } else if cfg!(target_endian = "big") && !bigendian { - array.reverse(); - } - let endianness = if bigendian { - Endianness::Big - } else { - Endianness::Little - }; - Self { array, endianness } + // Converts internal storage to a mutable byte slice + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + // SAFETY: This is safe because the size of the array is the same as the size of the slice + unsafe { + core::slice::from_raw_parts_mut( + &mut self.array as *mut T as *mut u8, + N * core::mem::size_of::(), + ) + } + } + fn as_byte_slice(&self) -> &[u8] { + // SAFETY: This is safe because the size of the array is the same as the size of the slice + unsafe { + core::slice::from_raw_parts( + &self.array as *const T as *const u8, + N * core::mem::size_of::(), + ) + } } } + +#[cfg(feature = "use-unsafe")] impl Borrow<[u8]> for BytesHolder { fn borrow(&self) -> &[u8] { - T::to_byte_buffer(&self.array, self.endianness) + self.as_byte_slice() } } +#[cfg(feature = "use-unsafe")] impl BorrowMut<[u8]> for BytesHolder { fn borrow_mut(&mut self) -> &mut [u8] { - T::to_byte_buffer_mut(&mut self.array, self.endianness) + self.as_byte_slice_mut() } } +#[cfg(feature = "use-unsafe")] impl AsRef<[u8]> for BytesHolder { fn as_ref(&self) -> &[u8] { - T::to_byte_buffer(&self.array, self.endianness) + self.as_byte_slice() } } +#[cfg(feature = "use-unsafe")] impl AsMut<[u8]> for BytesHolder { fn as_mut(&mut self) -> &mut [u8] { - T::to_byte_buffer_mut(&mut self.array, self.endianness) + self.as_byte_slice_mut() } } +#[cfg(feature = "use-unsafe")] impl Hash for BytesHolder { - fn hash(&self, state: &mut H) { + fn hash(&self, _state: &mut H) { todo!() } } +#[cfg(feature = "use-unsafe")] impl num_traits::ToBytes for FixedUInt where T: core::fmt::Debug, @@ -1454,11 +1468,15 @@ where type Bytes = BytesHolder; fn to_be_bytes(&self) -> Self::Bytes { - Self::Bytes::new(self.array, true) + let mut ret = Self::Bytes { array: self.array }; + let _ = self.to_be_bytes(ret.as_byte_slice_mut()); + ret } fn to_le_bytes(&self) -> Self::Bytes { - Self::Bytes::new(self.array, false) + let mut ret = Self::Bytes { array: self.array }; + let _ = self.to_le_bytes(ret.as_byte_slice_mut()); + ret } } @@ -1706,4 +1724,35 @@ mod tests { assert_eq!(u32_ver.to_le_bytes(&mut output_buffer).unwrap(), &le_bytes); assert_eq!(u32_ver.to_be_bytes(&mut output_buffer).unwrap(), &be_bytes); } + + fn test_helper(input: &T, expected_be: &[u8]) { + let mut buffer = [0u8; 256]; + buffer[..expected_be.len()].copy_from_slice(expected_be); + let expected_le = &mut buffer[..expected_be.len()]; + expected_le.reverse(); + + let out = input.to_be_bytes(); + assert_eq!(out.as_ref(), expected_be); + let out = input.to_le_bytes(); + assert_eq!(out.as_ref(), expected_le); + } + + #[cfg(feature = "use-unsafe")] + #[test] + fn test_to_bytes() { + test_helper(&0xAB_u8, &[0xAB_u8]); + test_helper(&0xABCD_u16, &[0xAB, 0xCD]); + test_helper( + &FixedUInt::::from_u32(0x12345678).unwrap(), + &[0x12, 0x34, 0x56, 0x78], + ); + test_helper( + &FixedUInt::::from_u32(0x12345678).unwrap(), + &[0x12, 0x34, 0x56, 0x78], + ); + test_helper( + &FixedUInt::::from_u32(0x12345678).unwrap(), + &[0x12, 0x34, 0x56, 0x78], + ); + } } diff --git a/src/machineword.rs b/src/machineword.rs index 0536346..c3647d4 100644 --- a/src/machineword.rs +++ b/src/machineword.rs @@ -12,14 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Enum to specify byte order. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub enum Endianness { - Big, - Little, - Native, -} - /// Represents a CPU native word, from 8-bit to 32-bit, with corresponding /// double-word to hold multiplication/division products. pub trait MachineWord: @@ -39,15 +31,6 @@ pub trait MachineWord: // Todo: get rid of this, single use fn to_ne_bytes(self) -> [u8; 8]; - - #[cfg(feature = "use-unsafe")] - fn to_byte_buffer<'a, const N: usize>(array: &'a [Self; N], endianness: Endianness) - -> &'a [u8]; - #[cfg(feature = "use-unsafe")] - fn to_byte_buffer_mut<'a, const N: usize>( - array: &'a mut [Self; N], - endianness: Endianness, - ) -> &'a mut [u8]; } impl MachineWord for u8 { @@ -63,20 +46,6 @@ impl MachineWord for u8 { ret[0] = self; ret } - #[cfg(feature = "use-unsafe")] - fn to_byte_buffer<'a, const N: usize>( - array: &'a [Self; N], - _endianness: Endianness, - ) -> &'a [u8] { - array - } - #[cfg(feature = "use-unsafe")] - fn to_byte_buffer_mut<'a, const N: usize>( - array: &'a mut [u8; N], - _endianness: Endianness, - ) -> &'a mut [u8] { - array - } } impl MachineWord for u16 { type DoubleWord = u32; @@ -92,30 +61,6 @@ impl MachineWord for u16 { halfslice.copy_from_slice(&self.to_ne_bytes()); ret } - #[cfg(feature = "use-unsafe")] - fn to_byte_buffer<'a, const N: usize>( - array: &'a [Self; N], - endianness: Endianness, - ) -> &'a [u8] { - let buffer = array.map(|word| match endianness { - Endianness::Big => word.to_be_bytes(), - Endianness::Little => word.to_le_bytes(), - Endianness::Native => word.to_ne_bytes(), - }); - unsafe { core::slice::from_raw_parts(buffer.as_ptr() as *const u8, N * 2) } - } - #[cfg(feature = "use-unsafe")] - fn to_byte_buffer_mut<'a, const N: usize>( - array: &'a mut [u16; N], - endianness: Endianness, - ) -> &'a mut [u8] { - let mut buffer = array.map(|word| match endianness { - Endianness::Big => word.to_be_bytes(), - Endianness::Little => word.to_le_bytes(), - Endianness::Native => word.to_ne_bytes(), - }); - unsafe { core::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, N * 2) } - } } impl MachineWord for u32 { type DoubleWord = u64; @@ -131,30 +76,6 @@ impl MachineWord for u32 { halfslice.copy_from_slice(&self.to_ne_bytes()); ret } - #[cfg(feature = "use-unsafe")] - fn to_byte_buffer<'a, const N: usize>( - array: &'a [Self; N], - endianness: Endianness, - ) -> &'a [u8] { - let buffer = array.map(|word| match endianness { - Endianness::Big => word.to_be_bytes(), - Endianness::Little => word.to_le_bytes(), - Endianness::Native => word.to_ne_bytes(), - }); - unsafe { core::slice::from_raw_parts(buffer.as_ptr() as *const u8, N * 4) } - } - #[cfg(feature = "use-unsafe")] - fn to_byte_buffer_mut<'a, const N: usize>( - array: &'a mut [u32; N], - endianness: Endianness, - ) -> &'a mut [u8] { - let mut buffer = array.map(|word| match endianness { - Endianness::Big => word.to_be_bytes(), - Endianness::Little => word.to_le_bytes(), - Endianness::Native => word.to_ne_bytes(), - }); - unsafe { core::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, N * 4) } - } } #[cfg(test)] @@ -175,58 +96,4 @@ mod tests { compare(2u32, [2u8, 0, 0, 0, 0, 0, 0, 0]); compare(65537u32, [1u8, 0, 1, 0, 0, 0, 0, 0]); } - - #[cfg(feature = "use-unsafe")] - #[test] - fn test_to_byte_buffer() { - const N: usize = 3; - let words_u8: [u8; N] = [1; N]; - let words_u16: [u16; N] = [256; N]; - let words_u32: [u32; N] = [65536; N]; - - let buffer_u8 = ::to_byte_buffer(&words_u8, Endianness::Native); - let buffer_u16 = ::to_byte_buffer(&words_u16, Endianness::Native); - let buffer_u32 = ::to_byte_buffer(&words_u32, Endianness::Native); - - assert_eq!(buffer_u8.len(), N); - assert_eq!(buffer_u16.len(), N * 2); - assert_eq!(buffer_u32.len(), N * 4); - } - #[cfg(feature = "use-unsafe")] - #[test] - fn test_to_mut_byte_buffer() { - const N: usize = 3; - let mut words_u8: [u8; N] = [1; N]; - let mut words_u16: [u16; N] = [256; N]; - let mut words_u32: [u32; N] = [65536; N]; - - let buffer_u8 = ::to_byte_buffer_mut(&mut words_u8, Endianness::Native); - let buffer_u16 = - ::to_byte_buffer_mut(&mut words_u16, Endianness::Native); - let buffer_u32 = - ::to_byte_buffer_mut(&mut words_u32, Endianness::Native); - - buffer_u8[0] = 42; - buffer_u16[0] = 42; - buffer_u32[0] = 42; - assert_eq!(buffer_u8.len(), N); - assert_eq!(buffer_u16.len(), N * 2); - assert_eq!(buffer_u32.len(), N * 4); - } - #[cfg(feature = "use-unsafe")] - #[test] - fn test_actual_correctness_of_to_byte_buffer() { - const N: usize = 3; - let words_u8: [u8; N] = [1, 2, 3]; - let words_u16: [u16; N] = [256, 257, 258]; - let words_u32: [u32; N] = [65536, 65537, 65538]; - - let buffer_u8 = ::to_byte_buffer(&words_u8, Endianness::Native); - let buffer_u16 = ::to_byte_buffer(&words_u16, Endianness::Big); - let buffer_u32 = ::to_byte_buffer(&words_u32, Endianness::Native); - - assert_eq!(buffer_u8, &[1, 2, 3]); - //assert_eq!(buffer_u16, &[0, 1, 0, 1, 2, 1]); - // assert_eq!(buffer_u32, &[0, 1, 0, 0, 1, 0, 0, 2, 1, 0, 0, 3]); - } }