diff --git a/Cargo.lock b/Cargo.lock index 9314533..b83d042 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,6 +300,7 @@ dependencies = [ "heapless", "num-traits", "once_cell", + "paste", "postcard", "serde", "spacepackets", @@ -511,6 +512,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + [[package]] name = "postcard" version = "1.0.2" diff --git a/fsrc-core/Cargo.toml b/fsrc-core/Cargo.toml index 35072fe..0db0e44 100644 --- a/fsrc-core/Cargo.toml +++ b/fsrc-core/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" delegate = "0.8" hashbrown = "0.12" heapless = "0.7" +paste = "1.0" [dependencies.num-traits] version = "0.2" diff --git a/fsrc-core/src/util.rs b/fsrc-core/src/util.rs index 33d506c..bb9439e 100644 --- a/fsrc-core/src/util.rs +++ b/fsrc-core/src/util.rs @@ -1,3 +1,6 @@ +//! Utility types and enums +//! +//! This module contains helper types. use crate::pool::StoreAddr; #[cfg(feature = "alloc")] use alloc::string::String; @@ -5,32 +8,177 @@ use alloc::string::String; use alloc::string::ToString; #[cfg(feature = "alloc")] use alloc::vec::Vec; +use core::mem::size_of; +use paste::paste; +use spacepackets::ecss::ToBeBytes; + +macro_rules! primitive_newtypes { + ($($ty: ty,)+) => { + $( + paste! { + #[derive(Debug, Copy, Clone)] + pub struct [<$ty:upper>](pub $ty); + #[derive(Debug, Copy, Clone)] + pub struct [<$ty:upper Pair>](pub $ty, pub $ty); + #[derive(Debug, Copy, Clone)] + pub struct [<$ty:upper Triplet>](pub $ty, pub $ty, pub $ty); + + impl From<$ty> for [<$ty:upper>] { + fn from(v: $ty) -> Self { + Self(v) + } + } + impl From<($ty, $ty)> for [<$ty:upper Pair>] { + fn from(v: ($ty, $ty)) -> Self { + Self(v.0, v.1) + } + } + impl From<($ty, $ty, $ty)> for [<$ty:upper Triplet>] { + fn from(v: ($ty, $ty, $ty)) -> Self { + Self(v.0, v.1, v.2) + } + } + } + )+ + } +} + +primitive_newtypes!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64,); + +macro_rules! scalar_to_be_bytes_impl { + ($($ty: ty,)+) => { + $( + paste! { + impl ToBeBytes for [<$ty:upper>] { + type ByteArray = [u8; size_of::<$ty>()]; + fn to_be_bytes(&self) -> Self::ByteArray { + self.0.to_be_bytes() + } + } + } + )+ + } +} + +macro_rules! pair_to_be_bytes_impl { + ($($ty: ty,)+) => { + $( + paste! { + impl ToBeBytes for [<$ty:upper Pair>] { + type ByteArray = [u8; size_of::<$ty>() * 2]; + fn to_be_bytes(&self) -> Self::ByteArray { + let mut array = [0; size_of::<$ty>() * 2]; + array[0..size_of::<$ty>()].copy_from_slice(&self.0.to_be_bytes()); + array[ + size_of::<$ty>()..2 * size_of::<$ty>() + ].copy_from_slice(&self.1.to_be_bytes()); + array + } + } + } + )+ + } +} + +macro_rules! triplet_to_be_bytes_impl { + ($($ty: ty,)+) => { + $( + paste! { + impl ToBeBytes for [<$ty:upper Triplet>] { + type ByteArray = [u8; size_of::<$ty>() * 3]; + fn to_be_bytes(&self) -> Self::ByteArray { + let mut array = [0; size_of::<$ty>() * 3]; + array[0..size_of::<$ty>()].copy_from_slice(&self.0.to_be_bytes()); + array[ + size_of::<$ty>()..2* size_of::<$ty>() + ].copy_from_slice(&self.1.to_be_bytes()); + array[ + 2 * size_of::<$ty>()..3* size_of::<$ty>() + ].copy_from_slice(&self.2.to_be_bytes()); + array + } + } + } + )+ + } +} + +scalar_to_be_bytes_impl!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64,); + +impl ToBeBytes for U8Pair { + type ByteArray = [u8; 2]; + + fn to_be_bytes(&self) -> Self::ByteArray { + let mut array = [0; 2]; + array[0] = self.0; + array[1] = self.1; + array + } +} + +impl ToBeBytes for I8Pair { + type ByteArray = [u8; 2]; + + fn to_be_bytes(&self) -> Self::ByteArray { + let mut array = [0; 2]; + array[0] = self.0 as u8; + array[1] = self.1 as u8; + array + } +} + +impl ToBeBytes for U8Triplet { + type ByteArray = [u8; 3]; + + fn to_be_bytes(&self) -> Self::ByteArray { + let mut array = [0; 3]; + array[0] = self.0; + array[1] = self.1; + array[2] = self.2; + array + } +} + +impl ToBeBytes for I8Triplet { + type ByteArray = [u8; 3]; + + fn to_be_bytes(&self) -> Self::ByteArray { + let mut array = [0; 3]; + array[0] = self.0 as u8; + array[1] = self.1 as u8; + array[2] = self.2 as u8; + array + } +} + +pair_to_be_bytes_impl!(u16, u32, u64, i16, i32, i64, f32, f64,); +triplet_to_be_bytes_impl!(u16, u32, u64, i16, i32, i64, f32, f64,); #[derive(Debug, Copy, Clone)] pub enum AuxDataRaw { - U8(u8), - U8Pair((u8, u8)), - U8Triplet((u8, u8, u8)), - I8(i8), - I8Pair((i8, i8)), - I8Triplet((i8, i8, i8)), - U16(u16), - U16Pair((u16, u16)), - U16Triplet((u16, u16, u16)), - I16(i16), - I16Pair((i16, i16)), - I16Triplet((i16, i16, i16)), - U32(u32), - U32Pair((u32, u32)), - U32Triplet((u32, u32, u32)), - I32(i32), - I32Pair((i32, i32)), - I32Triplet((i32, i32, i32)), - F32(f32), - F32Pair((f32, f32)), - F32Triplet((f32, f32, f32)), - U64(u64), - F64(f64), + U8(U8), + U8Pair(U8Pair), + U8Triplet(U8Triplet), + I8(I8), + I8Pair(I8Pair), + I8Triplet(I8Triplet), + U16(U16), + U16Pair(U16Pair), + U16Triplet(U16Triplet), + I16(I16), + I16Pair(I16Pair), + I16Triplet(I16Triplet), + U32(U32), + U32Pair(U32Pair), + U32Triplet(U32Triplet), + I32(I32), + I32Pair(I32Pair), + I32Triplet(I32Triplet), + F32(F32), + F32Pair(F32Pair), + F32Triplet(F32Triplet), + U64(U64), + F64(F64), } #[derive(Debug, Copy, Clone)] @@ -50,7 +198,7 @@ macro_rules! from_conversions_for_raw { $( impl From<$raw_ty> for AuxDataRaw { fn from(val: $raw_ty) -> Self { - $TargetPath(val) + $TargetPath(val.into()) } } @@ -127,3 +275,47 @@ impl From<&str> for AuxData { Self::String(val.to_string()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_basic_u32_pair() { + let u32_pair = U32Pair(4, 8); + assert_eq!(u32_pair.0, 4); + assert_eq!(u32_pair.1, 8); + let raw = u32_pair.to_be_bytes(); + let mut u32_conv_back = u32::from_be_bytes(raw[0..4].try_into().unwrap()); + assert_eq!(u32_conv_back, 4); + u32_conv_back = u32::from_be_bytes(raw[4..8].try_into().unwrap()); + assert_eq!(u32_conv_back, 8); + } + + #[test] + fn basic_signed_test_pair() { + let i8_pair = I8Pair(-3, -16); + assert_eq!(i8_pair.0, -3); + assert_eq!(i8_pair.1, -16); + let raw = i8_pair.to_be_bytes(); + let mut i8_conv_back = i8::from_be_bytes(raw[0..1].try_into().unwrap()); + assert_eq!(i8_conv_back, -3); + i8_conv_back = i8::from_be_bytes(raw[1..2].try_into().unwrap()); + assert_eq!(i8_conv_back, -16); + } + + #[test] + fn basic_signed_test_triplet() { + let i8_triplet = I8Triplet(-3, -16, -126); + assert_eq!(i8_triplet.0, -3); + assert_eq!(i8_triplet.1, -16); + assert_eq!(i8_triplet.2, -126); + let raw = i8_triplet.to_be_bytes(); + let mut i8_conv_back = i8::from_be_bytes(raw[0..1].try_into().unwrap()); + assert_eq!(i8_conv_back, -3); + i8_conv_back = i8::from_be_bytes(raw[1..2].try_into().unwrap()); + assert_eq!(i8_conv_back, -16); + i8_conv_back = i8::from_be_bytes(raw[2..3].try_into().unwrap()); + assert_eq!(i8_conv_back, -126); + } +}