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