smpp_codec/pdus/session_pdus/generic_nack.rs
1use crate::common::{get_status_code, get_status_description, PduError, GENERIC_NACK, HEADER_LEN};
2use std::io::{Cursor, Read, Write};
3
4/// Represents a Generic NACK PDU.
5///
6/// Sent when a PDU cannot be identified or is malformed (e.g., invalid Command ID).
7#[derive(Debug, Clone, PartialEq)]
8pub struct GenericNack {
9 /// Sequence number of the PDU
10 pub sequence_number: u32,
11 /// The error code explaining why the NACK was sent
12 pub command_status: u32, // The error code explaining why the NACK was sent
13 /// Human-readable status name
14 pub status_name: String,
15}
16
17impl GenericNack {
18 /// Create a new Generic NACK.
19 ///
20 /// # Examples
21 ///
22 /// ```
23 /// use smpp_codec::pdus::GenericNack;
24 ///
25 /// let sequence_number: u32 = 1;
26 /// let nack = GenericNack::new("ESME_RINVCMDID", sequence_number);
27 /// ```
28 pub fn new(status_name: &str, sequence_number: u32) -> Self {
29 let command_status = get_status_code(status_name);
30 Self {
31 sequence_number,
32 command_status,
33 status_name: status_name.to_string(),
34 }
35 }
36
37 /// Encode the struct into raw bytes for the network.
38 ///
39 /// # Errors
40 ///
41 /// Returns a [`PduError`] if an I/O error occurs while writing.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// # use smpp_codec::pdus::GenericNack;
47 /// # let sequence_number: u32 = 1;
48 /// # let nack = GenericNack::new("ESME_RINVCMDID", sequence_number);
49 /// let mut buffer = Vec::new();
50 /// nack.encode(&mut buffer).expect("Encoding failed");
51 /// ```
52 pub fn encode(&self, writer: &mut impl Write) -> Result<(), PduError> {
53 let command_len = HEADER_LEN as u32;
54 writer.write_all(&command_len.to_be_bytes())?;
55 writer.write_all(&GENERIC_NACK.to_be_bytes())?;
56 writer.write_all(&self.command_status.to_be_bytes())?;
57 writer.write_all(&self.sequence_number.to_be_bytes())?;
58 Ok(())
59 }
60
61 /// Decode raw bytes from the network into the struct.
62 ///
63 /// # Errors
64 ///
65 /// Returns a [`PduError`] if the buffer is too short.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// # use smpp_codec::pdus::GenericNack;
71 /// # let sequence_number: u32 = 1;
72 /// # let nack = GenericNack::new("ESME_RINVCMDID", sequence_number);
73 /// # let mut buffer = Vec::new();
74 /// # nack.encode(&mut buffer).unwrap();
75 /// let decoded = GenericNack::decode(&buffer).expect("Decoding failed");
76 /// assert_eq!(decoded.status_name, "ESME_RINVCMDID");
77 /// ```
78 pub fn decode(buffer: &[u8]) -> Result<Self, PduError> {
79 if buffer.len() < HEADER_LEN {
80 return Err(PduError::BufferTooShort);
81 }
82 let mut cursor = Cursor::new(buffer);
83
84 // Skip Length (4) and ID (4)
85 cursor.set_position(8);
86
87 let mut bytes = [0u8; 4];
88
89 // Status
90 cursor.read_exact(&mut bytes)?;
91 let command_status = u32::from_be_bytes(bytes);
92
93 // Sequence
94 cursor.read_exact(&mut bytes)?;
95 let sequence_number = u32::from_be_bytes(bytes);
96
97 Ok(Self {
98 sequence_number,
99 command_status,
100 status_name: get_status_description(command_status),
101 })
102 }
103}