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#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
18#[rusmpp(decode = skip, test = skip)]
19pub struct Udh {
20 length: u8,
22 id: UdhId,
24 value: Option<UdhValue>,
26}
27
28impl Udh {
29 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 pub const fn id(&self) -> UdhId {
44 self.id
45 }
46
47 pub const fn length(&self) -> u8 {
49 self.length
50 }
51
52 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#[non_exhaustive]
66#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
67pub enum UdhValue {
68 ConcatenatedShortMessage8Bit(ConcatenatedShortMessage8Bit),
70 ConcatenatedShortMessage16Bit(ConcatenatedShortMessage16Bit),
72 Other {
74 udh_id: UdhId,
75 value: AnyOctetString,
76 },
77}
78
79impl UdhValue {
80 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, 0x08, 0x04, 0x12, 0x34, 0x03, 0x01, ];
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, 0x00, 0x03, 0x12, 0x03, 0x01, ];
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, 0x08, 0x04, 0x12, 0x34, 0x03, 0x01, 0x00, 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, 0x00, 0x03, 0x12, 0x03, 0x01, 0x00, 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}