some restructuring
Some checks failed
Rust/spacepackets/pipeline/head There was a failure building this commit
Rust/spacepackets/pipeline/pr-main There was a failure building this commit

This commit is contained in:
Robin Müller 2023-08-16 17:27:02 +02:00
parent 4e2c0f1aa7
commit 3cb19298c8
Signed by: muellerr
GPG Key ID: FCE0B2BD2195142F
2 changed files with 125 additions and 13 deletions

View File

@ -9,6 +9,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod msg_to_user;
pub const MIN_TLV_LEN: usize = 2; pub const MIN_TLV_LEN: usize = 2;
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
@ -98,12 +100,30 @@ impl<'data> Tlv<'data> {
} }
} }
/// Checks whether the type field contains one of the standard types specified in the CFDP
/// standard and is part of the [TlvType] enum.
pub fn is_standard_tlv(&self) -> bool {
if let TlvTypeField::Standard(_) = self.tlv_type_field {
return true;
}
false
}
/// Returns the standard TLV type if the TLV field is not a custom field
pub fn tlv_type(&self) -> Option<TlvType> {
if let TlvTypeField::Standard(tlv_type) = self.tlv_type_field {
Some(tlv_type)
} else {
None
}
}
pub fn tlv_type_field(&self) -> TlvTypeField { pub fn tlv_type_field(&self) -> TlvTypeField {
self.tlv_type_field self.tlv_type_field
} }
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> { pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
generic_len_check_data_serialization(buf, self.len_value(), MIN_TLV_LEN)?; generic_len_check_data_serialization(buf, self.value().len(), MIN_TLV_LEN)?;
buf[0] = self.tlv_type_field.into(); buf[0] = self.tlv_type_field.into();
self.lv.write_to_be_bytes_no_len_check(&mut buf[1..]); self.lv.write_to_be_bytes_no_len_check(&mut buf[1..]);
Ok(self.len_full()) Ok(self.len_full())
@ -113,7 +133,8 @@ impl<'data> Tlv<'data> {
self.lv.value() self.lv.value()
} }
/// Returns the length of the value part, not including the length byte. /// Helper method to retrieve the length of the value. Simply calls the [slice::len] method of
/// [Self::value]
pub fn len_value(&self) -> usize { pub fn len_value(&self) -> usize {
self.lv.len_value() self.lv.len_value()
} }
@ -244,15 +265,15 @@ impl<'data> TryFrom<Tlv<'data>> for EntityIdTlv {
))); )));
} }
} }
if value.len_value() != 1 let len_value = value.value().len();
&& value.len_value() != 2 if len_value != 1
&& value.len_value() != 4 && len_value != 2
&& value.len_value() != 8 && len_value != 4
{ && len_value != 8 {
return Err(TlvLvError::InvalidValueLength(value.len_value())); return Err(TlvLvError::InvalidValueLength(len_value));
} }
Ok(Self::new( Ok(Self::new(
UnsignedByteField::new_from_be_bytes(value.len_value(), value.value()).map_err( UnsignedByteField::new_from_be_bytes(len_value, value.value()).map_err(
|e| match e { |e| match e {
UnsignedByteFieldError::ByteConversionError(e) => e, UnsignedByteFieldError::ByteConversionError(e) => e,
// This can not happen, we checked for the length validity, and the data is always smaller than // This can not happen, we checked for the length validity, and the data is always smaller than
@ -481,6 +502,7 @@ mod tests {
TlvTypeField::Standard(TlvType::EntityId) TlvTypeField::Standard(TlvType::EntityId)
); );
assert_eq!(tlv_res.len_full(), 3); assert_eq!(tlv_res.len_full(), 3);
assert_eq!(tlv_res.value().len(), 1);
assert_eq!(tlv_res.len_value(), 1); assert_eq!(tlv_res.len_value(), 1);
assert!(!tlv_res.is_empty()); assert!(!tlv_res.is_empty());
assert_eq!(tlv_res.value()[0], 5); assert_eq!(tlv_res.value()[0], 5);
@ -517,7 +539,7 @@ mod tests {
tlv_from_raw.tlv_type_field(), tlv_from_raw.tlv_type_field(),
TlvTypeField::Standard(TlvType::EntityId) TlvTypeField::Standard(TlvType::EntityId)
); );
assert_eq!(tlv_from_raw.len_value(), 1); assert_eq!(tlv_from_raw.value().len(), 1);
assert_eq!(tlv_from_raw.len_full(), 3); assert_eq!(tlv_from_raw.len_full(), 3);
assert_eq!(tlv_from_raw.value()[0], 5); assert_eq!(tlv_from_raw.value()[0], 5);
} }
@ -528,7 +550,7 @@ mod tests {
assert_eq!(tlv_empty.value().len(), 0); assert_eq!(tlv_empty.value().len(), 0);
assert!(tlv_empty.is_empty()); assert!(tlv_empty.is_empty());
assert_eq!(tlv_empty.len_full(), 2); assert_eq!(tlv_empty.len_full(), 2);
assert_eq!(tlv_empty.len_value(), 0); assert!(tlv_empty.value().is_empty());
assert_eq!( assert_eq!(
tlv_empty.tlv_type_field(), tlv_empty.tlv_type_field(),
TlvTypeField::Standard(TlvType::MsgToUser) TlvTypeField::Standard(TlvType::MsgToUser)
@ -559,7 +581,7 @@ mod tests {
TlvTypeField::Standard(TlvType::MsgToUser) TlvTypeField::Standard(TlvType::MsgToUser)
); );
assert_eq!(tlv_empty.len_full(), 2); assert_eq!(tlv_empty.len_full(), 2);
assert_eq!(tlv_empty.len_value(), 0); assert!(tlv_empty.value().is_empty());
} }
#[test] #[test]
@ -585,7 +607,7 @@ mod tests {
assert!(tlv.is_ok()); assert!(tlv.is_ok());
let tlv = tlv.unwrap(); let tlv = tlv.unwrap();
assert_eq!(tlv.tlv_type_field(), TlvTypeField::Custom(3)); assert_eq!(tlv.tlv_type_field(), TlvTypeField::Custom(3));
assert_eq!(tlv.len_value(), 1); assert_eq!(tlv.value().len(), 1);
assert_eq!(tlv.len_full(), 3); assert_eq!(tlv.len_full(), 3);
} }

View File

@ -0,0 +1,90 @@
use delegate::delegate;
use crate::ByteConversionError;
use super::{TlvLvError, Tlv, TlvType, TlvTypeField};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct MsgToUserTlv<'data> {
pub tlv: Tlv<'data>,
}
impl<'data> MsgToUserTlv<'data> {
/// Create a new message to user TLV where the type field is set correctly.
pub fn new(value: &'data [u8]) -> Result<MsgToUserTlv<'data>, TlvLvError> {
Ok(Self {
tlv: Tlv::new(TlvType::MsgToUser, value)?
})
}
delegate! {
to self.tlv {
pub fn tlv_type_field(&self) -> TlvTypeField;
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError>;
pub fn value(&self) -> &[u8];
/// Helper method to retrieve the length of the value. Simply calls the [slice::len] method of
/// [Self::value]
pub fn len_value(&self) -> usize;
/// Returns the full raw length, including the length byte.
pub fn len_full(&self) -> usize;
/// Checks whether the value field is empty.
pub fn is_empty(&self) -> bool;
/// If the TLV was generated from a raw bytestream using [Self::from_bytes], the raw start
/// of the TLV can be retrieved with this method.
pub fn raw_data(&self) -> Option<&[u8]>;
}
}
pub fn is_standard_tlv(&self) -> bool {
true
}
pub fn tlv_type(&self) -> Option<TlvType> {
Some(TlvType::MsgToUser)
}
/// This is a thin wrapper around [Tlv::from_bytes] with the additional type check.
pub fn from_bytes(buf: &'data [u8]) -> Result<MsgToUserTlv<'data>, TlvLvError> {
let msg_to_user = Self {
tlv: Tlv::from_bytes(buf)?,
};
match msg_to_user.tlv_type_field() {
TlvTypeField::Standard(tlv_type) => {
if tlv_type != TlvType::MsgToUser {
return Err(TlvLvError::InvalidTlvTypeField((
tlv_type as u8,
Some(TlvType::MsgToUser as u8),
)));
}
}
TlvTypeField::Custom(raw) => {
return Err(TlvLvError::InvalidTlvTypeField((
raw,
Some(TlvType::MsgToUser as u8),
)));
}
}
Ok(msg_to_user)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic() {
let custom_value: [u8; 4] = [1, 2, 3, 4];
let msg_to_user = MsgToUserTlv::new(&custom_value);
assert!(msg_to_user.is_ok());
let msg_to_user = msg_to_user.unwrap();
assert!(msg_to_user.is_standard_tlv());
assert_eq!(msg_to_user.tlv_type().unwrap(), TlvType::MsgToUser);
assert_eq!(msg_to_user.value(), custom_value);
assert_eq!(msg_to_user.value().len(), 4);
assert_eq!(msg_to_user.len_value(), 4);
assert_eq!(msg_to_user.len_full(), 5);
assert!(!msg_to_user.is_empty());
assert!(msg_to_user.raw_data().is_none());
}
}