CFDP initial packet support #14
367
src/util.rs
367
src/util.rs
@ -1,7 +1,9 @@
|
||||
use crate::{ByteConversionError, SizeMissmatch};
|
||||
use core::fmt::Debug;
|
||||
use core::fmt::{Debug, Display, Formatter};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "std")]
|
||||
use std::error::Error;
|
||||
|
||||
pub trait ToBeBytes {
|
||||
type ByteArray: AsRef<[u8]>;
|
||||
@ -74,6 +76,43 @@ pub trait UnsignedEnum {
|
||||
|
||||
pub trait UnsignedEnumExt: UnsignedEnum + Debug + Copy + Clone + PartialEq + Eq {}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum UnsignedByteFieldError {
|
||||
/// Value is too large for specified width of byte field. The first value contains the width,
|
||||
/// the second value contains the detected value.
|
||||
ValueTooLargeForWidth((usize, u64)),
|
||||
/// Only 1, 2, 4 and 8 are allow width values. Optionally contains the expected width if
|
||||
/// applicable, for example for conversions.
|
||||
InvalidWidth(usize, Option<usize>),
|
||||
ByteConversionError(ByteConversionError),
|
||||
}
|
||||
|
||||
impl From<ByteConversionError> for UnsignedByteFieldError {
|
||||
fn from(value: ByteConversionError) -> Self {
|
||||
Self::ByteConversionError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for UnsignedByteFieldError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::ByteConversionError(e) => {
|
||||
write!(f, "low level byte conversion error: {e}")
|
||||
}
|
||||
Self::InvalidWidth(val, _) => {
|
||||
write!(f, "invalid width {val}, only 1, 2, 4 and 8 are allowed.")
|
||||
}
|
||||
Self::ValueTooLargeForWidth((width, value)) => {
|
||||
write!(f, "value {value} too large for width {width}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Error for UnsignedByteFieldError {}
|
||||
|
||||
/// Type erased variant.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
@ -87,30 +126,30 @@ impl UnsignedByteField {
|
||||
Self { width, value }
|
||||
}
|
||||
|
||||
pub fn new_from_be_bytes(width: usize, buf: &[u8]) -> Result<Self, ByteConversionError> {
|
||||
pub fn new_from_be_bytes(width: usize, buf: &[u8]) -> Result<Self, UnsignedByteFieldError> {
|
||||
if width > buf.len() {
|
||||
return Err(ByteConversionError::FromSliceTooSmall(SizeMissmatch {
|
||||
found: buf.len(),
|
||||
expected: width,
|
||||
}));
|
||||
})
|
||||
.into());
|
||||
}
|
||||
match width {
|
||||
0 => Ok(Self::new(0, 0)),
|
||||
1 => Ok(Self::new(1, buf[0] as u64)),
|
||||
0 => Ok(Self::new(width, 0)),
|
||||
1 => Ok(Self::new(width, buf[0] as u64)),
|
||||
2 => Ok(Self::new(
|
||||
2,
|
||||
width,
|
||||
u16::from_be_bytes(buf[0..2].try_into().unwrap()) as u64,
|
||||
)),
|
||||
4 => Ok(Self::new(
|
||||
2,
|
||||
width,
|
||||
u32::from_be_bytes(buf[0..4].try_into().unwrap()) as u64,
|
||||
)),
|
||||
8 => Ok(Self::new(
|
||||
2,
|
||||
width,
|
||||
u64::from_be_bytes(buf[0..8].try_into().unwrap()),
|
||||
)),
|
||||
// TODO: I don't know whether it is a good idea to panic here.
|
||||
_ => panic!("invalid width"),
|
||||
_ => Err(UnsignedByteFieldError::InvalidWidth(width, None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -156,18 +195,18 @@ impl UnsignedEnum for UnsignedByteField {
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct GenericUnsignedByteField<TYPE> {
|
||||
val: TYPE,
|
||||
value: TYPE,
|
||||
}
|
||||
|
||||
impl<TYPE> GenericUnsignedByteField<TYPE> {
|
||||
pub fn new(val: TYPE) -> Self {
|
||||
Self { val }
|
||||
Self { value: val }
|
||||
}
|
||||
}
|
||||
|
||||
impl<TYPE: ToBeBytes> UnsignedEnum for GenericUnsignedByteField<TYPE> {
|
||||
fn len(&self) -> usize {
|
||||
self.val.written_len()
|
||||
self.value.written_len()
|
||||
}
|
||||
|
||||
fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<(), ByteConversionError> {
|
||||
@ -177,7 +216,7 @@ impl<TYPE: ToBeBytes> UnsignedEnum for GenericUnsignedByteField<TYPE> {
|
||||
expected: self.len(),
|
||||
}));
|
||||
}
|
||||
buf[0..self.len()].copy_from_slice(self.val.to_be_bytes().as_ref());
|
||||
buf[0..self.len()].copy_from_slice(self.value.to_be_bytes().as_ref());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -190,16 +229,16 @@ pub type UnsignedU64 = GenericUnsignedByteField<u64>;
|
||||
|
||||
impl From<UnsignedU8> for UnsignedByteField {
|
||||
fn from(value: UnsignedU8) -> Self {
|
||||
Self::new(1, value.val as u64)
|
||||
Self::new(1, value.value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<UnsignedByteField> for UnsignedU8 {
|
||||
type Error = ();
|
||||
type Error = UnsignedByteFieldError;
|
||||
|
||||
fn try_from(value: UnsignedByteField) -> Result<Self, ()> {
|
||||
if value.value > 2_u64.pow(8) - 1 {
|
||||
return Err(());
|
||||
fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> {
|
||||
if value.width != 1 {
|
||||
return Err(UnsignedByteFieldError::InvalidWidth(value.width, Some(1)));
|
||||
}
|
||||
Ok(Self::new(value.value as u8))
|
||||
}
|
||||
@ -207,16 +246,16 @@ impl TryFrom<UnsignedByteField> for UnsignedU8 {
|
||||
|
||||
impl From<UnsignedU16> for UnsignedByteField {
|
||||
fn from(value: UnsignedU16) -> Self {
|
||||
Self::new(2, value.val as u64)
|
||||
Self::new(2, value.value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<UnsignedByteField> for UnsignedU16 {
|
||||
type Error = ();
|
||||
type Error = UnsignedByteFieldError;
|
||||
|
||||
fn try_from(value: UnsignedByteField) -> Result<Self, ()> {
|
||||
if value.value > 2_u64.pow(16) - 1 {
|
||||
return Err(());
|
||||
fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> {
|
||||
if value.width != 2 {
|
||||
return Err(UnsignedByteFieldError::InvalidWidth(value.width, Some(2)));
|
||||
}
|
||||
Ok(Self::new(value.value as u16))
|
||||
}
|
||||
@ -224,16 +263,16 @@ impl TryFrom<UnsignedByteField> for UnsignedU16 {
|
||||
|
||||
impl From<UnsignedU32> for UnsignedByteField {
|
||||
fn from(value: UnsignedU32) -> Self {
|
||||
Self::new(4, value.val as u64)
|
||||
Self::new(4, value.value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<UnsignedByteField> for UnsignedU32 {
|
||||
type Error = ();
|
||||
type Error = UnsignedByteFieldError;
|
||||
|
||||
fn try_from(value: UnsignedByteField) -> Result<Self, ()> {
|
||||
if value.value > 2_u64.pow(32) - 1 {
|
||||
return Err(());
|
||||
fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> {
|
||||
if value.width != 4 {
|
||||
return Err(UnsignedByteFieldError::InvalidWidth(value.width, Some(4)));
|
||||
}
|
||||
Ok(Self::new(value.value as u32))
|
||||
}
|
||||
@ -241,17 +280,277 @@ impl TryFrom<UnsignedByteField> for UnsignedU32 {
|
||||
|
||||
impl From<UnsignedU64> for UnsignedByteField {
|
||||
fn from(value: UnsignedU64) -> Self {
|
||||
Self::new(8, value.val)
|
||||
Self::new(8, value.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<UnsignedByteField> for UnsignedU64 {
|
||||
type Error = ();
|
||||
type Error = UnsignedByteFieldError;
|
||||
|
||||
fn try_from(value: UnsignedByteField) -> Result<Self, ()> {
|
||||
if value.value > 2_u64.pow(64) - 1 {
|
||||
return Err(());
|
||||
fn try_from(value: UnsignedByteField) -> Result<Self, Self::Error> {
|
||||
if value.width != 8 {
|
||||
return Err(UnsignedByteFieldError::InvalidWidth(value.width, Some(8)));
|
||||
}
|
||||
Ok(Self::new(value.value))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::util::{
|
||||
UnsignedByteField, UnsignedByteFieldError, UnsignedEnum, UnsignedU16, UnsignedU32,
|
||||
UnsignedU64, UnsignedU8,
|
||||
};
|
||||
use std::format;
|
||||
|
||||
#[test]
|
||||
fn test_simple_u8() {
|
||||
let u8 = UnsignedU8::new(5);
|
||||
assert_eq!(u8.len(), 1);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u8.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
assert_eq!(buf[0], 5);
|
||||
for i in 1..8 {
|
||||
assert_eq!(buf[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_u16() {
|
||||
let u16 = UnsignedU16::new(3823);
|
||||
assert_eq!(u16.len(), 2);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u16.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
let raw_val = u16::from_be_bytes(buf[0..2].try_into().unwrap());
|
||||
assert_eq!(raw_val, 3823);
|
||||
for i in 2..8 {
|
||||
assert_eq!(buf[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_u32() {
|
||||
let u32 = UnsignedU32::new(80932);
|
||||
assert_eq!(u32.len(), 4);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u32.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
let raw_val = u32::from_be_bytes(buf[0..4].try_into().unwrap());
|
||||
assert_eq!(raw_val, 80932);
|
||||
for i in 4..8 {
|
||||
assert_eq!(buf[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_u64() {
|
||||
let u64 = UnsignedU64::new(5999999);
|
||||
assert_eq!(u64.len(), 8);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u64.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
let raw_val = u64::from_be_bytes(buf[0..8].try_into().unwrap());
|
||||
assert_eq!(raw_val, 5999999);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversions_u8() {
|
||||
let u8 = UnsignedU8::new(5);
|
||||
let u8_type_erased = UnsignedByteField::from(u8);
|
||||
assert_eq!(u8_type_erased.width, 1);
|
||||
assert_eq!(u8_type_erased.value, 5);
|
||||
let u8_conv_back = UnsignedU8::try_from(u8_type_erased).expect("conversion failed for u8");
|
||||
assert_eq!(u8, u8_conv_back);
|
||||
assert_eq!(u8_conv_back.value, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_u8_fails() {
|
||||
let field = UnsignedByteField::new(2, 60000);
|
||||
let conv_fails = UnsignedU8::try_from(field);
|
||||
assert!(conv_fails.is_err());
|
||||
let err = conv_fails.unwrap_err();
|
||||
match err {
|
||||
UnsignedByteFieldError::InvalidWidth(width, Some(expected)) => {
|
||||
assert_eq!(width, 2);
|
||||
assert_eq!(expected, 1);
|
||||
}
|
||||
_ => {
|
||||
panic!("{}", format!("invalid error {err}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversions_u16() {
|
||||
let u16 = UnsignedU16::new(64444);
|
||||
let u16_type_erased = UnsignedByteField::from(u16);
|
||||
assert_eq!(u16_type_erased.width, 2);
|
||||
assert_eq!(u16_type_erased.value, 64444);
|
||||
let u16_conv_back =
|
||||
UnsignedU16::try_from(u16_type_erased).expect("conversion failed for u16");
|
||||
assert_eq!(u16, u16_conv_back);
|
||||
assert_eq!(u16_conv_back.value, 64444);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_u16_fails() {
|
||||
let field = UnsignedByteField::new(4, 75000);
|
||||
let conv_fails = UnsignedU16::try_from(field);
|
||||
assert!(conv_fails.is_err());
|
||||
let err = conv_fails.unwrap_err();
|
||||
match err {
|
||||
UnsignedByteFieldError::InvalidWidth(width, Some(expected)) => {
|
||||
assert_eq!(width, 4);
|
||||
assert_eq!(expected, 2);
|
||||
}
|
||||
_ => {
|
||||
panic!("{}", format!("invalid error {err}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversions_u32() {
|
||||
let u32 = UnsignedU32::new(75000);
|
||||
let u32_type_erased = UnsignedByteField::from(u32);
|
||||
assert_eq!(u32_type_erased.width, 4);
|
||||
assert_eq!(u32_type_erased.value, 75000);
|
||||
let u32_conv_back =
|
||||
UnsignedU32::try_from(u32_type_erased).expect("conversion failed for u32");
|
||||
assert_eq!(u32, u32_conv_back);
|
||||
assert_eq!(u32_conv_back.value, 75000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_u32_fails() {
|
||||
let field = UnsignedByteField::new(8, 75000);
|
||||
let conv_fails = UnsignedU32::try_from(field);
|
||||
assert!(conv_fails.is_err());
|
||||
let err = conv_fails.unwrap_err();
|
||||
match err {
|
||||
UnsignedByteFieldError::InvalidWidth(width, Some(expected)) => {
|
||||
assert_eq!(width, 8);
|
||||
assert_eq!(expected, 4);
|
||||
}
|
||||
_ => {
|
||||
panic!("{}", format!("invalid error {err}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversions_u64() {
|
||||
let u64 = UnsignedU64::new(5999999);
|
||||
let u64_type_erased = UnsignedByteField::from(u64);
|
||||
assert_eq!(u64_type_erased.width, 8);
|
||||
assert_eq!(u64_type_erased.value, 5999999);
|
||||
let u64_conv_back =
|
||||
UnsignedU64::try_from(u64_type_erased).expect("conversion failed for u64");
|
||||
assert_eq!(u64, u64_conv_back);
|
||||
assert_eq!(u64_conv_back.value, 5999999);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conversion_u64_fails() {
|
||||
let field = UnsignedByteField::new(4, 60000);
|
||||
let conv_fails = UnsignedU64::try_from(field);
|
||||
assert!(conv_fails.is_err());
|
||||
let err = conv_fails.unwrap_err();
|
||||
match err {
|
||||
UnsignedByteFieldError::InvalidWidth(width, Some(expected)) => {
|
||||
assert_eq!(width, 4);
|
||||
assert_eq!(expected, 8);
|
||||
}
|
||||
_ => {
|
||||
panic!("{}", format!("invalid error {err}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_erased_u8_write() {
|
||||
let u8 = UnsignedByteField::new(1, 5);
|
||||
assert_eq!(u8.len(), 1);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u8.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
assert_eq!(buf[0], 5);
|
||||
for i in 1..8 {
|
||||
assert_eq!(buf[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_erased_u16_write() {
|
||||
let u16 = UnsignedByteField::new(2, 3823);
|
||||
assert_eq!(u16.len(), 2);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u16.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
let raw_val = u16::from_be_bytes(buf[0..2].try_into().unwrap());
|
||||
assert_eq!(raw_val, 3823);
|
||||
for i in 2..8 {
|
||||
assert_eq!(buf[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_erased_u32_write() {
|
||||
let u32 = UnsignedByteField::new(4, 80932);
|
||||
assert_eq!(u32.len(), 4);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u32.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
let raw_val = u32::from_be_bytes(buf[0..4].try_into().unwrap());
|
||||
assert_eq!(raw_val, 80932);
|
||||
for i in 4..8 {
|
||||
assert_eq!(buf[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_erased_u64_write() {
|
||||
let u64 = UnsignedByteField::new(8, 5999999);
|
||||
assert_eq!(u64.len(), 8);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u64.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
let raw_val = u64::from_be_bytes(buf[0..8].try_into().unwrap());
|
||||
assert_eq!(raw_val, 5999999);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_erased_u8_construction() {
|
||||
let buf: [u8; 2] = [5, 10];
|
||||
let u8 = UnsignedByteField::new_from_be_bytes(1, &buf).expect("construction failed");
|
||||
assert_eq!(u8.width, 1);
|
||||
assert_eq!(u8.value, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_erased_u16_construction() {
|
||||
let buf: [u8; 2] = [0x10, 0x15];
|
||||
let u16 = UnsignedByteField::new_from_be_bytes(2, &buf).expect("construction failed");
|
||||
assert_eq!(u16.width, 2);
|
||||
assert_eq!(u16.value, 0x1015);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_erased_u32_construction() {
|
||||
let buf: [u8; 4] = [0x01, 0x02, 0x03, 0x04];
|
||||
let u32 = UnsignedByteField::new_from_be_bytes(4, &buf).expect("construction failed");
|
||||
assert_eq!(u32.width, 4);
|
||||
assert_eq!(u32.value, 0x01020304);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_erased_u64_construction() {
|
||||
let buf: [u8; 8] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
|
||||
let u64 = UnsignedByteField::new_from_be_bytes(8, &buf).expect("construction failed");
|
||||
assert_eq!(u64.width, 8);
|
||||
assert_eq!(u64.value, 0x0102030405060708);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user