rusmpp_core/values/dest_address/
borrowed.rs

1use rusmpp_macros::Rusmpp;
2
3use crate::{
4    decode::{
5        DecodeError, DecodeResultExt,
6        borrowed::{Decode, DecodeExt},
7    },
8    encode::{Encode, Length},
9    types::borrowed::COctetString,
10    values::{dest_address::DestFlag, npi::Npi, ton::Ton},
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
15#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
16pub enum DestAddress<'a> {
17    /// SME Format Destination Address.
18    SmeAddress(SmeAddress<'a>),
19    /// Distribution List Format Destination Address.
20    DistributionListName(DistributionListName<'a>),
21}
22
23impl Length for DestAddress<'_> {
24    fn length(&self) -> usize {
25        match self {
26            Self::SmeAddress(sa) => sa.length(),
27            Self::DistributionListName(dlm) => dlm.length(),
28        }
29    }
30}
31
32impl Encode for DestAddress<'_> {
33    fn encode(&self, dst: &mut [u8]) -> usize {
34        match self {
35            Self::SmeAddress(sa) => sa.encode(dst),
36            Self::DistributionListName(dlm) => dlm.encode(dst),
37        }
38    }
39}
40
41impl<'a> Decode<'a> for DestAddress<'a> {
42    fn decode(src: &'a [u8]) -> Result<(Self, usize), DecodeError> {
43        let size = 0;
44
45        let (flag, size) = DestFlag::decode_move(src, size)?;
46
47        match flag {
48            DestFlag::SmeAddress => {
49                SmeAddress::decode_move(src, size).map_decoded(Self::SmeAddress)
50            }
51            DestFlag::DistributionListName => {
52                DistributionListName::decode_move(src, size).map_decoded(Self::DistributionListName)
53            }
54            DestFlag::Other(flag) => Err(DecodeError::unsupported_key(flag.into())),
55        }
56    }
57}
58
59/// SME Format Destination Address.
60#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
61#[rusmpp(decode = borrowed, test = skip)]
62#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
63#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
64pub struct SmeAddress<'a> {
65    /// 0x01 (SME Address).
66    ///
67    /// Can't and shouldn't be updated
68    #[rusmpp(skip_decode)]
69    dest_flag: DestFlag,
70    /// Type of Number for destination.
71    pub dest_addr_ton: Ton,
72    /// Numbering Plan Indicator for destination.
73    pub dest_addr_npi: Npi,
74    /// Destination address of this short message. For mobile
75    /// terminated messages, this is the directory number of the
76    /// recipient MS.
77    pub destination_addr: COctetString<'a, 1, 21>,
78}
79
80impl<'a> SmeAddress<'a> {
81    pub const fn new(
82        dest_addr_ton: Ton,
83        dest_addr_npi: Npi,
84        destination_addr: COctetString<'a, 1, 21>,
85    ) -> Self {
86        Self {
87            dest_flag: DestFlag::SmeAddress,
88            dest_addr_ton,
89            dest_addr_npi,
90            destination_addr,
91        }
92    }
93
94    pub fn dest_flag(&self) -> DestFlag {
95        self.dest_flag
96    }
97}
98
99/// Distribution List Format Destination Address.
100#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
101#[rusmpp(decode = borrowed, test = skip)]
102#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
103#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
104pub struct DistributionListName<'a> {
105    /// 0x02 (Distribution List).
106    ///
107    /// Can't and shouldn't be updated.
108    #[rusmpp(skip_decode)]
109    dest_flag: DestFlag,
110    /// Name of Distribution List.
111    pub dl_name: COctetString<'a, 1, 21>,
112}
113
114impl<'a> DistributionListName<'a> {
115    pub fn new(dl_name: COctetString<'a, 1, 21>) -> Self {
116        Self {
117            dest_flag: DestFlag::DistributionListName,
118            dl_name,
119        }
120    }
121
122    pub fn dest_flag(&self) -> DestFlag {
123        self.dest_flag
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    //! # Note
130    //!
131    //! [`encode_decode_test_instances`](crate::tests::borrowed::encode_decode_test_instances) will fail for [`SmeAddress`] and [`DistributionListName`]
132    //! because they encode the `dest_flag` field but skip decoding it, since it will be extracted while decoding [`DestAddress`].
133    //!
134    //! Another implementation for [`DestAddress`] that looks like `Pdu` or `Tlv` requires using the [`DestFlag`] as a key for decoding the `DestAddressVariant`,
135    //! and making [`DestAddress`] a struct with a `dest_flag` field and a `variant` field.
136    //! This means we should implement `DecodeWithKey` for `DestAddressVariant` with the [`DestFlag`] as a key.
137    //! But `DecodeWithKey` needs a `length` parameter, and our macro supports only `key` and `length` attributes.
138    //! So we have to create new trait that uses a key but does not require a length, and we have to update our macro to support only a key without a length.
139
140    use super::*;
141
142    impl crate::tests::TestInstance for DestAddress<'static> {
143        fn instances() -> alloc::vec::Vec<Self> {
144            alloc::vec![
145                Self::SmeAddress(SmeAddress::new(
146                    Ton::International,
147                    Npi::Isdn,
148                    COctetString::new(b"1234567890123456789\0").unwrap(),
149                )),
150                Self::DistributionListName(DistributionListName::new(
151                    COctetString::new(b"1234567890123456789\0").unwrap(),
152                )),
153            ]
154        }
155    }
156
157    #[test]
158    fn encode_decode() {
159        crate::tests::borrowed::encode_decode_test_instances::<DestAddress>();
160    }
161}