1use rusmpp_macros::Rusmpp;
2
3use crate::{
4 encode::Length,
5 pdus::borrowed::Pdu,
6 tlvs::borrowed::{MessageSubmissionRequestTlvValue, Tlv},
7 types::borrowed::{COctetString, EmptyOrFullCOctetString, OctetString},
8 values::{borrowed::*, *},
9};
10
11#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
12#[rusmpp(decode = borrowed, test = skip)]
13#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
14#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
15pub struct SubmitMulti<'a, const N: usize> {
16 pub service_type: ServiceType<'a>,
25 pub source_addr_ton: Ton,
29 pub source_addr_npi: Npi,
33 pub source_addr: COctetString<'a, 1, 21>,
37 number_of_dests: u8,
45 #[rusmpp(count = number_of_dests)]
47 #[cfg_attr(feature = "arbitrary", arbitrary(default))]
48 dest_address: heapless::vec::Vec<DestAddress<'a>, N>,
49 pub esm_class: EsmClass,
51 pub protocol_id: u8,
55 pub priority_flag: PriorityFlag,
57 pub schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
61 pub validity_period: EmptyOrFullCOctetString<'a, 17>,
67 pub registered_delivery: RegisteredDelivery,
70 pub replace_if_present_flag: ReplaceIfPresentFlag,
73 pub data_coding: DataCoding,
75 pub sm_default_msg_id: u8,
80 sm_length: u8,
82 #[rusmpp(length = sm_length)]
94 short_message: OctetString<'a, 0, 255>,
95 #[rusmpp(length = "unchecked")]
97 #[cfg_attr(feature = "arbitrary", arbitrary(default))]
98 tlvs: heapless::vec::Vec<Tlv<'a>, N>,
99}
100
101impl<'a, const N: usize> SubmitMulti<'a, N> {
102 #[allow(clippy::too_many_arguments)]
103 pub fn new(
104 service_type: ServiceType<'a>,
105 source_addr_ton: Ton,
106 source_addr_npi: Npi,
107 source_addr: COctetString<'a, 1, 21>,
108 dest_address: heapless::vec::Vec<DestAddress<'a>, N>,
109 esm_class: EsmClass,
110 protocol_id: u8,
111 priority_flag: PriorityFlag,
112 schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
113 validity_period: EmptyOrFullCOctetString<'a, 17>,
114 registered_delivery: RegisteredDelivery,
115 replace_if_present_flag: ReplaceIfPresentFlag,
116 data_coding: DataCoding,
117 sm_default_msg_id: u8,
118 short_message: OctetString<'a, 0, 255>,
119 tlvs: heapless::vec::Vec<MessageSubmissionRequestTlvValue<'a>, N>,
120 ) -> Self {
121 let sm_length = short_message.length() as u8;
122 let number_of_dests = dest_address.len() as u8;
123
124 let tlvs = tlvs.into_iter().map(From::from).collect();
125
126 Self {
127 service_type,
128 source_addr_ton,
129 source_addr_npi,
130 source_addr,
131 number_of_dests,
132 dest_address,
133 esm_class,
134 protocol_id,
135 priority_flag,
136 schedule_delivery_time,
137 validity_period,
138 registered_delivery,
139 replace_if_present_flag,
140 data_coding,
141 sm_default_msg_id,
142 sm_length,
143 short_message,
144 tlvs,
145 }
146 }
147
148 pub const fn number_of_dests(&self) -> u8 {
149 self.number_of_dests
150 }
151
152 pub fn dest_address(&'_ self) -> &'_ [DestAddress<'_>] {
153 &self.dest_address
154 }
155
156 pub fn set_dest_address(&mut self, dest_address: heapless::vec::Vec<DestAddress<'a>, N>) {
157 self.dest_address = dest_address;
158 self.number_of_dests = self.dest_address.len() as u8;
159 }
160
161 pub fn push_dest_address(
162 &mut self,
163 dest_address: DestAddress<'a>,
164 ) -> Result<(), DestAddress<'a>> {
165 self.dest_address.push(dest_address)?;
166 self.number_of_dests = self.dest_address.len() as u8;
167
168 Ok(())
169 }
170
171 pub fn clear_dest_address(&mut self) {
172 self.dest_address.clear();
173 self.number_of_dests = self.dest_address.len() as u8;
174 }
175
176 pub const fn sm_length(&self) -> u8 {
177 self.sm_length
178 }
179
180 pub const fn short_message(&self) -> &OctetString<'a, 0, 255> {
181 &self.short_message
182 }
183
184 pub fn set_short_message(&mut self, short_message: OctetString<'a, 0, 255>) {
191 self.short_message = short_message;
192 self.sm_length = self.short_message.length() as u8;
193 }
194
195 pub fn tlvs(&'_ self) -> &'_ [Tlv<'_>] {
196 &self.tlvs
197 }
198
199 pub fn set_tlvs(&mut self, tlvs: heapless::vec::Vec<MessageSubmissionRequestTlvValue<'a>, N>) {
200 self.tlvs = tlvs.into_iter().map(From::from).collect();
201 }
202
203 pub fn clear_tlvs(&mut self) {
204 self.tlvs.clear();
205 }
206
207 pub fn push_tlv(
208 &mut self,
209 tlv: impl Into<MessageSubmissionRequestTlvValue<'a>>,
210 ) -> Result<(), Tlv<'a>> {
211 self.tlvs.push(Tlv::from(tlv.into()))?;
212 Ok(())
213 }
214
215 pub fn builder() -> SubmitMultiBuilder<'a, N> {
216 SubmitMultiBuilder::new()
217 }
218}
219
220impl<'a, const N: usize> From<SubmitMulti<'a, N>> for Pdu<'a, N> {
221 fn from(value: SubmitMulti<'a, N>) -> Self {
222 Self::SubmitMulti(value)
223 }
224}
225
226#[derive(Debug, Default)]
227pub struct SubmitMultiBuilder<'a, const N: usize> {
228 inner: SubmitMulti<'a, N>,
229}
230
231impl<'a, const N: usize> SubmitMultiBuilder<'a, N> {
232 pub fn new() -> Self {
233 Default::default()
234 }
235
236 pub fn service_type(mut self, service_type: ServiceType<'a>) -> Self {
237 self.inner.service_type = service_type;
238 self
239 }
240
241 pub fn source_addr_ton(mut self, source_addr_ton: Ton) -> Self {
242 self.inner.source_addr_ton = source_addr_ton;
243 self
244 }
245
246 pub fn source_addr_npi(mut self, source_addr_npi: Npi) -> Self {
247 self.inner.source_addr_npi = source_addr_npi;
248 self
249 }
250
251 pub fn source_addr(mut self, source_addr: COctetString<'a, 1, 21>) -> Self {
252 self.inner.source_addr = source_addr;
253 self
254 }
255
256 pub fn dest_address(mut self, dest_address: heapless::vec::Vec<DestAddress<'a>, N>) -> Self {
257 self.inner.set_dest_address(dest_address);
258 self
259 }
260
261 pub fn push_dest_address(
262 mut self,
263 dest_address: DestAddress<'a>,
264 ) -> Result<Self, DestAddress<'a>> {
265 self.inner.push_dest_address(dest_address)?;
266 Ok(self)
267 }
268
269 pub fn clear_dest_address(mut self) -> Self {
270 self.inner.clear_dest_address();
271 self
272 }
273
274 pub fn esm_class(mut self, esm_class: EsmClass) -> Self {
275 self.inner.esm_class = esm_class;
276 self
277 }
278
279 pub fn protocol_id(mut self, protocol_id: u8) -> Self {
280 self.inner.protocol_id = protocol_id;
281 self
282 }
283
284 pub fn priority_flag(mut self, priority_flag: PriorityFlag) -> Self {
285 self.inner.priority_flag = priority_flag;
286 self
287 }
288
289 pub fn schedule_delivery_time(
290 mut self,
291 schedule_delivery_time: EmptyOrFullCOctetString<'a, 17>,
292 ) -> Self {
293 self.inner.schedule_delivery_time = schedule_delivery_time;
294 self
295 }
296
297 pub fn validity_period(mut self, validity_period: EmptyOrFullCOctetString<'a, 17>) -> Self {
298 self.inner.validity_period = validity_period;
299 self
300 }
301
302 pub fn registered_delivery(mut self, registered_delivery: RegisteredDelivery) -> Self {
303 self.inner.registered_delivery = registered_delivery;
304 self
305 }
306
307 pub fn replace_if_present_flag(
308 mut self,
309 replace_if_present_flag: ReplaceIfPresentFlag,
310 ) -> Self {
311 self.inner.replace_if_present_flag = replace_if_present_flag;
312 self
313 }
314
315 pub fn data_coding(mut self, data_coding: DataCoding) -> Self {
316 self.inner.data_coding = data_coding;
317 self
318 }
319
320 pub fn sm_default_msg_id(mut self, sm_default_msg_id: u8) -> Self {
321 self.inner.sm_default_msg_id = sm_default_msg_id;
322 self
323 }
324
325 pub fn short_message(mut self, short_message: OctetString<'a, 0, 255>) -> Self {
326 self.inner.set_short_message(short_message);
327 self
328 }
329
330 pub fn tlvs(
331 mut self,
332 tlvs: heapless::vec::Vec<MessageSubmissionRequestTlvValue<'a>, N>,
333 ) -> Self {
334 self.inner.set_tlvs(tlvs);
335 self
336 }
337
338 pub fn clear_tlvs(mut self) -> Self {
339 self.inner.clear_tlvs();
340 self
341 }
342
343 pub fn push_tlv(
344 mut self,
345 tlv: impl Into<MessageSubmissionRequestTlvValue<'a>>,
346 ) -> Result<Self, Tlv<'a>> {
347 self.inner.push_tlv(tlv)?;
348 Ok(self)
349 }
350
351 pub fn build(self) -> SubmitMulti<'a, N> {
352 self.inner
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use crate::{tests::TestInstance, types::borrowed::AnyOctetString};
359
360 use super::*;
361
362 impl<const N: usize> TestInstance for SubmitMulti<'static, N> {
363 fn instances() -> alloc::vec::Vec<Self> {
364 alloc::vec![
365 Self::default(),
366 Self::builder()
367 .service_type(ServiceType::default())
368 .source_addr_ton(Ton::International)
369 .source_addr_npi(Npi::Isdn)
370 .source_addr(COctetString::new(b"Source Address\0").unwrap())
371 .esm_class(EsmClass::default())
372 .protocol_id(0)
373 .priority_flag(PriorityFlag::default())
374 .schedule_delivery_time(EmptyOrFullCOctetString::empty())
375 .validity_period(EmptyOrFullCOctetString::empty())
376 .registered_delivery(RegisteredDelivery::default())
377 .replace_if_present_flag(ReplaceIfPresentFlag::default())
378 .data_coding(DataCoding::default())
379 .sm_default_msg_id(0)
380 .short_message(OctetString::new(b"Short Message").unwrap())
381 .build(),
382 Self::builder()
383 .short_message(OctetString::new(b"Short Message").unwrap())
384 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
385 MessagePayload::new(AnyOctetString::new(b"Message Payload")),
386 ))
387 .unwrap()
388 .build(),
389 Self::builder()
390 .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
391 Ton::International,
392 Npi::Isdn,
393 COctetString::new(b"1234567890123456789\0").unwrap(),
394 )))
395 .unwrap()
396 .push_dest_address(DestAddress::DistributionListName(
397 DistributionListName::new(
398 COctetString::new(b"1234567890123456789\0").unwrap(),
399 ),
400 ))
401 .unwrap()
402 .short_message(OctetString::new(b"Short Message").unwrap())
403 .push_tlv(MessageSubmissionRequestTlvValue::MessagePayload(
404 MessagePayload::new(AnyOctetString::new(b"Message Payload")),
405 ))
406 .unwrap()
407 .push_tlv(MessageSubmissionRequestTlvValue::DestTelematicsId(16))
408 .unwrap()
409 .build(),
410 ]
411 }
412 }
413
414 #[test]
415 fn encode_decode() {
416 crate::tests::borrowed::encode_decode_with_length_test_instances::<SubmitMulti<'static, 16>>(
417 );
418 }
419
420 #[test]
421 fn short_message_length() {
422 let short_message = OctetString::new(b"Short Message").unwrap();
423
424 let submit_sm = SubmitMulti::<'static, 16>::builder()
425 .short_message(short_message.clone())
426 .build();
427
428 assert_eq!(submit_sm.short_message(), &short_message);
429 assert_eq!(submit_sm.sm_length(), short_message.length() as u8);
430 }
431
432 #[test]
433 fn count() {
434 let submit_multi = SubmitMulti::<'static, 16>::default();
435
436 assert_eq!(submit_multi.number_of_dests(), 0);
437 assert!(submit_multi.dest_address().is_empty());
438
439 let submit_sm = SubmitMulti::<'static, 16>::builder()
440 .dest_address(
441 [
442 DestAddress::SmeAddress(SmeAddress::new(
443 Ton::International,
444 Npi::Isdn,
445 COctetString::new(b"1234567890123456789\0").unwrap(),
446 )),
447 DestAddress::DistributionListName(DistributionListName::new(
448 COctetString::new(b"1234567890123456789\0").unwrap(),
449 )),
450 ]
451 .into(),
452 )
453 .build();
454
455 assert_eq!(submit_sm.number_of_dests(), 2);
456 assert_eq!(submit_sm.dest_address().len(), 2);
457
458 let submit_sm = SubmitMulti::<'static, 16>::builder()
459 .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
460 Ton::International,
461 Npi::Isdn,
462 COctetString::new(b"1234567890123456789\0").unwrap(),
463 )))
464 .unwrap()
465 .push_dest_address(DestAddress::DistributionListName(
466 DistributionListName::new(COctetString::new(b"1234567890123456789\0").unwrap()),
467 ))
468 .unwrap()
469 .build();
470
471 assert_eq!(submit_sm.number_of_dests(), 2);
472 assert_eq!(submit_sm.dest_address().len(), 2);
473
474 let submit_sm = SubmitMulti::<'static, 16>::builder()
475 .push_dest_address(DestAddress::SmeAddress(SmeAddress::new(
476 Ton::International,
477 Npi::Isdn,
478 COctetString::new(b"1234567890123456789\0").unwrap(),
479 )))
480 .unwrap()
481 .push_dest_address(DestAddress::DistributionListName(
482 DistributionListName::new(COctetString::new(b"1234567890123456789\0").unwrap()),
483 ))
484 .unwrap()
485 .clear_dest_address()
486 .build();
487
488 assert_eq!(submit_sm.number_of_dests(), 0);
489 assert!(submit_sm.dest_address().is_empty());
490 }
491}