Skip to content

Commit

Permalink
introduce new more efficient LittleEndianConvert trait
Browse files Browse the repository at this point in the history
  • Loading branch information
Robbepop committed Dec 29, 2021
1 parent aea0581 commit d3e0958
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 186 deletions.
18 changes: 6 additions & 12 deletions src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,10 @@ impl MemoryInstance {

/// Get value from memory at given offset.
pub fn get_value<T: LittleEndianConvert>(&self, offset: u32) -> Result<T, Error> {
let mut buffer = self.buffer.borrow_mut();
let region =
self.checked_region(&mut buffer, offset as usize, ::core::mem::size_of::<T>())?;
Ok(
T::from_little_endian(&buffer.as_slice_mut()[region.range()])
.expect("Slice size is checked"),
)
let mut bytes = <<T as LittleEndianConvert>::Bytes as Default>::default();
self.get_into(offset, bytes.as_mut())?;
let value = T::from_le_bytes(bytes);
Ok(value)
}

/// Copy data from memory at given offset.
Expand Down Expand Up @@ -248,11 +245,8 @@ impl MemoryInstance {

/// Copy value in the memory at given offset.
pub fn set_value<T: LittleEndianConvert>(&self, offset: u32, value: T) -> Result<(), Error> {
let mut buffer = self.buffer.borrow_mut();
let range = self
.checked_region(&mut buffer, offset as usize, ::core::mem::size_of::<T>())?
.range();
value.into_little_endian(&mut buffer.as_slice_mut()[range]);
let bytes = T::into_le_bytes(value);
self.set(offset, bytes.as_ref())?;
Ok(())
}

Expand Down
225 changes: 51 additions & 174 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,58 @@ pub trait TransmuteInto<T> {
fn transmute_into(self) -> T;
}

/// Convert from and to little endian.
pub trait LittleEndianConvert
where
Self: Sized,
{
/// Convert to little endian buffer.
fn into_little_endian(self, buffer: &mut [u8]);
/// Convert from little endian buffer.
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error>;
/// Types that can be converted from and to little endian bytes.
pub trait LittleEndianConvert {
/// The little endian bytes representation.
type Bytes: Default + AsRef<[u8]> + AsMut<[u8]>;

/// Converts `self` into little endian bytes.
fn into_le_bytes(self) -> Self::Bytes;

/// Converts little endian bytes into `Self`.
fn from_le_bytes(bytes: Self::Bytes) -> Self;
}

macro_rules! impl_little_endian_convert_primitive {
( $($primitive:ty),* $(,)? ) => {
$(
impl LittleEndianConvert for $primitive {
type Bytes = [::core::primitive::u8; ::core::mem::size_of::<$primitive>()];

fn into_le_bytes(self) -> Self::Bytes {
<$primitive>::to_le_bytes(self)
}

fn from_le_bytes(bytes: Self::Bytes) -> Self {
<$primitive>::from_le_bytes(bytes)
}
}
)*
};
}
impl_little_endian_convert_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64);

macro_rules! impl_little_endian_convert_float {
( $( struct $float_ty:ident($uint_ty:ty); )* $(,)? ) => {
$(
impl LittleEndianConvert for $float_ty {
type Bytes = <$uint_ty as LittleEndianConvert>::Bytes;

fn into_le_bytes(self) -> Self::Bytes {
<$uint_ty>::into_le_bytes(self.to_bits())
}

fn from_le_bytes(bytes: Self::Bytes) -> Self {
Self::from_bits(<$uint_ty>::from_le_bytes(bytes))
}
}
)*
};
}
impl_little_endian_convert_float!(
struct F32(u32);
struct F64(u64);
);

/// Arithmetic operations.
pub trait ArithmeticOps<T> {
Expand Down Expand Up @@ -565,171 +607,6 @@ impl TransmuteInto<i64> for u64 {
}
}

impl LittleEndianConvert for i8 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer[0] = self as u8;
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer
.get(0)
.map(|v| *v as i8)
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for u8 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer[0] = self;
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
buffer
.get(0)
.cloned()
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for i16 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer.copy_from_slice(&self.to_le_bytes());
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
let mut res = [0u8; 2];
buffer
.get(0..2)
.map(|s| {
res.copy_from_slice(s);
Self::from_le_bytes(res)
})
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for u16 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer.copy_from_slice(&self.to_le_bytes());
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
let mut res = [0u8; 2];
buffer
.get(0..2)
.map(|s| {
res.copy_from_slice(s);
Self::from_le_bytes(res)
})
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for i32 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer.copy_from_slice(&self.to_le_bytes());
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
let mut res = [0u8; 4];
buffer
.get(0..4)
.map(|s| {
res.copy_from_slice(s);
Self::from_le_bytes(res)
})
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for u32 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer.copy_from_slice(&self.to_le_bytes());
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
let mut res = [0u8; 4];
buffer
.get(0..4)
.map(|s| {
res.copy_from_slice(s);
Self::from_le_bytes(res)
})
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for i64 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer.copy_from_slice(&self.to_le_bytes());
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
let mut res = [0u8; 8];
buffer
.get(0..8)
.map(|s| {
res.copy_from_slice(s);
Self::from_le_bytes(res)
})
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for f32 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer.copy_from_slice(&self.to_bits().to_le_bytes());
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
let mut res = [0u8; 4];
buffer
.get(0..4)
.map(|s| {
res.copy_from_slice(s);
Self::from_bits(u32::from_le_bytes(res))
})
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for f64 {
fn into_little_endian(self, buffer: &mut [u8]) {
buffer.copy_from_slice(&self.to_bits().to_le_bytes());
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
let mut res = [0u8; 8];
buffer
.get(0..8)
.map(|s| {
res.copy_from_slice(s);
Self::from_bits(u64::from_le_bytes(res))
})
.ok_or(Error::InvalidLittleEndianBuffer)
}
}

impl LittleEndianConvert for F32 {
fn into_little_endian(self, buffer: &mut [u8]) {
(self.to_bits() as i32).into_little_endian(buffer)
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
i32::from_little_endian(buffer).map(|val| Self::from_bits(val as _))
}
}

impl LittleEndianConvert for F64 {
fn into_little_endian(self, buffer: &mut [u8]) {
(self.to_bits() as i64).into_little_endian(buffer)
}

fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
i64::from_little_endian(buffer).map(|val| Self::from_bits(val as _))
}
}

macro_rules! impl_integer_arithmetic_ops {
($type: ident) => {
impl ArithmeticOps<$type> for $type {
Expand Down

0 comments on commit d3e0958

Please sign in to comment.