Skip to main content

c_its_parser/transport/
decode.rs

1use nom::bytes::streaming::take;
2use nom::combinator::{into, map_res};
3use nom::error::{ErrorKind, FromExternalError, ParseError};
4use nom::sequence::pair;
5
6#[derive(Debug, PartialEq)]
7pub enum DecodeError<I> {
8    IntegerError(alloc::string::String),
9    IPv6Parsing(alloc::string::String),
10    Nom(I, ErrorKind),
11    #[cfg(feature = "json")]
12    Json(alloc::string::String),
13}
14
15impl<I> ParseError<I> for DecodeError<I> {
16    fn from_error_kind(input: I, kind: ErrorKind) -> Self {
17        DecodeError::Nom(input, kind)
18    }
19
20    fn append(_: I, _: ErrorKind, other: Self) -> Self {
21        other
22    }
23}
24
25impl<I, E> FromExternalError<I, E> for DecodeError<I> {
26    fn from_external_error(input: I, kind: ErrorKind, _: E) -> Self {
27        DecodeError::Nom(input, kind)
28    }
29}
30
31pub type IResult<I, T> = nom::IResult<I, T, DecodeError<I>>;
32
33pub trait Decode: Sized {
34    /// Decoder trait for decoding the individual fields of the transport header
35    /// Takes byte slice as input.
36    /// ### Usage
37    /// ```ignore
38    /// # use c_its_parser::transport::*;
39    /// let input: &'static [u8] = &[0,1,0,2];
40    /// let (_remaining_input, decoded) = BasicTransportAHeader::decode(input).unwrap();
41    /// assert_eq!(
42    ///     decoded,
43    ///     BasicTransportAHeader {
44    ///         destination_port: 1,
45    ///         source_port: 2,
46    ///     }
47    /// );
48    /// ```
49    fn decode(input: &[u8]) -> IResult<&[u8], Self>;
50}
51
52impl Decode for super::BasicTransportAHeader {
53    fn decode(input: &[u8]) -> IResult<&[u8], Self> {
54        into(pair(u16_from_be_bytes, u16_from_be_bytes))(input)
55    }
56}
57
58impl From<(u16, u16)> for super::BasicTransportAHeader {
59    fn from(value: (u16, u16)) -> Self {
60        Self {
61            destination_port: value.0,
62            source_port: value.1,
63        }
64    }
65}
66
67impl super::BasicTransportAHeader {
68    #[cfg(feature = "json")]
69    /// Decodes a BTP-A header from JSON
70    ///
71    /// # Errors
72    /// Returns an error when parsing failed
73    pub fn decode_from_json(input: &str) -> Result<Self, DecodeError<&str>> {
74        serde_json::from_str(input)
75            .map_err(|e| DecodeError::Json(alloc::format!("Error encoding to JSON: {e:?}")))
76    }
77}
78
79impl Decode for super::BasicTransportBHeader {
80    fn decode(input: &[u8]) -> IResult<&[u8], Self> {
81        into(pair(u16_from_be_bytes, u16_from_be_bytes))(input)
82    }
83}
84
85impl From<(u16, u16)> for super::BasicTransportBHeader {
86    fn from(value: (u16, u16)) -> Self {
87        Self {
88            destination_port: value.0,
89            destination_port_info: value.1,
90        }
91    }
92}
93
94impl super::BasicTransportBHeader {
95    #[cfg(feature = "json")]
96    /// Decodes a BTP-B header from JSON
97    ///
98    /// # Errors
99    /// Returns an error when parsing failed
100    pub fn decode_from_json(input: &str) -> Result<Self, DecodeError<&str>> {
101        serde_json::from_str(input)
102            .map_err(|e| DecodeError::Json(alloc::format!("Error encoding to JSON: {e:?}")))
103    }
104}
105
106fn u16_from_be_bytes(input: &[u8]) -> IResult<&[u8], u16> {
107    map_res(take(2usize), |slice: &[u8]| {
108        slice.try_into().map(u16::from_be_bytes).map_err(|e| {
109            DecodeError::IntegerError::<&[u8]>(alloc::format!(
110                "Failed to construct integer from bytes: {e:?}"
111            ))
112        })
113    })(input)
114}
115
116impl Decode for super::IPv6Header {
117    fn decode(input: &[u8]) -> IResult<&[u8], Self> {
118        etherparse::PacketHeaders::from_ip_slice(input)
119            .map(|headers| {
120                let first_after_headers = headers
121                    .net
122                    .as_ref()
123                    .map_or(0, etherparse::NetHeaders::header_len)
124                    + headers
125                        .link
126                        .as_ref()
127                        .map_or(0, etherparse::LinkHeader::header_len)
128                    + headers
129                        .transport
130                        .as_ref()
131                        .map_or(0, etherparse::TransportHeader::header_len)
132                    + headers
133                        .link_exts
134                        .first()
135                        .map_or(0, etherparse::LinkExtHeader::header_len);
136                (
137                    &input[first_after_headers..],
138                    super::IPv6Header::from(headers),
139                )
140            })
141            .map_err(|e| {
142                nom::Err::Error(DecodeError::IPv6Parsing(alloc::format!(
143                    "Error parsing IPv6 Header: {e:?}"
144                )))
145            })
146    }
147}
148
149impl From<etherparse::PacketHeaders<'_>> for super::IPv6Header {
150    fn from(value: etherparse::PacketHeaders<'_>) -> Self {
151        Self {
152            ip: value.net,
153            link: value.link,
154            transport: value.transport,
155            link_ext: value.link_exts.first().cloned(),
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {}