Skip to main content

mountain_mqtt/packets/
packet.rs

1use crate::data::packet_type::PacketType;
2use crate::{
3    codec::{
4        mqtt_reader::{self, MqttReader},
5        mqtt_writer::{self, MqttLenWriter, MqttWriter},
6        read::Read,
7        write::Write,
8    },
9    error::PacketReadError,
10};
11
12pub const KEEP_ALIVE_DEFAULT: u16 = 60;
13pub const PROTOCOL_NAME: &str = "MQTT";
14pub const PROTOCOL_VERSION_5: u8 = 0x05;
15
16pub trait Packet {
17    fn packet_type(&self) -> PacketType;
18    fn fixed_header_first_byte(&self) -> u8 {
19        self.packet_type().into()
20    }
21}
22
23pub trait PacketWrite: Packet {
24    fn put_variable_header_and_payload<'w, W: MqttWriter<'w>>(
25        &self,
26        writer: &mut W,
27    ) -> mqtt_writer::Result<()>;
28}
29
30impl<P: PacketWrite> Write for P {
31    fn write<'w, W: MqttWriter<'w>>(&self, writer: &mut W) -> mqtt_writer::Result<()> {
32        // Find length of variable header, and payload
33        let mut lw = MqttLenWriter::new();
34        self.put_variable_header_and_payload(&mut lw)?;
35        let remaining_length = lw.position();
36
37        // fixed header including length, then variable header and payload
38        writer.put_u8(self.fixed_header_first_byte())?;
39        writer.put_variable_u32(remaining_length as u32)?;
40        self.put_variable_header_and_payload(writer)?;
41
42        Ok(())
43    }
44}
45
46pub trait PacketRead<'a>: Packet {
47    /// Read the variable header and payload from a reader
48    /// Note that the reader is NOT necessarily at position 0 when provided,
49    /// so implementations must check position if needed.
50    /// The first header byte is provided - this only needs to be used if
51    /// it may contain information in addition to the [PacketType] -
52    /// since this trait extends [Packet] it's required that
53    /// any user of this trait independently checks that the
54    /// first header byte matches the expected [PacketType] before
55    /// calling this method.
56    /// `len` is the remaining length read from the fixed header,
57    /// and so is the amount of data expected to be present in the
58    /// reader and needed to decode the variable header and payload.
59    /// As noted above, the reader position may not begin at 0, so
60    /// if you need to track the amount of data read against len,
61    /// make sure to check the reader position before using it.
62    fn get_variable_header_and_payload<R: MqttReader<'a>>(
63        reader: &mut R,
64        first_header_byte: u8,
65        len: usize,
66    ) -> mqtt_reader::Result<Self>
67    where
68        Self: Sized;
69}
70
71impl<'a, P: PacketRead<'a>> Read<'a> for P {
72    fn read<R: MqttReader<'a>>(reader: &mut R) -> mqtt_reader::Result<Self>
73    where
74        Self: Sized,
75    {
76        let first_header_byte = reader.get_u8()?;
77
78        let remaining_length = reader.get_variable_u32()? as usize;
79        let packet_end_position = reader.position() + remaining_length;
80
81        let packet = <Self as PacketRead>::get_variable_header_and_payload(
82            reader,
83            first_header_byte,
84            remaining_length,
85        )?;
86
87        // Check that packet type is as expected, so `PacketRead` implementation
88        // doesn't have to
89        let packet_type = PacketType::try_from(first_header_byte)?;
90        if packet_type != packet.packet_type() {
91            return Err(PacketReadError::IncorrectPacketType);
92        }
93
94        // Check remaining length was correct
95        if reader.position() == packet_end_position {
96            Ok(packet)
97        } else {
98            Err(PacketReadError::IncorrectPacketLength)
99        }
100    }
101}