mqtt5_protocol/packet/
pingreq.rs1use crate::error::Result;
2use crate::packet::{FixedHeader, MqttPacket, PacketType};
3use bebytes::BeBytes;
4use bytes::{Buf, BufMut};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, BeBytes)]
8pub struct PingReqPacket {
9 #[bebytes(big_endian)]
11 fixed_header: u16, }
13
14impl PingReqPacket {
15 pub const FIXED_HEADER: u16 = 0xC000; }
18
19impl Default for PingReqPacket {
20 fn default() -> Self {
21 Self {
22 fixed_header: Self::FIXED_HEADER,
23 }
24 }
25}
26
27impl MqttPacket for PingReqPacket {
28 fn packet_type(&self) -> PacketType {
29 PacketType::PingReq
30 }
31
32 fn encode_body<B: BufMut>(&self, _buf: &mut B) -> Result<()> {
33 Ok(())
35 }
36
37 fn decode_body<B: Buf>(_buf: &mut B, _fixed_header: &FixedHeader) -> Result<Self> {
38 Ok(Self::default())
40 }
41}
42
43impl PingReqPacket {
44 #[must_use]
46 pub fn encode_complete(&self) -> Vec<u8> {
47 self.to_be_bytes()
48 }
49
50 pub fn decode_complete(data: &[u8]) -> Result<Self> {
59 let (packet, _consumed) = Self::try_from_be_bytes(data).map_err(|e| {
60 crate::error::MqttError::MalformedPacket(format!("Invalid PINGREQ packet: {e}"))
61 })?;
62
63 if packet.fixed_header != Self::FIXED_HEADER {
65 return Err(crate::error::MqttError::MalformedPacket(format!(
66 "Invalid PINGREQ packet: expected 0x{:04X}, got 0x{:04X}",
67 Self::FIXED_HEADER,
68 packet.fixed_header
69 )));
70 }
71
72 Ok(packet)
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use bytes::BytesMut;
80
81 #[cfg(test)]
82 mod property_tests {
83 use super::*;
84 use proptest::prelude::*;
85
86 proptest! {
87 #[test]
88 fn prop_pingreq_encode_decode_round_trip(_data in any::<u32>()) {
89 let packet = PingReqPacket::default();
90 let bytes = packet.encode_complete();
91 let decoded = PingReqPacket::decode_complete(&bytes).unwrap();
92
93 prop_assert_eq!(bytes, vec![0xC0, 0x00]);
95 prop_assert_eq!(decoded.packet_type(), PacketType::PingReq);
96 prop_assert_eq!(packet, decoded);
97 }
98
99 #[test]
100 fn prop_pingreq_consistent_encoding(_data in any::<u16>()) {
101 let packet1 = PingReqPacket::default();
102 let packet2 = PingReqPacket::default();
103
104 prop_assert_eq!(packet1.encode_complete(), packet2.encode_complete());
105 prop_assert_eq!(packet1, packet2);
106 }
107 }
108 }
109
110 #[test]
111 fn test_pingreq_bebytes_encode_decode() {
112 let packet = PingReqPacket::default();
113
114 let bytes = packet.encode_complete();
116 assert_eq!(bytes.len(), 2);
117 assert_eq!(bytes[0], 0xC0); assert_eq!(bytes[1], 0x00); let decoded = PingReqPacket::decode_complete(&bytes).unwrap();
122 assert_eq!(decoded, packet);
123 }
124
125 #[test]
126 fn test_pingreq_mqtt_packet_interface() {
127 let packet = PingReqPacket::default();
128
129 let mut buf = BytesMut::new();
130 packet.encode(&mut buf).unwrap();
131
132 assert_eq!(buf.len(), 2); assert_eq!(buf[0], 0xC0); assert_eq!(buf[1], 0x00); let fixed_header = FixedHeader::decode(&mut buf).unwrap();
137 assert_eq!(fixed_header.packet_type, PacketType::PingReq);
138 assert_eq!(fixed_header.remaining_length, 0);
139
140 let decoded = PingReqPacket::decode_body(&mut buf, &fixed_header).unwrap();
141 assert_eq!(decoded, packet);
142 }
143
144 #[test]
145 fn test_pingreq_malformed_data() {
146 let result = PingReqPacket::decode_complete(&[0xC0]);
148 assert!(result.is_err());
149
150 let result = PingReqPacket::decode_complete(&[0xD0, 0x00]);
152 assert!(result.is_err());
153 }
154}