Initial commit

This commit is contained in:
Michael Pfaff 2022-08-21 10:40:39 -04:00
commit 053ecf1fdf
Signed by: michael
GPG Key ID: CF402C4A012AA9D4
3 changed files with 179 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/Cargo.lock

10
Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "order"
version = "0.1.0"
edition = "2021"
publish = false
[features]
nightly = []
[dependencies]

167
src/lib.rs Normal file
View File

@ -0,0 +1,167 @@
//! Provides traits for types that can be represented as both big and little-endian byte arrays.
//! Types that have a "canonical" byte array representation are not appropriate implementors of
//! [`ByteOrdered`].
#![feature(generic_const_exprs)]
mod private {
pub trait Sealed {}
}
/// Order of bits or bytes.
pub trait Order {
fn from_bytes<T: ByteOrdered>(bytes: [u8; T::BYTES]) -> T;
fn to_bytes<T: ByteOrdered>(value: T) -> [u8; T::BYTES];
}
#[derive(Clone, Copy)]
pub struct Big;
#[derive(Clone, Copy)]
pub struct Little;
impl Order for Big {
#[inline(always)]
fn from_bytes<T: ByteOrdered>(bytes: [u8; T::BYTES]) -> T {
T::from_be_bytes(bytes)
}
#[inline(always)]
fn to_bytes<T: ByteOrdered>(value: T) -> [u8; T::BYTES] {
value.to_be_bytes()
}
}
impl Order for Little {
#[inline(always)]
fn from_bytes<T: ByteOrdered>(bytes: [u8; T::BYTES]) -> T {
T::from_le_bytes(bytes)
}
#[inline(always)]
fn to_bytes<T: ByteOrdered>(value: T) -> [u8; T::BYTES] {
value.to_le_bytes()
}
}
pub trait ByteOrdered: Copy {
/// Length of the type in bytes.
const BYTES: usize;
#[inline(always)]
fn to_bytes<O: Order>(self) -> [u8; Self::BYTES] {
O::to_bytes(self)
}
#[inline(always)]
fn from_bytes<O: Order>(bytes: [u8; Self::BYTES]) -> Self {
O::from_bytes(bytes)
}
fn to_be_bytes(self) -> [u8; Self::BYTES];
fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self;
fn to_le_bytes(self) -> [u8; Self::BYTES];
fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self;
}
// TODO: file a bug report "Use-sites of this trait as a bound are required to also duplicate the
// where clause"
pub trait ByteOrderedA: ByteOrdered
where
[(); <Self as ByteOrdered>::BYTES]:,
{
}
impl<T> ByteOrderedA for T
where
T: ByteOrdered,
[(); T::BYTES]:,
{
}
macro_rules! num_impl {
($ty:ty) => {
impl ByteOrdered for $ty {
const BYTES: usize = std::mem::size_of::<$ty>();
#[inline(always)]
fn to_be_bytes(self) -> [u8; Self::BYTES] {
<$ty>::to_be_bytes(self)
}
#[inline(always)]
fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self {
<$ty>::from_be_bytes(bytes)
}
#[inline(always)]
fn to_le_bytes(self) -> [u8; Self::BYTES] {
<$ty>::to_le_bytes(self)
}
#[inline(always)]
fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self {
<$ty>::from_le_bytes(bytes)
}
}
};
}
num_impl!(u8);
num_impl!(u16);
num_impl!(u32);
num_impl!(u64);
num_impl!(u128);
num_impl!(i8);
num_impl!(i16);
num_impl!(i32);
num_impl!(i64);
num_impl!(i128);
num_impl!(f32);
num_impl!(f64);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_be_bytes() {
const CASES: &[(u32, [u8; 4])] = &[
(0x420, [0x00, 0x00, 0x04, 0x20]),
(0x69, [0x00, 0x00, 0x00, 0x69]),
(u32::MAX, [0xFF, 0xFF, 0xFF, 0xFF]),
(32, [0, 0, 0, 32]),
];
for (n, bytes) in CASES {
assert_eq!(n.to_be_bytes(), *bytes);
assert_eq!(n.to_bytes::<Big>(), *bytes);
assert_eq!(Big::to_bytes(*n), *bytes);
assert_eq!(u32::from_be_bytes(*bytes), *n);
}
}
#[test]
fn to_le_bytes() {
const CASES: &[(u32, [u8; 4])] = &[
(0x420, [0x20, 0x04, 0x00, 0x00]),
(0x69, [0x69, 0x00, 0x00, 0x00]),
(u32::MAX, [0xFF, 0xFF, 0xFF, 0xFF]),
(32, [32, 0, 0, 0]),
];
for (n, bytes) in CASES {
assert_eq!(n.to_le_bytes(), *bytes);
assert_eq!(n.to_bytes::<Little>(), *bytes);
assert_eq!(Little::to_bytes(*n), *bytes);
assert_eq!(u32::from_le_bytes(*bytes), *n);
}
}
}