Skip to content

Commit

Permalink
Working design
Browse files Browse the repository at this point in the history
  • Loading branch information
kaidokert committed Sep 23, 2024
1 parent 6c40733 commit 8f5fc48
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 159 deletions.
96 changes: 70 additions & 26 deletions src/fixeduint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@
// 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;

use core::borrow::{Borrow, BorrowMut};
use core::convert::TryFrom;
use core::fmt::Write;
use core::hash::Hash;
use core::marker::PhantomData;

use crate::machineword::{Endianness, MachineWord};
use crate::machineword::MachineWord;
use crate::patch_num_traits::{OverflowingShl, OverflowingShr};

use zeroize::DefaultIsZeroes;
Expand Down Expand Up @@ -1397,68 +1396,82 @@ impl<T: MachineWord, const N: usize> num_integer::Integer for FixedUInt<T, N> {

impl<T: MachineWord, const N: usize> DefaultIsZeroes for FixedUInt<T, N> {}

// Helper trait to provide byte size

// Holds an owned copy of returned bytes
#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Debug)]
pub struct BytesHolder<T: MachineWord, const N: usize> {
array: [T; N],
endianness: Endianness,
}

#[cfg(feature = "use-unsafe")]
impl<T: MachineWord, const N: usize> BytesHolder<T, N> {
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 }
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::<T>(),
)
}
}
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::<T>(),
)
}
}
}

#[cfg(feature = "use-unsafe")]
impl<T: MachineWord, const N: usize> Borrow<[u8]> for BytesHolder<T, N> {
fn borrow(&self) -> &[u8] {
T::to_byte_buffer(&self.array, self.endianness)
self.as_byte_slice()
}
}
#[cfg(feature = "use-unsafe")]
impl<T: MachineWord, const N: usize> BorrowMut<[u8]> for BytesHolder<T, N> {
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<T: MachineWord, const N: usize> AsRef<[u8]> for BytesHolder<T, N> {
fn as_ref(&self) -> &[u8] {
T::to_byte_buffer(&self.array, self.endianness)
self.as_byte_slice()
}
}
#[cfg(feature = "use-unsafe")]
impl<T: MachineWord, const N: usize> AsMut<[u8]> for BytesHolder<T, N> {
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<T: MachineWord, const N: usize> Hash for BytesHolder<T, N> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
fn hash<H: core::hash::Hasher>(&self, _state: &mut H) {
todo!()
}
}

#[cfg(feature = "use-unsafe")]
impl<T: MachineWord, const N: usize> num_traits::ToBytes for FixedUInt<T, N>
where
T: core::fmt::Debug,
{
type Bytes = BytesHolder<T, N>;

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
}
}

Expand Down Expand Up @@ -1706,4 +1719,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<T: num_traits::ToBytes>(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::<u8, 4>::from_u32(0x12345678).unwrap(),
&[0x12, 0x34, 0x56, 0x78],
);
test_helper(
&FixedUInt::<u16, 2>::from_u32(0x12345678).unwrap(),
&[0x12, 0x34, 0x56, 0x78],
);
test_helper(
&FixedUInt::<u32, 1>::from_u32(0x12345678).unwrap(),
&[0x12, 0x34, 0x56, 0x78],
);
}
}
133 changes: 0 additions & 133 deletions src/machineword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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)]
Expand All @@ -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 = <u8 as MachineWord>::to_byte_buffer(&words_u8, Endianness::Native);
let buffer_u16 = <u16 as MachineWord>::to_byte_buffer(&words_u16, Endianness::Native);
let buffer_u32 = <u32 as MachineWord>::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 = <u8 as MachineWord>::to_byte_buffer_mut(&mut words_u8, Endianness::Native);
let buffer_u16 =
<u16 as MachineWord>::to_byte_buffer_mut(&mut words_u16, Endianness::Native);
let buffer_u32 =
<u32 as MachineWord>::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 = <u8 as MachineWord>::to_byte_buffer(&words_u8, Endianness::Native);
let buffer_u16 = <u16 as MachineWord>::to_byte_buffer(&words_u16, Endianness::Big);
let buffer_u32 = <u32 as MachineWord>::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]);
}
}

0 comments on commit 8f5fc48

Please sign in to comment.