1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use crate::{decoder::*, encoder::*, *};

// use alloc::{string::String, vec::Vec};
use heapless::{String, Vec, consts};


/// Publish packet ([MQTT 3.3]).
///
/// [MQTT 3.3]: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718037
#[derive(Debug, Clone, PartialEq)]
pub struct Publish<'a> {
    pub dup: bool,
    pub qospid: QosPid,
    pub retain: bool,
    pub topic_name: &'a str,
    pub payload: &'a [u8],
}

impl<'a> Publish<'a> {
    pub(crate) fn from_buffer(
        header: &Header,
        remaining_len: usize,
        buf: &'a [u8],
        offset: &mut usize,
    ) -> Result<Self, Error> {
        let payload_end = *offset + remaining_len;
        let topic_name = read_str(buf, offset)?;

        let qospid = match header.qos {
            QoS::AtMostOnce => QosPid::AtMostOnce,
            QoS::AtLeastOnce => QosPid::AtLeastOnce(Pid::from_buffer(buf, offset)?),
            QoS::ExactlyOnce => QosPid::ExactlyOnce(Pid::from_buffer(buf, offset)?),
        };

        Ok(Publish {
            dup: header.dup,
            qospid,
            retain: header.retain,
            topic_name,
            payload: &buf[*offset..payload_end],
        })
    }
    pub(crate) fn to_buffer(&self, buf: &mut [u8], offset: &mut usize) -> Result<usize, Error> {
        // Header
        let mut header: u8 = match self.qospid {
            QosPid::AtMostOnce => 0b00110000,
            QosPid::AtLeastOnce(_) => 0b00110010,
            QosPid::ExactlyOnce(_) => 0b00110100,
        };
        if self.dup {
            header |= 0b00001000 as u8;
        };
        if self.retain {
            header |= 0b00000001 as u8;
        };
        check_remaining(buf, offset, 1)?;
        write_u8(buf, offset, header)?;

        // Length: topic (2+len) + pid (0/2) + payload (len)
        let length = self.topic_name.len()
            + match self.qospid {
                QosPid::AtMostOnce => 2,
                _ => 4,
            }
            + self.payload.len();

        let write_len = write_length(buf, offset, length)? + 1;

        // Topic
        write_string(buf, offset, self.topic_name)?;

        // Pid
        match self.qospid {
            QosPid::AtMostOnce => (),
            QosPid::AtLeastOnce(pid) => pid.to_buffer(buf, offset)?,
            QosPid::ExactlyOnce(pid) => pid.to_buffer(buf, offset)?,
        }

        // Payload
        for &byte in self.payload {
            write_u8(buf, offset, byte)?;
        }

        Ok(write_len)
    }
}