#![no_std]
#[cfg(feature = "endian_codec_derive")]
pub use endian_codec_derive::*;
pub trait EncodeLE: PackedSize {
fn encode_as_le_bytes(&self, bytes: &mut [u8]);
}
pub trait EncodeBE: PackedSize {
fn encode_as_be_bytes(&self, bytes: &mut [u8]);
}
pub trait EncodeME: PackedSize {
fn encode_as_me_bytes(&self, bytes: &mut [u8]);
}
pub trait DecodeLE: PackedSize {
fn decode_from_le_bytes(bytes: &[u8]) -> Self;
}
pub trait DecodeBE: PackedSize {
fn decode_from_be_bytes(bytes: &[u8]) -> Self;
}
pub trait DecodeME: PackedSize {
fn decode_from_me_bytes(bytes: &[u8]) -> Self;
}
pub trait PackedSize {
const PACKED_LEN: usize;
}
macro_rules! impl_codec_for_primitives {
($type:ty, $byte_len:expr) => {
impl PackedSize for $type {
const PACKED_LEN: usize = $byte_len;
}
impl EncodeLE for $type {
#[inline]
fn encode_as_le_bytes(&self, bytes: &mut [u8]) {
bytes.copy_from_slice(&(self.to_le_bytes()))
}
}
impl EncodeBE for $type {
#[inline]
fn encode_as_be_bytes(&self, bytes: &mut [u8]) {
bytes.copy_from_slice(&(self.to_be_bytes()))
}
}
impl DecodeLE for $type {
#[inline]
fn decode_from_le_bytes(bytes: &[u8]) -> Self {
let mut arr = [0; $byte_len];
arr.copy_from_slice(&bytes);
Self::from_le_bytes(arr)
}
}
impl DecodeBE for $type {
#[inline]
fn decode_from_be_bytes(bytes: &[u8]) -> Self {
let mut arr = [0; $byte_len];
arr.copy_from_slice(&bytes);
Self::from_be_bytes(arr)
}
}
};
}
impl_codec_for_primitives!(u8, 1);
impl_codec_for_primitives!(i8, 1);
impl EncodeME for u8 {
#[inline]
fn encode_as_me_bytes(&self, bytes: &mut [u8]) {
bytes.copy_from_slice(&(self.to_be_bytes()));
}
}
impl DecodeME for u8 {
#[inline]
fn decode_from_me_bytes(bytes: &[u8]) -> Self {
let mut arr = [0; 1];
arr.copy_from_slice(bytes);
Self::from_le_bytes(arr)
}
}
impl_codec_for_primitives!(u16, 2);
impl_codec_for_primitives!(i16, 2);
impl_codec_for_primitives!(u32, 4);
impl_codec_for_primitives!(i32, 4);
impl_codec_for_primitives!(u64, 8);
impl_codec_for_primitives!(i64, 8);
impl_codec_for_primitives!(u128, 16);
impl_codec_for_primitives!(i128, 16);
macro_rules! impl_codec_for_array {
($type:ty, $size:expr) => {
impl PackedSize for $type {
const PACKED_LEN: usize = $size;
}
impl EncodeBE for $type {
#[inline]
fn encode_as_be_bytes(&self, bytes: &mut [u8]) {
bytes.copy_from_slice(self);
}
}
impl EncodeLE for $type {
#[inline]
fn encode_as_le_bytes(&self, bytes: &mut [u8]) {
bytes.copy_from_slice(self);
}
}
impl EncodeME for $type {
#[inline]
fn encode_as_me_bytes(&self, bytes: &mut [u8]) {
bytes.copy_from_slice(self);
}
}
impl DecodeBE for $type {
#[inline]
fn decode_from_be_bytes(bytes: &[u8]) -> Self {
let mut arr = [0; Self::PACKED_LEN];
arr.copy_from_slice(bytes);
arr
}
}
impl DecodeLE for $type {
#[inline]
fn decode_from_le_bytes(bytes: &[u8]) -> Self {
let mut arr = [0; Self::PACKED_LEN];
arr.copy_from_slice(bytes);
arr
}
}
impl DecodeME for $type {
#[inline]
fn decode_from_me_bytes(bytes: &[u8]) -> Self {
let mut arr = [0; Self::PACKED_LEN];
arr.copy_from_slice(bytes);
arr
}
}
};
}
impl_codec_for_array!([u8; 1], 1);
impl_codec_for_array!([u8; 2], 2);
impl_codec_for_array!([u8; 3], 3);
impl_codec_for_array!([u8; 4], 4);
impl_codec_for_array!([u8; 5], 5);
impl_codec_for_array!([u8; 6], 6);
impl_codec_for_array!([u8; 7], 7);
impl_codec_for_array!([u8; 8], 8);
impl_codec_for_array!([u8; 9], 9);
impl_codec_for_array!([u8; 10], 10);
impl_codec_for_array!([u8; 11], 11);
impl_codec_for_array!([u8; 12], 12);
impl_codec_for_array!([u8; 13], 13);
impl_codec_for_array!([u8; 14], 14);
impl_codec_for_array!([u8; 15], 15);
impl_codec_for_array!([u8; 16], 16);
impl_codec_for_array!([u8; 17], 17);
impl_codec_for_array!([u8; 18], 18);
impl_codec_for_array!([u8; 19], 19);
impl_codec_for_array!([u8; 20], 20);
impl_codec_for_array!([u8; 21], 21);
impl_codec_for_array!([u8; 22], 22);
impl_codec_for_array!([u8; 23], 23);
impl_codec_for_array!([u8; 24], 24);
impl_codec_for_array!([u8; 25], 25);
impl_codec_for_array!([u8; 26], 26);
impl_codec_for_array!([u8; 27], 27);
impl_codec_for_array!([u8; 28], 28);
impl_codec_for_array!([u8; 29], 29);
impl_codec_for_array!([u8; 30], 30);
impl_codec_for_array!([u8; 31], 31);
impl_codec_for_array!([u8; 32], 32);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn derive_endian_size() {
#[derive(PackedSize)]
struct A {};
assert_eq!(A::PACKED_LEN, 0);
#[derive(PackedSize)]
struct B {
_a: u16,
}
assert_eq!(B::PACKED_LEN, 2);
#[derive(PackedSize)]
struct C {
_a: u16,
_b: u16,
}
assert_eq!(C::PACKED_LEN, 2 + 2);
}
#[test]
fn derive_littlendian_serialize() {
#[derive(PackedSize, EncodeLE)]
struct Example {
a: u16,
}
let t = Example { a: 5 };
let mut b = [0; 2];
t.encode_as_le_bytes(&mut b);
}
#[test]
fn derive_bigendian_serialize() {
#[derive(PackedSize, EncodeBE)]
struct Example {
a: u16,
}
let t = Example { a: 5 };
let mut b = [0; 2];
t.encode_as_be_bytes(&mut b);
}
#[test]
fn derive_mixed_endian_serialize() {
#[derive(PackedSize, EncodeME, Default)]
struct Example {
#[endian = "le"]
a: u16,
#[endian = "be"]
b: u16,
#[endian = "little"]
aa: i16,
#[endian = "big"]
bb: i16,
}
let t = Example::default();
let mut b = [0; 8];
t.encode_as_me_bytes(&mut b);
}
#[test]
fn derive_all_serialize() {
#[derive(Default, PackedSize, EncodeLE, EncodeBE, EncodeME)]
struct Example {
#[endian = "be"]
a: u16,
b: [u8; 32],
}
let t = Example::default();
let mut b = [0; 34];
t.encode_as_me_bytes(&mut b);
t.encode_as_be_bytes(&mut b);
t.encode_as_le_bytes(&mut b);
}
#[test]
fn derive_all() {
#[derive(
Default, PackedSize, EncodeLE, EncodeBE, EncodeME, DecodeLE, DecodeBE, DecodeME,
)]
struct Example {
#[endian = "be"]
a: u16,
}
let t = Example::default();
let mut b = [0; 2];
t.encode_as_me_bytes(&mut b);
t.encode_as_be_bytes(&mut b);
t.encode_as_le_bytes(&mut b);
}
#[test]
fn test_codec_2bytes_primitives() {
#[derive(Debug, PartialEq, Eq, PackedSize, EncodeLE, DecodeLE, EncodeBE, DecodeBE)]
struct A {
a: u16,
b: i16,
}
let test = A { a: 0x2F, b: 0x2F00 };
assert_eq!(A::PACKED_LEN, 4);
let mut bytes = [0; A::PACKED_LEN];
test.encode_as_le_bytes(&mut bytes);
assert_eq!([47, 0, 0, 47], bytes);
let test_back = A::decode_from_le_bytes(&bytes);
assert_eq!(test, test_back);
test.encode_as_be_bytes(&mut bytes);
assert_eq!([0, 47, 47, 0], bytes);
let test_back = A::decode_from_be_bytes(&bytes);
assert_eq!(test, test_back);
}
#[test]
fn test_codec_4bytes_primitives() {
#[derive(Debug, PartialEq, Eq, PackedSize, EncodeLE, DecodeLE, EncodeBE, DecodeBE)]
struct A {
a: u32,
b: i32,
}
let test = A {
a: 0x2F,
b: 0x2F000000,
};
assert_eq!(A::PACKED_LEN, 8);
let mut bytes = [0; A::PACKED_LEN];
test.encode_as_le_bytes(&mut bytes);
assert_eq!([47, 0, 0, 0, 0, 0, 0, 47], bytes);
let test_back = A::decode_from_le_bytes(&bytes);
assert_eq!(test, test_back);
test.encode_as_be_bytes(&mut bytes);
assert_eq!([0, 0, 0, 47, 47, 0, 0, 0], bytes);
let test_back = A::decode_from_be_bytes(&bytes);
assert_eq!(test, test_back);
}
#[test]
fn test_codec_8bytes_primitives() {
#[derive(Debug, PartialEq, Eq, PackedSize, EncodeLE, DecodeLE, EncodeBE, DecodeBE)]
struct A {
a: u64,
b: i64,
}
let test = A {
a: 0x2F,
b: 0x2F000000_00000000,
};
assert_eq!(A::PACKED_LEN, 16);
let mut bytes = [0; A::PACKED_LEN];
test.encode_as_le_bytes(&mut bytes);
assert_eq!([47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47], bytes);
let test_back = A::decode_from_le_bytes(&bytes);
assert_eq!(test, test_back);
test.encode_as_be_bytes(&mut bytes);
assert_eq!([0, 0, 0, 0, 0, 0, 0, 47, 47, 0, 0, 0, 0, 0, 0, 0,], bytes);
let test_back = A::decode_from_be_bytes(&bytes);
assert_eq!(test, test_back);
}
#[test]
fn test_codec_16bytes_primitives() {
#[derive(Debug, PartialEq, Eq, PackedSize, EncodeLE, DecodeLE, EncodeBE, DecodeBE)]
struct A {
a: u128,
b: i128,
}
let test = A {
a: 0x2F,
b: 0x2F000000_00000000_00000000_00000000,
};
assert_eq!(A::PACKED_LEN, 32);
let mut bytes = [0; A::PACKED_LEN];
test.encode_as_le_bytes(&mut bytes);
assert_eq!(
[
47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 47
],
bytes
);
let test_back = A::decode_from_le_bytes(&bytes);
assert_eq!(test, test_back);
test.encode_as_be_bytes(&mut bytes);
assert_eq!(
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
],
bytes
);
let test_back = A::decode_from_be_bytes(&bytes);
assert_eq!(test, test_back);
}
}