Skip to content

Commit

Permalink
Store chars of non-native endianness as u32s
Browse files Browse the repository at this point in the history
  • Loading branch information
djkoloski committed Aug 30, 2022
1 parent 2f0d504 commit 6f75ee6
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 8 deletions.
4 changes: 3 additions & 1 deletion src/impl_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ macro_rules! impl_struct {
/// Creates a new value from a native-endian value
#[inline]
pub $($const)? fn new(value: $ne) -> Self {
let value = from_native!(@$class $endian<$ne> value);
Self {
value: swap_bytes!(@$class $endian<$ne> value)
}
Expand All @@ -28,7 +29,8 @@ macro_rules! impl_struct {
/// Converts the value to a native-endian value
#[inline]
pub $($const)? fn value(self) -> $ne {
swap_bytes!(@$class $endian<$ne> self.value)
let value = swap_bytes!(@$class $endian<$ne> self.value);
to_native!(@$class $endian<$ne> value)
}

/// Creates a `NativeEndian` from this value
Expand Down
61 changes: 54 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ use core::{
},
};

/// A type that has an associated cross-endian storage type.
pub unsafe trait Primitive {
/// An endian-agnostic type that can represent the primitve in both little- and big-endian
/// forms.
type Storage;
}

/// A wrapper for native-endian types.
///
/// This is mostly useful for `const` conversions to big- and little-endian types in contexts where
Expand All @@ -100,15 +107,15 @@ pub struct NativeEndian<T> {
/// A wrapper for big-endian types.
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct LittleEndian<T> {
value: T,
pub struct LittleEndian<T: Primitive> {
value: T::Storage,
}

/// A wrapper for little-endian types.
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct BigEndian<T> {
value: T,
pub struct BigEndian<T: Primitive> {
value: T::Storage,
}

macro_rules! swap_endian {
Expand Down Expand Up @@ -148,7 +155,7 @@ macro_rules! swap_bytes {
<$ne>::from_bits(swap_endian!(@$endian $value.to_bits()))
};
(@char $endian:ident<$ne:ty> $value:expr) => {
unsafe { ::core::char::from_u32_unchecked(swap_endian!(@$endian $value as u32)) }
swap_endian!(@$endian $value)
};
(@nonzero $endian:ident<$ne:ty> $value:expr) => {
unsafe { <$ne>::new_unchecked(swap_endian!(@$endian $value.get())) }
Expand All @@ -158,6 +165,18 @@ macro_rules! swap_bytes {
};
}

macro_rules! from_native {
(@char NativeEndian<$ne:ty> $value:expr) => { $value };
(@char $endian:ident<$ne:ty> $value:expr) => { $value as u32 };
(@$class:ident $endian:ident<$ne:ty> $value:expr) => { $value };
}

macro_rules! to_native {
(@char NativeEndian<$ne:ty> $value:expr) => { $value };
(@char $endian:ident<$ne:ty> $value:expr) => { unsafe { char::from_u32_unchecked($value) } };
(@$class:ident $endian:ident<$ne:ty> $value:expr) => { $value };
}

macro_rules! impl_endian {
(
@$class:ident $native:ty $(= $prim:ty)?,
Expand All @@ -173,14 +192,42 @@ macro_rules! impl_endian {
impl_struct!(@$class $endian<$ne> $(= $prim)?);
#[cfg(feature = "validation")]
impl_validation!(@$class $endian<$ne> $(= $prim)?);
#[doc = "Alias for `"]
#[doc = "Alias for "]
#[doc = $doc]
#[doc = "`"]
#[doc = "."]
#[allow(non_camel_case_types)]
pub type $alias = $endian<$ne>;
};
}

macro_rules! impl_primitive {
($($ty:ty),+ $(,)?) => {
$(
unsafe impl Primitive for $ty {
type Storage = $ty;
}
)+
};
}

impl_primitive!(
i16, i32, i64, i128,
u16, u32, u64, u128,
f32, f64,
NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
);

#[cfg(has_atomics)]
impl_primitive!(AtomicI16, AtomicI32, AtomicU16, AtomicU32);

#[cfg(has_atomics_64)]
impl_primitive!(AtomicI64, AtomicU64);

unsafe impl Primitive for char {
type Storage = u32;
}

impl_endian!(
@signed_int i16,
i16_ne = "`NativeEndian<i16>`",
Expand Down

0 comments on commit 6f75ee6

Please sign in to comment.