embedded_mqtt/variable_header/
publish.rs

1use core::{
2	convert::TryFrom,
3	result::Result,
4};
5
6use crate::{
7	fixed_header::{PacketFlags, PublishFlags},
8	codec::{self, Encodable},
9	status::Status,
10	error::{DecodeError, EncodeError},
11	qos,
12};
13
14use super::{PacketId, HeaderDecode};
15
16#[derive(Debug)]
17pub struct Publish<'a> {
18	topic_name: &'a str,
19	packet_identifier: Option<PacketId>,
20}
21
22impl<'a> Publish<'a> {
23	pub fn new(topic_name: &'a str, packet_identifier: Option<PacketId>) -> Self {
24		Self {
25			topic_name,
26			packet_identifier,
27		}
28	}
29
30	pub fn topic_name(&self) -> &'a str {
31		self.topic_name
32	}
33
34	pub fn packet_identifier(&self) -> Option<PacketId> {
35		self.packet_identifier
36	}
37}
38
39impl<'a> HeaderDecode<'a> for Publish<'a> {
40	fn decode(flags: PacketFlags, bytes: &'a [u8]) -> Result<Status<(usize, Self)>, DecodeError> {
41		let flags = PublishFlags::try_from(flags)?;
42
43		let offset = 0;
44		let (offset, topic_name) = read!(codec::string::parse_string, bytes, offset);
45
46		let (offset, packet_identifier) = if flags.qos()? != qos::QoS::AtMostOnce {
47			let (offset, packet_identifier) = read!(codec::values::parse_u16, bytes, offset);
48			(offset, Some(packet_identifier))
49		} else {
50			(offset, None)
51		};
52
53		Ok(Status::Complete((offset, Self {
54			topic_name,
55			packet_identifier
56		})))
57	}
58}
59
60impl<'a> Encodable for Publish<'a> {
61	fn encoded_len(&self) -> usize {
62		self.topic_name.encoded_len() + self.packet_identifier.map(|_| 2).unwrap_or(0)
63	}
64
65	fn encode(&self, bytes: &mut [u8]) -> Result<usize, EncodeError> {
66		let offset = 0;
67		let offset = {
68			let o = self.topic_name.encode(&mut bytes[offset..])?;
69			offset + o
70		};
71		let offset = if let Some(packet_identifier) = self.packet_identifier {
72			let o = codec::values::encode_u16(packet_identifier, &mut bytes[offset..])?;
73			offset + o
74		} else {
75			offset
76		};
77		Ok(offset)
78	}
79}
80
81#[cfg(test)]
82mod tests {
83	use super::*;
84
85	#[test]
86	fn encode() {
87		let header = Publish {
88			topic_name: "a/b",
89			packet_identifier: Some(1),
90		};
91
92		assert_eq!(7, header.encoded_len());
93
94		let mut buf = [0u8; 7];
95		let res = header.encode(&mut buf[..]);
96		assert_eq!(res, Ok(7));
97
98		assert_eq!(buf, [
99			0b0000_0000,
100			0b0000_0011,
101			0x61,
102			0x2f,
103			0x62,
104			0b0000_0000,
105			0b0000_0001,
106		]);
107	}
108}