use std::marker::PhantomData;
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt};
use serde::de::{
self, DeserializeOwned, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
VariantAccess, Visitor,
};
use paste::paste;
use crate::{
dds::adapters::{no_key, with_key},
Keyed, RepresentationIdentifier,
};
pub struct CDRDeserializerAdapter<D> {
phantom: PhantomData<D>,
}
const REPR_IDS: [RepresentationIdentifier; 3] = [
RepresentationIdentifier::CDR_BE,
RepresentationIdentifier::CDR_LE,
RepresentationIdentifier::PL_CDR_LE,
];
impl<D> no_key::DeserializerAdapter<D> for CDRDeserializerAdapter<D> {
type Error = Error;
type Decoded = D;
fn supported_encodings() -> &'static [RepresentationIdentifier] {
&REPR_IDS
}
fn transform_decoded(decoded: Self::Decoded) -> D {
decoded
}
}
impl<D> with_key::DeserializerAdapter<D> for CDRDeserializerAdapter<D>
where
D: Keyed + DeserializeOwned,
<D as Keyed>::K: DeserializeOwned, {
type DecodedKey = D::K;
fn transform_decoded_key(decoded_key: Self::DecodedKey) -> D::K {
decoded_key
}
}
impl<'de, D> no_key::DefaultDecoder<D> for CDRDeserializerAdapter<D>
where
D: serde::Deserialize<'de>,
{
type Decoder = CdrDeserializeDecoder<D>;
const DECODER: Self::Decoder = CdrDeserializeDecoder(PhantomData);
}
impl<D> with_key::DefaultDecoder<D> for CDRDeserializerAdapter<D>
where
D: Keyed + DeserializeOwned,
D::K: DeserializeOwned,
{
type Decoder = CdrDeserializeDecoder<D>;
const DECODER: Self::Decoder = CdrDeserializeDecoder(PhantomData);
}
pub struct CdrDeserializeDecoder<D>(PhantomData<D>);
impl<'de, D> no_key::Decode<D> for CdrDeserializeDecoder<D>
where
D: serde::Deserialize<'de>,
{
type Error = Error;
fn decode_bytes(self, input_bytes: &[u8], encoding: RepresentationIdentifier) -> Result<D> {
deserialize_from_cdr(input_bytes, encoding).map(|(d, _size)| d)
}
}
impl<Dec, DecKey> with_key::Decode<Dec, DecKey> for CdrDeserializeDecoder<Dec>
where
Dec: DeserializeOwned,
DecKey: DeserializeOwned,
{
fn decode_key_bytes(
self,
input_key_bytes: &[u8],
encoding: RepresentationIdentifier,
) -> Result<DecKey> {
deserialize_from_cdr(input_key_bytes, encoding).map(|(d, _size)| d)
}
}
impl<D> Clone for CdrDeserializeDecoder<D> {
fn clone(&self) -> Self {
Self(self.0)
}
}
#[derive(Clone)]
pub struct CdrDeserializeSeedDecoder<S, SK> {
value_seed: S,
key_seed: SK,
}
impl<'de, S, SK> CdrDeserializeSeedDecoder<S, SK>
where
S: serde::de::DeserializeSeed<'de>,
SK: serde::de::DeserializeSeed<'de>,
{
pub fn new(value_seed: S, key_seed: SK) -> Self {
Self {
value_seed,
key_seed,
}
}
}
impl<'de, D, S, SK> no_key::Decode<D> for CdrDeserializeSeedDecoder<S, SK>
where
S: serde::de::DeserializeSeed<'de, Value = D>,
{
type Error = Error;
fn decode_bytes(self, input_bytes: &[u8], encoding: RepresentationIdentifier) -> Result<D> {
deserialize_from_cdr_with(input_bytes, encoding, self.value_seed).map(|(d, _size)| d)
}
}
impl<'de, Dec, DecKey, S, SK> with_key::Decode<Dec, DecKey> for CdrDeserializeSeedDecoder<S, SK>
where
S: serde::de::DeserializeSeed<'de, Value = Dec>,
SK: serde::de::DeserializeSeed<'de, Value = DecKey>,
{
fn decode_key_bytes(
self,
input_key_bytes: &[u8],
encoding: RepresentationIdentifier,
) -> Result<DecKey> {
deserialize_from_cdr_with(input_key_bytes, encoding, self.key_seed).map(|(d, _size)| d)
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Deserializer does not support this operation: {0}")]
NotSupported(String),
#[error("unexpected end of input")]
Eof,
#[error("Expected 0 or 1 as Boolean, got: {0}")]
BadBoolean(u8),
#[error("UTF-8 error: {0}")]
BadUTF8(std::str::Utf8Error),
#[error("Bad Unicode character code: {0}")]
BadChar(u32), #[error("Option value must have discriminant 0 or 1, read: {0}")]
BadOption(u32), #[error("Trailing garbage, {:?} bytes", .0.len())]
TrailingCharacters(Vec<u8>),
#[error("Serde says: {0}")]
Serde(String),
}
impl de::Error for Error {
fn custom<T: std::fmt::Display>(msg: T) -> Self {
Self::Serde(msg.to_string())
}
}
pub struct CdrDeserializer<'i, BO> {
phantom: PhantomData<BO>, input: &'i [u8], serialized_data_count: usize, }
impl<'de, BO> CdrDeserializer<'de, BO>
where
BO: ByteOrder,
{
pub fn new_little_endian(input: &[u8]) -> CdrDeserializer<LittleEndian> {
CdrDeserializer::<LittleEndian>::new(input)
}
pub fn new_big_endian(input: &[u8]) -> CdrDeserializer<BigEndian> {
CdrDeserializer::<BigEndian>::new(input)
}
pub fn new(input: &'de [u8]) -> CdrDeserializer<'de, BO> {
CdrDeserializer::<BO> {
phantom: PhantomData,
input,
serialized_data_count: 0,
}
}
fn next_bytes(&mut self, count: usize) -> Result<&[u8]> {
if count <= self.input.len() {
let (head, tail) = self.input.split_at(count);
self.input = tail;
self.serialized_data_count += count;
Ok(head)
} else {
Err(Error::Eof)
}
}
fn remove_bytes_from_input(&mut self, count: usize) -> Result<()> {
let _pad = self.next_bytes(count)?;
Ok(())
}
fn calculate_padding_count_from_written_bytes_and_remove(
&mut self,
type_octet_alignment: usize,
) -> Result<()> {
let modulo = self.serialized_data_count % type_octet_alignment;
if modulo == 0 {
Ok(())
} else {
let padding = type_octet_alignment - modulo;
self.remove_bytes_from_input(padding)
}
}
}
pub fn deserialize_from_cdr<'de, T>(
input_bytes: &[u8],
encoding: RepresentationIdentifier,
) -> Result<(T, usize)>
where
T: serde::Deserialize<'de>,
{
deserialize_from_cdr_with(input_bytes, encoding, PhantomData)
}
pub fn deserialize_from_cdr_with<'de, S>(
input_bytes: &[u8],
encoding: RepresentationIdentifier,
decoder: S,
) -> Result<(S::Value, usize)>
where
S: DeserializeSeed<'de>,
{
match encoding {
RepresentationIdentifier::CDR_LE | RepresentationIdentifier::PL_CDR_LE => {
let mut deserializer = CdrDeserializer::<LittleEndian>::new(input_bytes);
let t = decoder.deserialize(&mut deserializer)?;
Ok((t, deserializer.serialized_data_count))
}
RepresentationIdentifier::CDR_BE | RepresentationIdentifier::PL_CDR_BE => {
let mut deserializer = CdrDeserializer::<BigEndian>::new(input_bytes);
let t = decoder.deserialize(&mut deserializer)?;
Ok((t, deserializer.serialized_data_count))
}
repr_id => Err(Error::NotSupported(format!(
"Unknown serialization format. requested={:?}.",
repr_id
))),
}
}
#[cfg(test)]
pub fn deserialize_from_little_endian<T>(s: &[u8]) -> Result<T>
where
T: DeserializeOwned,
{
let mut deserializer = CdrDeserializer::<LittleEndian>::new(s);
T::deserialize(&mut deserializer)
}
#[cfg(test)]
pub fn deserialize_from_big_endian<T>(s: &[u8]) -> Result<T>
where
T: DeserializeOwned,
{
let mut deserializer = CdrDeserializer::<BigEndian>::new(s);
T::deserialize(&mut deserializer)
}
macro_rules! deserialize_multibyte_number {
($num_type:ident) => {
paste! {
fn [<deserialize_ $num_type>]<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
const SIZE :usize = std::mem::size_of::<$num_type>();
static_assertions::const_assert!(SIZE > 1); self.calculate_padding_count_from_written_bytes_and_remove(SIZE)?;
visitor.[<visit_ $num_type>](
self.next_bytes(SIZE)?.[<read_ $num_type>]::<BO>().unwrap() )
}
}
};
}
impl<'de, 'a, 'c, BO> de::Deserializer<'de> for &'a mut CdrDeserializer<'c, BO>
where
BO: ByteOrder,
{
type Error = Error;
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
Err(Error::NotSupported(
"CDR cannot deserialize \"any\" type. ".to_string(),
))
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.next_bytes(1)?.first().unwrap() {
0 => visitor.visit_bool(false),
1 => visitor.visit_bool(true),
x => Err(Error::BadBoolean(*x)),
}
}
deserialize_multibyte_number!(i16);
deserialize_multibyte_number!(i32);
deserialize_multibyte_number!(i64);
deserialize_multibyte_number!(u16);
deserialize_multibyte_number!(u32);
deserialize_multibyte_number!(u64);
deserialize_multibyte_number!(f32);
deserialize_multibyte_number!(f64);
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_i8(self.next_bytes(1)?.read_i8().unwrap())
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_u8(self.next_bytes(1)?.read_u8().unwrap())
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.calculate_padding_count_from_written_bytes_and_remove(4)?;
let codepoint = self.next_bytes(4)?.read_u32::<BO>().unwrap();
match Some(codepoint as u8 as char) {
Some(c) => visitor.visit_char(c),
None => Err(Error::BadChar(codepoint)),
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.calculate_padding_count_from_written_bytes_and_remove(4)?;
let bytes_len = self.next_bytes(4)?.read_u32::<BO>().unwrap() as usize;
let bytes = self.next_bytes(bytes_len)?; let bytes_without_null = match bytes.split_last() {
None => {
info!("deserialize_str: Received string with not even a null terminator.");
bytes
}
Some((null_char, contents)) => {
if *null_char != 0 {
warn!(
"deserialize_str: Expected string null terminator, got {:#x} instead.",
null_char
);
}
contents
}
};
std::str::from_utf8(bytes_without_null)
.map_err(Error::BadUTF8)
.and_then(|s| visitor.visit_str(s))
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.calculate_padding_count_from_written_bytes_and_remove(4)?;
let enum_tag = self.next_bytes(4)?.read_u32::<BO>().unwrap();
match enum_tag {
0 => visitor.visit_none(),
1 => visitor.visit_some(self),
wtf => Err(Error::BadOption(wtf)),
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor) }
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.calculate_padding_count_from_written_bytes_and_remove(4)?;
let element_count = self.next_bytes(4)?.read_u32::<BO>().unwrap() as usize;
visitor.visit_seq(SequenceHelper::new(self, element_count))
}
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_seq(SequenceHelper::new(self, len))
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_seq(SequenceHelper::new(self, len))
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.calculate_padding_count_from_written_bytes_and_remove(4)?;
let element_count = self.next_bytes(4)?.read_u32::<BO>().unwrap() as usize;
visitor.visit_map(SequenceHelper::new(self, element_count))
}
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_seq(SequenceHelper::new(self, fields.len()))
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.calculate_padding_count_from_written_bytes_and_remove(4)?;
visitor.visit_enum(EnumerationHelper::<BO>::new(self))
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_u32(visitor)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
struct EnumerationHelper<'a, 'i: 'a, BO> {
de: &'a mut CdrDeserializer<'i, BO>,
}
impl<'a, 'i, BO> EnumerationHelper<'a, 'i, BO>
where
BO: ByteOrder,
{
fn new(de: &'a mut CdrDeserializer<'i, BO>) -> Self {
EnumerationHelper::<BO> { de }
}
}
impl<'de, 'a, BO> EnumAccess<'de> for EnumerationHelper<'a, '_, BO>
where
BO: ByteOrder,
{
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: DeserializeSeed<'de>,
{
let enum_tag = self.de.next_bytes(4)?.read_u32::<BO>().unwrap();
let val: Result<_> = seed.deserialize(enum_tag.into_deserializer());
Ok((val?, self))
}
}
impl<'de, 'a, BO> VariantAccess<'de> for EnumerationHelper<'a, '_, BO>
where
BO: ByteOrder,
{
type Error = Error;
fn unit_variant(self) -> Result<()> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(self.de)
}
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
de::Deserializer::deserialize_tuple(self.de, len, visitor)
}
fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
de::Deserializer::deserialize_tuple(self.de, fields.len(), visitor)
}
}
struct SequenceHelper<'a, 'i: 'a, BO> {
de: &'a mut CdrDeserializer<'i, BO>,
element_counter: usize,
expected_count: usize,
}
impl<'a, 'i, BO> SequenceHelper<'a, 'i, BO> {
fn new(de: &'a mut CdrDeserializer<'i, BO>, expected_count: usize) -> Self {
SequenceHelper {
de,
element_counter: 0,
expected_count,
}
}
}
impl<'a, 'de, BO> SeqAccess<'de> for SequenceHelper<'a, '_, BO>
where
BO: ByteOrder,
{
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
if self.element_counter == self.expected_count {
Ok(None)
} else {
self.element_counter += 1;
seed.deserialize(&mut *self.de).map(Some)
}
}
}
impl<'de, 'a, BO> MapAccess<'de> for SequenceHelper<'a, '_, BO>
where
BO: ByteOrder,
{
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: DeserializeSeed<'de>,
{
if self.element_counter == self.expected_count {
Ok(None)
} else {
self.element_counter += 1;
seed.deserialize(&mut *self.de).map(Some)
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: DeserializeSeed<'de>,
{
seed.deserialize(&mut *self.de)
}
}
#[cfg(test)]
#[allow(clippy::needless_pass_by_value)]
mod tests {
use byteorder::{BigEndian, LittleEndian};
use log::info;
use serde::{Deserialize, Serialize};
use test_case::test_case;
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::{
serialization::{
cdr_deserializer::{deserialize_from_big_endian, deserialize_from_little_endian},
cdr_serializer::to_bytes,
deserialize_from_cdr,
},
RepresentationIdentifier,
};
#[test]
fn cdr_deserialization_struct() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct MyType {
first_value: u8,
second_value: i8,
third_value: i32,
fourth_value: u64,
fifth: bool,
sixth: f32,
seventh: bool,
eighth: Vec<i32>,
ninth: Vec<u8>,
tenth: Vec<i16>,
eleventh: Vec<i64>,
twelve: [u16; 3],
thirteen: String,
}
let micky_mouse = MyType {
first_value: 1,
second_value: -3,
third_value: -5000,
fourth_value: 1234u64,
fifth: true,
sixth: -6.6f32,
seventh: true,
eighth: vec![1, 2],
ninth: vec![1],
tenth: vec![5, -4, 3, -2, 1],
eleventh: vec![],
twelve: [3, 2, 1],
thirteen: "abc".to_string(),
};
let expected_serialized_result: Vec<u8> = vec![
0x01, 0xfd, 0x00, 0x00, 0x78, 0xec, 0xff, 0xff, 0xd2, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x33, 0x33, 0xd3, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xfc, 0xff, 0x03, 0x00, 0xfe, 0xff,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x00,
];
let serialized = to_bytes::<MyType, LittleEndian>(&micky_mouse).unwrap();
for x in 0..expected_serialized_result.len() {
if expected_serialized_result[x] != serialized[x] {
info!("index: {}", x);
}
}
assert_eq!(serialized, expected_serialized_result);
info!("serialization successful!");
let built: MyType = deserialize_from_little_endian(&expected_serialized_result).unwrap();
assert_eq!(built, micky_mouse);
info!("deserialized: {:?}", built);
}
#[test]
fn cdr_deserialization_user_defined_data() {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
struct ShapeType {
color: String,
x: i32,
y: i32,
size: i32,
}
let message = ShapeType {
color: "BLUE".to_string(),
x: 34,
y: 100,
size: 24,
};
let expected_serialized_result: Vec<u8> = vec![
0x05, 0x00, 0x00, 0x00, 0x42, 0x4c, 0x55, 0x45, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00,
0x00, 0x64, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
];
let serialized = to_bytes::<ShapeType, LittleEndian>(&message).unwrap();
assert_eq!(serialized, expected_serialized_result);
let deserialized_message: ShapeType = deserialize_from_little_endian(&serialized).unwrap();
assert_eq!(deserialized_message, message);
}
#[test]
fn cdr_deserialization_serialization_topic_name() {
let received_cdr_string: Vec<u8> = vec![
0x07, 0x00, 0x00, 0x00, 0x053, 0x71, 0x75, 0x61, 0x72, 0x65, 0x00, ];
let deserialized_message: String =
deserialize_from_little_endian(&received_cdr_string).unwrap();
info!("{:?}", deserialized_message);
assert_eq!("Square", deserialized_message);
let received_cdr_string2: Vec<u8> = vec![
0x0A, 0x00, 0x00, 0x00, 0x53, 0x68, 0x61, 0x70, 0x65, 0x54, 0x79, 0x70, 0x65,
0x00, ];
let deserialized_message2: String =
deserialize_from_little_endian(&received_cdr_string2).unwrap();
info!("{:?}", deserialized_message2);
assert_eq!("ShapeType", deserialized_message2);
}
#[test]
fn cdr_deserialization_example_struct() {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
struct Example {
a: u32,
b: [u8; 4],
}
let o = Example {
a: 1,
b: [b'a', b'b', b'c', b'd'],
};
let serialized_le: Vec<u8> = vec![0x01, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64];
let serialized_be: Vec<u8> = vec![0x00, 0x00, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64];
let deserialized_le: Example = deserialize_from_little_endian(&serialized_le).unwrap();
let deserialized_be: Example = deserialize_from_big_endian(&serialized_be).unwrap();
let serialized_o_le = to_bytes::<Example, LittleEndian>(&o).unwrap();
let serialized_o_be = to_bytes::<Example, BigEndian>(&o).unwrap();
assert_eq!(
serialized_o_le,
vec![0x01, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64,]
);
assert_eq!(
serialized_o_be,
vec![0x00, 0x00, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64,]
);
info!("serialization success");
assert_eq!(deserialized_le, o);
assert_eq!(deserialized_be, o);
info!("deserialization success");
}
#[test]
fn cdr_deserialization_serialization_payload_shapes() {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
struct ShapeType {
color: String,
x: i32,
y: i32,
size: i32,
}
let received_message: Vec<u8> = vec![
0x04, 0x00, 0x00, 0x00, 0x52, 0x45, 0x44, 0x00, 0x61, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00,
];
let received_message2: Vec<u8> = vec![
0x04, 0x00, 0x00, 0x00, 0x52, 0x45, 0x44, 0x00, 0x61, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00,
];
let deserialized_message: ShapeType =
deserialize_from_little_endian(&received_message).unwrap();
info!("{:?}", deserialized_message);
let serialized_message = to_bytes::<ShapeType, LittleEndian>(&deserialized_message).unwrap();
assert_eq!(serialized_message, received_message2);
}
#[test]
fn cdr_deserialization_custom_data_message_from_ros_and_wireshark() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct MessageType {
x: f64,
y: f64,
heading: f64,
v_x: f64,
v_y: f64,
kappa: f64,
test: String,
}
let received_message_le: Vec<u8> = vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x85, 0xeb, 0x51, 0xb8,
0x1e, 0xd5, 0x3f, 0x0a, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x69, 0x6d, 0x69, 0x69, 0x6b, 0x6f,
0x3f, 0x00, ];
let value: MessageType = deserialize_from_little_endian(&received_message_le).unwrap();
info!("{:?}", value);
assert_eq!(value.test, "Toimiiko?");
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct InterestingMessage {
unbounded_string: String,
x: i32,
y: i32,
shape_size: i32,
slide: f32,
double_slide: f64,
three_short: [u16; 3],
four_short: [i16; 4],
booleans: Vec<bool>,
three_bytes: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum BigEnum {
Interesting(InterestingMessage),
Boring,
Something { x: f32, y: f32 },
}
#[test]
fn cdr_deserialization_custom_type() {
let value = InterestingMessage {
unbounded_string: "Tassa on aika pitka teksti".to_string(), x: 2,
y: -3,
shape_size: -4,
slide: 5.5,
double_slide: -6.6,
three_short: [1, 2, 3],
four_short: [1, -2, -3, 4],
booleans: vec![true, false, true],
three_bytes: [23, 0, 2].to_vec(),
};
const DATA: &[u8] = &[
0x1b, 0x00, 0x00, 0x00, 0x54, 0x61, 0x73, 0x73, 0x61, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x69,
0x6b, 0x61, 0x20, 0x70, 0x69, 0x74, 0x6b, 0x61, 0x20, 0x74, 0x65, 0x6b, 0x73, 0x74, 0x69,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x00,
0x00, 0xb0, 0x40, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x1a, 0xc0, 0x01, 0x00, 0x02, 0x00,
0x03, 0x00, 0x01, 0x00, 0xfe, 0xff, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x02,
];
let serialization_result_le = to_bytes::<InterestingMessage, LittleEndian>(&value).unwrap();
assert_eq!(serialization_result_le, DATA);
info!("serialization success!");
let deserialization_result: InterestingMessage = deserialize_from_little_endian(DATA).unwrap();
info!("{:?}", deserialization_result);
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
enum SomeTupleEnum {
A(i32),
B(i32),
C(i32),
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
enum MixedEnum {
A(i32),
B { value: i32 },
C(i32, i32),
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(i8)]
pub enum GoalStatusEnum {
Unknown = 0, Accepted = 1,
Executing = 2,
Canceling = 3,
Succeeded = 4,
Canceled = 5,
Aborted = 6,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
struct AlignMe {
some_bytes: [u8; 4],
status: i8,
}
#[test_case(35_u8 ; "u8")]
#[test_case(35_u16 ; "u16")]
#[test_case(352323_u32 ; "u32")]
#[test_case(352323232_u64 ; "u64")]
#[test_case(-3_i8 ; "i8")]
#[test_case(-3_i16 ; "i16")]
#[test_case(-323232_i32 ; "i32")]
#[test_case(-3232323434_i64 ; "i64")]
#[test_case(true)]
#[test_case(false)]
#[test_case(2.35_f32 ; "f32")]
#[test_case(278.35_f64 ; "f64")]
#[test_case('a' ; "char")]
#[test_case("BLUE".to_string() ; "string")]
#[test_case(vec![1_i32, -2_i32, 3_i32] ; "Vec<i32>")]
#[test_case(InterestingMessage {
unbounded_string: "Here is a fairly long text".to_string(),
x: 2,
y: -3,
shape_size: -4,
slide: 5.5,
double_slide: -6.6,
three_short: [1, 2, 3],
four_short: [1, -2, -3, 4],
booleans: vec![true, false, true],
three_bytes: [23, 0, 2].to_vec(),
} ; "InterestingMessage")]
#[test_case( BigEnum::Boring ; "BigEnum::Boring")]
#[test_case( BigEnum::Interesting(InterestingMessage {
unbounded_string: "Here is a fairly long text".to_string(),
x: 2,
y: -3,
shape_size: -4,
slide: 5.5,
double_slide: -6.6,
three_short: [1, 2, 3],
four_short: [1, -2, -3, 4],
booleans: vec![true, false, true],
three_bytes: [23, 0, 2].to_vec(),
}) ; "BigEnum::Interesting")]
#[test_case( BigEnum::Something{ x:123.0, y:-0.1 } ; "BigEnum::Something")]
#[test_case( SomeTupleEnum::A(123) ; "SomeTupleEnum::A")]
#[test_case( SomeTupleEnum::B(1234) ; "SomeTupleEnum::B")]
#[test_case( SomeTupleEnum::C(-1) ; "SomeTupleEnum::C")]
#[test_case( MixedEnum::A(123) ; "MixedEnum::A")]
#[test_case( MixedEnum::B{ value:1234 } ; "MixedEnum::B")]
#[test_case( MixedEnum::C(42,43) ; "MixedEnum::C")]
#[test_case( GoalStatusEnum::Accepted ; "GoalStatusEnum::Accepted")]
#[test_case( [AlignMe{some_bytes: [1,2,3,4], status:10 } ,
AlignMe{some_bytes: [5,6,7,8], status:11 } ] ; "AlignMeArray")]
fn cdr_serde_round_trip<T>(input: T)
where
T: PartialEq + std::fmt::Debug + Serialize + for<'a> Deserialize<'a>,
{
let serialized = to_bytes::<_, LittleEndian>(&input).unwrap();
println!("Serialized data: {:x?}", &serialized);
let (deserialized, bytes_consumed): (T, usize) =
deserialize_from_cdr(&serialized, RepresentationIdentifier::CDR_LE).unwrap();
assert_eq!(input, deserialized);
assert_eq!(serialized.len(), bytes_consumed);
}
}