rusmpp_core/command/
owned.rs

1use rusmpp_macros::Rusmpp;
2
3use crate::{CommandId, CommandStatus, pdus::owned::Pdu};
4
5/// `SMPP` command.
6///
7/// The following PDU example illustrates how a `SMPP` PDU is decoded:
8///
9/// Sample PDU (Values are shown in Hex format):
10///
11/// 00 00 00 2F 00 00 00 02 00 00 00 00 00 00 00 01
12///
13/// 53 4D 50 50 33 54 45 53 54 00 73 65 63 72 65 74
14///
15/// 30 38 00 53 55 42 4D 49 54 31 00 50 01 01 00
16///
17/// The 16-octet header would be decoded as follows:
18///
19/// | Octets | Description |
20/// | ------ | ----------- |
21/// | 00 00 00 2F | Command Length (47) |
22/// | 00 00 00 02 | Command ID (bind_transmitter) |
23/// | 00 00 00 00 | Command Status (0) |
24/// | 00 00 00 01 | Sequence Number (1)|
25///
26/// The remaining data represents the PDU body (which in this example relates to the
27/// bind_transmitter PDU). This is diagnosed as follows:
28///
29/// | Octets | Value |
30/// | ------ | ----- |
31/// | 53 4D 50 50 33 54 45 53 54 00 | system_id (“SMPP3TEST”) |
32/// | 73 65 63 72 65 74 30 38 00    | password (“secret08”) |
33/// | 53 55 42 4D 49 54 31 00       | system_type (“SUBMIT1”) |
34/// | 50                            | interface_version (0x50 “V5.0 compliant”) |
35/// | 01                            | addr_ton (0x01) |
36/// | 01                            | addr_npi (0x01) |
37/// | 00                            | addr_range (NULL) |
38#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Rusmpp)]
39#[rusmpp(decode = owned)]
40#[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))]
41#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
42#[cfg_attr(feature = "serde-deserialize-unchecked", derive(::serde::Deserialize))]
43pub struct Command {
44    /// See [`CommandId`]
45    id: CommandId,
46    /// See [`CommandStatus`]
47    pub status: CommandStatus,
48    /// The sequence_number represents a means of uniquely
49    /// identifying each PDU within a `SMPP` session. It also provides a means of correlating request
50    /// and response PDUs based on matching sequence number.
51    pub sequence_number: u32,
52    /// See [`Pdu`]
53    ///
54    /// Optional because incoming commands may not have a PDU.
55    #[rusmpp(key = id, length = "unchecked")]
56    pdu: Option<Pdu>,
57}
58
59impl Default for Command {
60    fn default() -> Self {
61        Self {
62            id: CommandId::EnquireLink,
63            status: CommandStatus::EsmeRok,
64            sequence_number: 0,
65            pdu: Some(Pdu::EnquireLink),
66        }
67    }
68}
69
70impl Command {
71    pub fn new(status: CommandStatus, sequence_number: u32, pdu: impl Into<Pdu>) -> Self {
72        Self::new_const(status, sequence_number, pdu.into())
73    }
74
75    pub const fn new_const(status: CommandStatus, sequence_number: u32, pdu: Pdu) -> Self {
76        let id = pdu.command_id();
77
78        Self {
79            id,
80            status,
81            sequence_number,
82            pdu: Some(pdu),
83        }
84    }
85
86    #[inline]
87    pub const fn id(&self) -> CommandId {
88        self.id
89    }
90
91    #[inline]
92    pub const fn status(&self) -> CommandStatus {
93        self.status
94    }
95
96    #[inline]
97    pub const fn sequence_number(&self) -> u32 {
98        self.sequence_number
99    }
100
101    #[inline]
102    pub const fn pdu(&self) -> Option<&Pdu> {
103        self.pdu.as_ref()
104    }
105
106    #[inline]
107    pub fn set_pdu(&mut self, pdu: impl Into<Pdu>) {
108        let pdu = pdu.into();
109
110        self.id = pdu.command_id();
111
112        self.pdu = Some(pdu);
113    }
114
115    #[inline]
116    pub fn builder() -> CommandStatusBuilder {
117        Default::default()
118    }
119}
120
121#[derive(Debug, Default)]
122pub struct CommandStatusBuilder {
123    inner: Command,
124}
125
126impl CommandStatusBuilder {
127    #[inline]
128    pub fn status(mut self, status: CommandStatus) -> SequenceNumberBuilder {
129        self.inner.status = status;
130
131        SequenceNumberBuilder { inner: self.inner }
132    }
133}
134
135#[derive(Debug)]
136pub struct SequenceNumberBuilder {
137    inner: Command,
138}
139
140impl SequenceNumberBuilder {
141    #[inline]
142    pub fn sequence_number(mut self, sequence_number: u32) -> PduBuilder {
143        self.inner.sequence_number = sequence_number;
144
145        PduBuilder { inner: self.inner }
146    }
147}
148
149#[derive(Debug)]
150pub struct PduBuilder {
151    inner: Command,
152}
153
154impl PduBuilder {
155    #[inline]
156    pub fn pdu(mut self, pdu: impl Into<Pdu>) -> Command {
157        self.inner.set_pdu(pdu);
158        self.inner
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    #[test]
167    fn encode_decode() {
168        crate::tests::owned::encode_decode_with_length_test_instances::<Command>();
169    }
170}