use bytes::{Buf, BufMut, BytesMut};
pub trait FieldSerialize {
fn serialize_field(&self, buf: &mut BytesMut);
}
pub trait FieldDeserialize: Sized {
fn deserialize_field<B: Buf>(buf: &mut B) -> Self;
}
pub trait FieldLen {
fn field_len(&self) -> usize;
}
pub trait FieldDeserializeWithLen: Sized {
fn deserialize_with_len<B: Buf>(buf: &mut B, len: usize) -> Self;
}
impl<T> FieldDeserializeWithLen for Option<T>
where
T: FieldDeserializeWithLen,
{
fn deserialize_with_len<B: Buf>(buf: &mut B, len: usize) -> Self {
if len == 0 {
None
} else {
Some(<T as FieldDeserializeWithLen>::deserialize_with_len(
buf, len,
))
}
}
}
#[macro_export]
macro_rules! __pdu_prep_serialize_field {
( len = $len_field:ident ; $self:ident, $field:ident, Option<$inner:ty> ) => {
$self.$len_field = $self.$field.as_ref().map_or(0u8, |v| {
<$inner as $crate::pdu_macro::FieldLen>::field_len(v) as u8
});
};
( len = $len_field:ident ; $self:ident, $field:ident, $t:ty ) => {
$self.$len_field = u8::try_from(<$t as $crate::pdu_macro::FieldLen>::field_len(
&$self.$field,
))
.unwrap_or_default();
};
( ; $self:ident, $field:ident, $t:ty ) => {
};
}
#[macro_export]
macro_rules! __pdu_deserialize_field {
( len = $len_field:ident ; $field:ident, Option<$inner:ty>, $buf:ident ) => {
let $field: Option<$inner> = {
let len_val = $len_field as usize;
if len_val == 0 {
None
} else {
Some(
<$inner as $crate::pdu_macro::FieldDeserializeWithLen>::deserialize_with_len(
$buf, len_val,
),
)
}
};
};
( len = $len_field:ident ; $field:ident, $t:ty, $buf:ident ) => {
let $field: $t = <$t as $crate::pdu_macro::FieldDeserializeWithLen>::deserialize_with_len(
$buf,
$len_field as usize,
);
};
( ; $field:ident, $t:ty, $buf:ident ) => {
let $field: $t = <$t as $crate::pdu_macro::FieldDeserialize>::deserialize_field($buf);
};
}
macro_rules! impl_primitive {
($ty:ty, $put:ident, $get:ident, $len:expr) => {
impl FieldSerialize for $ty {
fn serialize_field(&self, buf: &mut BytesMut) {
buf.$put(*self);
}
}
impl FieldDeserialize for $ty {
fn deserialize_field<B: Buf>(buf: &mut B) -> Self {
buf.$get()
}
}
impl FieldLen for $ty {
fn field_len(&self) -> usize {
$len
}
}
};
}
impl_primitive!(u8, put_u8, get_u8, 1usize);
impl_primitive!(i8, put_i8, get_i8, 1usize);
impl_primitive!(u16, put_u16, get_u16, 2usize);
impl_primitive!(i16, put_i16, get_i16, 2usize);
impl_primitive!(u32, put_u32, get_u32, 4usize);
impl_primitive!(i32, put_i32, get_i32, 4usize);
impl_primitive!(u64, put_u64, get_u64, 8usize);
impl_primitive!(i64, put_i64, get_i64, 8usize);
impl_primitive!(f32, put_f32, get_f32, 4usize);
impl_primitive!(f64, put_f64, get_f64, 8usize);
impl FieldSerialize for String {
fn serialize_field(&self, buf: &mut BytesMut) {
buf.put_slice(self.as_bytes());
}
}
impl FieldDeserialize for String {
fn deserialize_field<B: Buf>(_buf: &mut B) -> Self {
Self::new()
}
}
impl FieldLen for String {
fn field_len(&self) -> usize {
self.len()
}
}
impl<T> FieldSerialize for Vec<T>
where
T: FieldSerialize,
{
fn serialize_field(&self, buf: &mut BytesMut) {
for item in self {
item.serialize_field(buf);
}
}
}
impl<T> FieldDeserialize for Vec<T>
where
T: FieldDeserialize,
{
fn deserialize_field<B: Buf>(_buf: &mut B) -> Self {
Self::new()
}
}
impl<T> FieldLen for Vec<T>
where
T: FieldLen,
{
fn field_len(&self) -> usize {
self.iter().map(FieldLen::field_len).sum()
}
}
impl<T> FieldSerialize for Option<T>
where
T: FieldSerialize,
{
fn serialize_field(&self, buf: &mut BytesMut) {
if let Some(v) = self.as_ref() {
v.serialize_field(buf);
}
}
}
impl<T> FieldDeserialize for Option<T>
where
T: FieldDeserialize,
{
fn deserialize_field<B: Buf>(_buf: &mut B) -> Self {
None
}
}
impl<T> FieldLen for Option<T>
where
T: FieldLen,
{
fn field_len(&self) -> usize {
self.as_ref().map_or(0, FieldLen::field_len)
}
}
#[macro_export]
macro_rules! define_pdu {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
header: $header:ty,
pdu_type: $pdu_type:expr,
protocol_family: $protocol_family:expr,
fields: {
$(
$(#[len = $len_field:ident])? $fvis:vis $field:ident : $ftype:ty,
)*
}
}
) => {
$(#[$meta])*
$vis struct $name {
header: $header,
$(
$fvis $field : $ftype,
)*
}
impl Default for $name {
fn default() -> Self {
Self {
header: <$header>::default(),
$(
$field: <$ftype>::default(),
)*
}
}
}
impl $name {
fn deserialize_body<B: bytes::Buf>(buf: &mut B) -> Self {
$(
$crate::__pdu_deserialize_field!( $( len = $len_field )? ; $field, $ftype, buf );
)*
Self {
header: <$header>::default(),
$(
$field,
)*
}
}
}
impl $crate::common::pdu::Pdu for $name {
type Header = $header;
fn calculate_length(&self) -> Result<u16, $crate::common::dis_error::DISError> {
let mut len: usize = <$header>::LENGTH;
$(
len += <$ftype as $crate::pdu_macro::FieldLen>::field_len(&self.$field);
)*
u16::try_from(len).map_err(|_| $crate::common::dis_error::DISError::PduSizeExceeded {
size: len,
max_size: $crate::common::constants::MAX_PDU_SIZE_OCTETS,
})
}
fn header(&self) -> &Self::Header {
&self.header
}
fn header_mut(&mut self) -> &mut Self::Header {
&mut self.header
}
fn serialize(&mut self, buf: &mut bytes::BytesMut) -> Result<(), $crate::common::dis_error::DISError> {
self.header.set_pdu_type($pdu_type);
self.header.set_protocol_family($protocol_family);
$( $crate::__pdu_prep_serialize_field!( $( len = $len_field )? ; self, $field, $ftype ); )*
let len = self.calculate_length()?;
self.header.set_length(len);
self.header.serialize(buf);
$(
<$ftype as $crate::pdu_macro::FieldSerialize>::serialize_field(&self.$field, buf);
)*
Ok(())
}
fn deserialize<B: bytes::Buf>(buf: &mut B) -> Result<Self, $crate::common::dis_error::DISError>
where Self: Sized {
let header: Self::Header = <Self::Header as $crate::pdu_macro::FieldDeserialize>::deserialize_field(buf);
if header.pdu_type() != $pdu_type {
return Err($crate::common::dis_error::DISError::invalid_header(
format!("Expected PDU type {:?}, got {:?}", $pdu_type, header.pdu_type()),
None,
));
}
let mut body = Self::deserialize_body(buf);
body.header = header;
Ok(body)
}
fn deserialize_without_header<B: bytes::Buf>(buf: &mut B, header: Self::Header) -> Result<Self, $crate::common::dis_error::DISError>
where Self: Sized {
let mut body = Self::deserialize_body(buf);
body.header = header;
Ok(body)
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl $name {
#[must_use]
pub fn new() -> Self {
let mut pdu = Self::default();
pdu.header.set_pdu_type($pdu_type);
pdu.header.set_protocol_family($protocol_family);
pdu.finalize();
pdu
}
}
};
}