rusmpp_core/udhs/owned/
udh.rs

1use rusmpp_macros::Rusmpp;
2
3use crate::{
4    decode::{
5        DecodeError, DecodeResultExt,
6        owned::{Decode, DecodeWithKey, DecodeWithLength},
7    },
8    encode::Length,
9    types::owned::AnyOctetString,
10    udhs::{
11        UdhId,
12        owned::concatenation::{ConcatenatedShortMessage8Bit, ConcatenatedShortMessage16Bit},
13    },
14};
15
16/// User Data Header (UDH).
17#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
18#[rusmpp(decode = skip, test = skip)]
19pub struct Udh {
20    /// UDH length (excluding the length field itself).
21    length: u8,
22    /// UDH identifier.
23    id: UdhId,
24    /// UDH value.
25    value: Option<UdhValue>,
26}
27
28impl Udh {
29    /// Creates a new [`Udh`] from the given [`UdhValue`].
30    pub fn new(value: impl Into<UdhValue>) -> Self {
31        let value = value.into();
32        let id = value.id();
33        let length = value.length() as u8 + id.length() as u8;
34
35        Self {
36            id,
37            length,
38            value: Some(value),
39        }
40    }
41
42    /// Returns the UDH identifier.
43    pub const fn id(&self) -> UdhId {
44        self.id
45    }
46
47    /// Returns the UDH length (excluding the length field itself).
48    pub const fn length(&self) -> u8 {
49        self.length
50    }
51
52    /// Returns a reference to the UDH value.
53    pub const fn value(&self) -> Option<&UdhValue> {
54        self.value.as_ref()
55    }
56}
57
58impl From<UdhValue> for Udh {
59    fn from(value: UdhValue) -> Self {
60        Self::new(value)
61    }
62}
63
64/// User Data Header (UDH) value.
65#[non_exhaustive]
66#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
67pub enum UdhValue {
68    /// 8-bit Concatenated Short Message UDH.
69    ConcatenatedShortMessage8Bit(ConcatenatedShortMessage8Bit),
70    /// 16-bit Concatenated Short Message UDH.
71    ConcatenatedShortMessage16Bit(ConcatenatedShortMessage16Bit),
72    /// Other UDH types.
73    Other {
74        udh_id: UdhId,
75        value: AnyOctetString,
76    },
77}
78
79impl UdhValue {
80    /// Returns the UDH identifier.
81    pub const fn id(&self) -> UdhId {
82        match self {
83            UdhValue::ConcatenatedShortMessage8Bit(_) => UdhId::ConcatenatedShortMessages8Bit,
84            UdhValue::ConcatenatedShortMessage16Bit(_) => UdhId::ConcatenatedShortMessages16Bit,
85            UdhValue::Other { udh_id, .. } => *udh_id,
86        }
87    }
88}
89
90impl Length for UdhValue {
91    fn length(&self) -> usize {
92        match self {
93            UdhValue::ConcatenatedShortMessage8Bit(udh) => udh.length(),
94            UdhValue::ConcatenatedShortMessage16Bit(udh) => udh.length(),
95            UdhValue::Other { value, .. } => value.length(),
96        }
97    }
98}
99
100impl crate::encode::Encode for UdhValue {
101    fn encode(&self, dst: &mut [u8]) -> usize {
102        match self {
103            UdhValue::ConcatenatedShortMessage8Bit(udh) => udh.encode(dst),
104            UdhValue::ConcatenatedShortMessage16Bit(udh) => udh.encode(dst),
105            UdhValue::Other { value, .. } => value.encode(dst),
106        }
107    }
108}
109
110impl crate::encode::owned::Encode for UdhValue {
111    fn encode(&self, dst: &mut bytes::BytesMut) {
112        match self {
113            UdhValue::ConcatenatedShortMessage8Bit(udh) => udh.encode(dst),
114            UdhValue::ConcatenatedShortMessage16Bit(udh) => udh.encode(dst),
115            UdhValue::Other { value, .. } => value.encode(dst),
116        }
117    }
118}
119
120impl DecodeWithKey for UdhValue {
121    type Key = UdhId;
122
123    fn decode(
124        key: Self::Key,
125        src: &mut bytes::BytesMut,
126        length: usize,
127    ) -> Result<(Self, usize), DecodeError> {
128        let (value, size) = match key {
129            UdhId::ConcatenatedShortMessages8Bit => {
130                Decode::decode(src).map_decoded(Self::ConcatenatedShortMessage8Bit)?
131            }
132            UdhId::ConcatenatedShortMessages16Bit => {
133                Decode::decode(src).map_decoded(Self::ConcatenatedShortMessage16Bit)?
134            }
135            other => {
136                DecodeWithLength::decode(src, length).map_decoded(|value| UdhValue::Other {
137                    udh_id: other,
138                    value,
139                })?
140            }
141        };
142
143        Ok((value, size))
144    }
145}
146
147impl Decode for Udh {
148    fn decode(src: &mut bytes::BytesMut) -> Result<(Self, usize), DecodeError> {
149        let size = 0;
150        let (length, size) = crate::decode::DecodeErrorExt::map_as_source(
151            crate::decode::owned::DecodeExt::decode_move(src, size),
152            crate::fields::SmppField::udh_length,
153        )?;
154        let (id, size): (UdhId, usize) = crate::decode::DecodeErrorExt::map_as_source(
155            crate::decode::owned::DecodeExt::decode_move(src, size),
156            crate::fields::SmppField::udh_id,
157        )?;
158
159        let value_length = (length as usize).saturating_sub(id.length());
160
161        let (value, size) = crate::decode::DecodeErrorExt::map_as_source(
162            crate::decode::owned::DecodeWithKeyExt::optional_length_checked_decode_move(
163                id,
164                src,
165                value_length,
166                size,
167            ),
168            crate::fields::SmppField::udh_value,
169        )?
170        .map(|(this, size)| (Some(this), size))
171        .unwrap_or((None, size));
172
173        Ok((Self { length, id, value }, size))
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180
181    mod encode {
182        use super::*;
183
184        #[test]
185        fn ok() {
186            use crate::encode::Encode;
187
188            let udh = Udh::new(ConcatenatedShortMessage16Bit::new(0x1234, 3, 1).unwrap());
189
190            let expected = [
191                0x06, // UDH length (following bytes = 6)
192                0x08, // UDH ID: Concatenated Short Messages, 16-bit reference number
193                0x04, // IE Data Length = 4 bytes
194                0x12, // Ref high
195                0x34, // Ref low
196                0x03, // Total parts
197                0x01, // Part number
198            ];
199
200            let mut buf = [0u8; 24];
201            let size = udh.encode(&mut buf);
202
203            assert_eq!(size, 7);
204            assert_eq!(&buf[..size], &expected);
205
206            let udh = Udh::new(ConcatenatedShortMessage8Bit::new(0x12, 3, 1).unwrap());
207            let expected = [
208                0x05, // UDH length (following bytes = 5)
209                0x00, // UDH ID: Concatenated Short Messages, 8-bit reference number
210                0x03, // IE Data Length = 3 bytes
211                0x12, // Ref
212                0x03, // Total parts
213                0x01, // Part number
214            ];
215
216            let mut buf = [0u8; 24];
217            let size = udh.encode(&mut buf);
218
219            assert_eq!(size, 6);
220            assert_eq!(&buf[..size], &expected);
221        }
222    }
223
224    mod decode {
225        use bytes::BytesMut;
226
227        use crate::decode::owned::Decode;
228
229        use super::*;
230
231        #[test]
232        fn ok() {
233            let mut buf = BytesMut::from(
234                &[
235                    0x06, // UDH length (following bytes = 6)
236                    0x08, // UDH ID: Concatenated Short Messages, 16-bit reference number
237                    0x04, // IE Data Length = 4 bytes
238                    0x12, // Ref high
239                    0x34, // Ref low
240                    0x03, // Total parts
241                    0x01, // Part number
242                    0x00, // Extra bytes
243                    0x00,
244                ][..],
245            );
246
247            let (udh, size) = <Udh as Decode>::decode(&mut buf).unwrap();
248
249            assert_eq!(size, 7);
250            assert_eq!(
251                udh,
252                Udh::new(ConcatenatedShortMessage16Bit::new(0x1234, 3, 1).unwrap())
253            );
254
255            let mut buf = BytesMut::from(
256                &[
257                    0x05, // UDH length (following bytes = 5)
258                    0x00, // UDH ID: Concatenated Short Messages, 8-bit reference number
259                    0x03, // IE Data Length = 3 bytes
260                    0x12, // Ref
261                    0x03, // Total parts
262                    0x01, // Part number
263                    0x00, // Extra bytes
264                    0x00,
265                ][..],
266            );
267
268            let (udh, size) = <Udh as Decode>::decode(&mut buf).unwrap();
269            assert_eq!(size, 6);
270            assert_eq!(
271                udh,
272                Udh::new(ConcatenatedShortMessage8Bit::new(0x12, 3, 1).unwrap())
273            );
274        }
275    }
276}