extern crate alloc;
use alloc::vec::Vec;
use crate::error::XrceError;
use crate::submessages::{FLAG_E_LITTLE_ENDIAN, Submessage, SubmessageId};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[repr(u8)]
#[allow(missing_docs)]
pub enum DataFormat {
#[default]
Data = 0b000,
Sample = 0b001,
DataSeq = 0b100,
SampleSeq = 0b101,
PackedSamples = 0b111,
}
impl DataFormat {
#[must_use]
pub fn to_flag_bits(self) -> u8 {
(self as u8) << 1
}
pub fn from_flag_bits(flags: u8) -> Result<Self, XrceError> {
match (flags >> 1) & 0b111 {
0b000 => Ok(Self::Data),
0b001 => Ok(Self::Sample),
0b100 => Ok(Self::DataSeq),
0b101 => Ok(Self::SampleSeq),
0b111 => Ok(Self::PackedSamples),
_ => Err(XrceError::ValueOutOfRange {
message: "reserved DataFormat bit pattern",
}),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct WriteDataPayload {
pub representation: Vec<u8>,
pub data_format: DataFormat,
}
impl WriteDataPayload {
#[must_use]
pub fn flags(&self) -> u8 {
FLAG_E_LITTLE_ENDIAN | self.data_format.to_flag_bits()
}
pub fn into_submessage(self) -> Result<Submessage, XrceError> {
let flags = self.flags();
Submessage::new(SubmessageId::WriteData, flags, self.representation)
}
pub fn try_from_submessage(sm: &Submessage) -> Result<Self, XrceError> {
if sm.header.submessage_id != SubmessageId::WriteData {
return Err(XrceError::ValueOutOfRange {
message: "submessage is not WRITE_DATA",
});
}
let data_format = DataFormat::from_flag_bits(sm.header.flags)?;
Ok(Self {
representation: sm.body.clone(),
data_format,
})
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, clippy::unwrap_used)]
use super::*;
#[test]
fn write_data_roundtrip_format_data() {
let p = WriteDataPayload {
representation: alloc::vec![1, 2, 3, 4],
data_format: DataFormat::Data,
};
let sm = p.clone().into_submessage().unwrap();
let p2 = WriteDataPayload::try_from_submessage(&sm).unwrap();
assert_eq!(p2, p);
}
#[test]
fn write_data_roundtrip_all_formats() {
for fmt in [
DataFormat::Data,
DataFormat::Sample,
DataFormat::DataSeq,
DataFormat::SampleSeq,
DataFormat::PackedSamples,
] {
let p = WriteDataPayload {
representation: alloc::vec![0; 8],
data_format: fmt,
};
let sm = p.clone().into_submessage().unwrap();
let p2 = WriteDataPayload::try_from_submessage(&sm).unwrap();
assert_eq!(p2.data_format, fmt);
}
}
#[test]
fn write_data_reserved_format_rejected() {
let bad_flags = FLAG_E_LITTLE_ENDIAN | (0b010 << 1);
let sm = Submessage::new(SubmessageId::WriteData, bad_flags, alloc::vec![]).unwrap();
let res = WriteDataPayload::try_from_submessage(&sm);
assert!(matches!(res, Err(XrceError::ValueOutOfRange { .. })));
}
}