rusmpp_core/framez/
mod.rs1use core::num::TryFromIntError;
4
5use framez::{decode::Decoder, encode::Encoder};
6
7use crate::{
8 command::borrowed::Command,
9 decode::borrowed::DecodeWithLength,
10 encode::{Encode, Length},
11 logging::{debug, error, trace},
12};
13
14#[cfg(test)]
15mod tests;
16
17#[derive(Debug)]
19#[non_exhaustive]
20pub struct CommandCodec<const N: usize> {}
21
22impl<const N: usize> CommandCodec<N> {
23 pub const fn new() -> Self {
24 Self {}
25 }
26}
27
28impl<const N: usize> Default for CommandCodec<N> {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34#[derive(Debug)]
36#[non_exhaustive]
37pub enum EncodeError {
38 BufferTooSmall,
40}
41
42impl core::fmt::Display for EncodeError {
43 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44 match self {
45 Self::BufferTooSmall => write!(f, "Buffer too small"),
46 }
47 }
48}
49
50impl core::error::Error for EncodeError {}
51
52impl<'buf, const N: usize> Encoder<Command<'buf, N>> for CommandCodec<N> {
53 type Error = EncodeError;
54
55 fn encode(&mut self, item: Command<'buf, N>, dst: &mut [u8]) -> Result<usize, Self::Error> {
56 let command_length = 4 + item.length();
57
58 if dst.len() < command_length {
59 return Err(EncodeError::BufferTooSmall);
60 }
61
62 dst[..4].copy_from_slice(&(command_length as u32).to_be_bytes());
63 let _ = item.encode(&mut dst[4..command_length]);
64
65 debug!(target: "rusmpp::codec::encode", command=?item, "Encoding");
66 debug!(target: "rusmpp::codec::encode", encoded=?crate::formatter::Formatter(&dst[..command_length]), encoded_length=item.length(), command_length, "Encoded");
67
68 Ok(command_length)
69 }
70}
71
72#[derive(Debug)]
74#[non_exhaustive]
75pub enum DecodeError {
76 Decode(crate::decode::DecodeError),
78 MinLength { actual: usize, min: usize },
80 InvalidLength(TryFromIntError),
82}
83
84impl core::fmt::Display for DecodeError {
85 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
86 match self {
87 DecodeError::Decode(e) => write!(f, "Decode error: {e}"),
88 DecodeError::MinLength { actual, min } => {
89 write!(
90 f,
91 "Minimum command length not met. actual: {actual}, min: {min}"
92 )
93 }
94
95 DecodeError::InvalidLength(e) => {
96 write!(f, "Integral type conversion failed: {e}")
97 }
98 }
99 }
100}
101
102impl core::error::Error for DecodeError {}
103
104impl<const N: usize> framez::decode::DecodeError for CommandCodec<N> {
105 type Error = DecodeError;
106}
107
108impl<'buf, const N: usize> Decoder<'buf> for CommandCodec<N> {
109 type Item = Command<'buf, N>;
110
111 fn decode(&mut self, src: &'buf mut [u8]) -> Result<Option<(Self::Item, usize)>, Self::Error> {
112 const HEADER_LENGTH: usize = 16;
113
114 if src.len() < HEADER_LENGTH {
115 trace!(target: "rusmpp::codec::decode", source_length=src.len(), "Not enough bytes to read the header");
116
117 return Ok(None);
118 }
119
120 let command_length =
121 usize::try_from(u32::from_be_bytes([src[0], src[1], src[2], src[3]]))
122 .inspect_err(|_err| {
123 error!(target: "rusmpp::codec::decode", err=?_err, "Failed to convert command length to usize");
124 })
125 .map_err(DecodeError::InvalidLength)?;
126
127 trace!(target: "rusmpp::codec::decode", command_length);
128
129 if command_length < HEADER_LENGTH {
130 error!(target: "rusmpp::codec::decode", command_length, min_command_length=HEADER_LENGTH, "Minimum command length not met");
131
132 return Err(DecodeError::MinLength {
133 actual: command_length,
134 min: HEADER_LENGTH,
135 });
136 }
137
138 if src.len() < command_length {
139 trace!(target: "rusmpp::codec::decode", command_length, "Not enough bytes to read the entire command");
140
141 return Ok(None);
142 }
143
144 let pdu_len = command_length - 4;
146
147 debug!(target: "rusmpp::codec::decode", decoding=?crate::formatter::Formatter(&src[..command_length]), "Decoding");
148
149 let (command, _size) = match Command::decode(&src[4..command_length], pdu_len) {
150 Ok((command, size)) => {
151 debug!(target: "rusmpp::codec::decode", command=?command, command_length, decoded_length=size, "Decoded");
152
153 (command, size)
154 }
155 Err(err) => {
156 error!(target: "rusmpp::codec::decode", ?err);
157
158 return Err(DecodeError::Decode(err));
159 }
160 };
161
162 Ok(Some((command, command_length)))
163 }
164}