use thiserror::Error;
#[derive(Error, Debug)]
pub enum DdsError {
#[error("Unknown representation identifier `{0:?}`")]
UnknownIdentifier([u8; 2]),
#[error("Invalid first byte got `{0}`, but it should always be `0x00`")]
InvalidFirstByte(u8),
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RepresentationIdentifier {
CdrBigEndian = 0x00,
CdrLittleEndian = 0x01,
ParameterListBigEndian = 0x02,
ParameterListLittleEndian = 0x03,
Xml = 0x04,
Cdr2BigEndian = 0x10,
Cdr2LittleEndian = 0x11,
ParameterListCdr2BigEndian = 0x12,
ParameterListCdr2LittleEndian = 0x13,
DelimitedCdrBigEndian = 0x14,
DelimitedCdrLittleEndian = 0x15,
}
impl RepresentationIdentifier {
pub fn from_bytes(bytes: [u8; 2]) -> Result<Self, DdsError> {
if bytes[0] != 0x00 {
return Err(DdsError::InvalidFirstByte(bytes[0]));
}
Self::from_second_byte(bytes[1]).ok_or(DdsError::UnknownIdentifier(bytes))
}
pub fn from_second_byte(second_byte: u8) -> Option<Self> {
match second_byte {
0x00 => Some(Self::CdrBigEndian),
0x01 => Some(Self::CdrLittleEndian),
0x02 => Some(Self::ParameterListBigEndian),
0x03 => Some(Self::ParameterListLittleEndian),
0x04 => Some(Self::Xml),
0x10 => Some(Self::Cdr2BigEndian),
0x11 => Some(Self::Cdr2LittleEndian),
0x12 => Some(Self::ParameterListCdr2BigEndian),
0x13 => Some(Self::ParameterListCdr2LittleEndian),
0x14 => Some(Self::DelimitedCdrBigEndian),
0x15 => Some(Self::DelimitedCdrLittleEndian),
_ => None,
}
}
pub fn to_bytes(self) -> [u8; 2] {
[0x00, self as u8]
}
pub fn is_big_endian(self) -> bool {
matches!(
self,
Self::CdrBigEndian
| Self::ParameterListBigEndian
| Self::Cdr2BigEndian
| Self::ParameterListCdr2BigEndian
| Self::DelimitedCdrBigEndian
)
}
pub fn is_little_endian(self) -> bool {
matches!(
self,
Self::CdrLittleEndian
| Self::ParameterListLittleEndian
| Self::Cdr2LittleEndian
| Self::ParameterListCdr2LittleEndian
| Self::DelimitedCdrLittleEndian
)
}
pub fn is_cdr(self) -> bool {
matches!(self, Self::CdrBigEndian | Self::CdrLittleEndian)
}
pub fn is_cdr2(self) -> bool {
matches!(
self,
Self::Cdr2BigEndian
| Self::Cdr2LittleEndian
| Self::ParameterListCdr2BigEndian
| Self::ParameterListCdr2LittleEndian
| Self::DelimitedCdrBigEndian
| Self::DelimitedCdrLittleEndian
)
}
pub fn is_parameter_list(self) -> bool {
matches!(
self,
Self::ParameterListBigEndian | Self::ParameterListLittleEndian
)
}
pub fn is_parameter_list_cdr2(self) -> bool {
matches!(
self,
Self::ParameterListCdr2BigEndian | Self::ParameterListCdr2LittleEndian
)
}
pub fn is_delimited_cdr(self) -> bool {
matches!(
self,
Self::DelimitedCdrBigEndian | Self::DelimitedCdrLittleEndian
)
}
pub fn is_xml(self) -> bool {
matches!(self, Self::Xml)
}
pub fn has_endianness(self) -> bool {
!self.is_xml()
}
}
impl TryFrom<[u8; 2]> for RepresentationIdentifier {
type Error = DdsError;
fn try_from(bytes: [u8; 2]) -> Result<Self, Self::Error> {
Self::from_bytes(bytes)
}
}
impl TryFrom<u8> for RepresentationIdentifier {
type Error = u8;
fn try_from(second_byte: u8) -> Result<Self, Self::Error> {
Self::from_second_byte(second_byte).ok_or(second_byte)
}
}
impl From<RepresentationIdentifier> for [u8; 2] {
fn from(repr: RepresentationIdentifier) -> Self {
repr.to_bytes()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_bytes() {
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x00]).unwrap(),
RepresentationIdentifier::CdrBigEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x01]).unwrap(),
RepresentationIdentifier::CdrLittleEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x02]).unwrap(),
RepresentationIdentifier::ParameterListBigEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x03]).unwrap(),
RepresentationIdentifier::ParameterListLittleEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x04]).unwrap(),
RepresentationIdentifier::Xml
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x10]).unwrap(),
RepresentationIdentifier::Cdr2BigEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x11]).unwrap(),
RepresentationIdentifier::Cdr2LittleEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x12]).unwrap(),
RepresentationIdentifier::ParameterListCdr2BigEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x13]).unwrap(),
RepresentationIdentifier::ParameterListCdr2LittleEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x14]).unwrap(),
RepresentationIdentifier::DelimitedCdrBigEndian
);
assert_eq!(
RepresentationIdentifier::from_bytes([0x00, 0x15]).unwrap(),
RepresentationIdentifier::DelimitedCdrLittleEndian
);
}
#[test]
fn test_from_second_byte() {
assert_eq!(
RepresentationIdentifier::from_second_byte(0x00).unwrap(),
RepresentationIdentifier::CdrBigEndian
);
assert_eq!(
RepresentationIdentifier::from_second_byte(0x04).unwrap(),
RepresentationIdentifier::Xml
);
assert_eq!(
RepresentationIdentifier::from_second_byte(0x15).unwrap(),
RepresentationIdentifier::DelimitedCdrLittleEndian
);
assert!(RepresentationIdentifier::from_second_byte(0xFF).is_none());
}
#[test]
fn test_invalid_first_byte() {
let result = RepresentationIdentifier::from_bytes([0x01, 0x00]);
assert!(matches!(result, Err(DdsError::InvalidFirstByte(0x01))));
}
#[test]
fn test_unknown_identifier() {
let result = RepresentationIdentifier::from_bytes([0x00, 0xFF]);
assert!(matches!(
result,
Err(DdsError::UnknownIdentifier([0x00, 0xFF]))
));
}
#[test]
fn test_to_bytes() {
assert_eq!(
RepresentationIdentifier::CdrBigEndian.to_bytes(),
[0x00, 0x00]
);
assert_eq!(
RepresentationIdentifier::CdrLittleEndian.to_bytes(),
[0x00, 0x01]
);
assert_eq!(
RepresentationIdentifier::ParameterListBigEndian.to_bytes(),
[0x00, 0x02]
);
assert_eq!(
RepresentationIdentifier::ParameterListLittleEndian.to_bytes(),
[0x00, 0x03]
);
assert_eq!(RepresentationIdentifier::Xml.to_bytes(), [0x00, 0x04]);
assert_eq!(
RepresentationIdentifier::Cdr2BigEndian.to_bytes(),
[0x00, 0x10]
);
assert_eq!(
RepresentationIdentifier::Cdr2LittleEndian.to_bytes(),
[0x00, 0x11]
);
assert_eq!(
RepresentationIdentifier::ParameterListCdr2BigEndian.to_bytes(),
[0x00, 0x12]
);
assert_eq!(
RepresentationIdentifier::ParameterListCdr2LittleEndian.to_bytes(),
[0x00, 0x13]
);
assert_eq!(
RepresentationIdentifier::DelimitedCdrBigEndian.to_bytes(),
[0x00, 0x14]
);
assert_eq!(
RepresentationIdentifier::DelimitedCdrLittleEndian.to_bytes(),
[0x00, 0x15]
);
}
#[test]
fn test_endianness_checks() {
assert!(RepresentationIdentifier::CdrBigEndian.is_big_endian());
assert!(!RepresentationIdentifier::CdrBigEndian.is_little_endian());
assert!(RepresentationIdentifier::ParameterListBigEndian.is_big_endian());
assert!(RepresentationIdentifier::Cdr2BigEndian.is_big_endian());
assert!(RepresentationIdentifier::ParameterListCdr2BigEndian.is_big_endian());
assert!(RepresentationIdentifier::DelimitedCdrBigEndian.is_big_endian());
assert!(!RepresentationIdentifier::CdrLittleEndian.is_big_endian());
assert!(RepresentationIdentifier::CdrLittleEndian.is_little_endian());
assert!(RepresentationIdentifier::ParameterListLittleEndian.is_little_endian());
assert!(RepresentationIdentifier::Cdr2LittleEndian.is_little_endian());
assert!(RepresentationIdentifier::ParameterListCdr2LittleEndian.is_little_endian());
assert!(RepresentationIdentifier::DelimitedCdrLittleEndian.is_little_endian());
assert!(!RepresentationIdentifier::Xml.is_big_endian());
assert!(!RepresentationIdentifier::Xml.is_little_endian());
assert!(!RepresentationIdentifier::Xml.has_endianness());
}
}