use crate::anyvec::AnyVec;
use crate::coding::encoder::{BytesIter, OptionalU16Iter, PacketLenIter, U8Iter, Unit};
use crate::coding::length::Length;
use crate::coding::{Decoder, Encoder};
use crate::err;
use crate::error::{Data, DecoderError, MemoryError};
use crate::packets::TryFromIterator;
use core::iter::Chain;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Publish<Bytes> {
dup: bool,
qos: u8,
retain: bool,
topic: Bytes,
packet_id: Option<u16>,
payload: Bytes,
}
impl<Bytes> Publish<Bytes>
where
Bytes: AnyVec<u8>,
{
pub const TYPE: u8 = 3;
pub fn new<T, P>(topic: T, payload: P, retain: bool) -> Result<Self, MemoryError>
where
T: AsRef<[u8]>,
P: AsRef<[u8]>,
{
let topic = Bytes::new(topic.as_ref())?;
let payload = Bytes::new(payload.as_ref())?;
Ok(Self { dup: false, qos: 0, retain, topic, packet_id: None, payload })
}
pub fn with_qos(mut self, qos: u8, packet_id: u16, dup: bool) -> Self {
self.dup = dup;
self.qos = qos;
self.packet_id = Some(packet_id);
self
}
pub fn topic(&self) -> &[u8] {
self.topic.as_ref()
}
pub fn payload(&self) -> &[u8] {
self.payload.as_ref()
}
pub fn retain(&self) -> bool {
self.retain
}
pub fn dup(&self) -> bool {
self.dup
}
pub fn qos(&self) -> u8 {
self.qos
}
pub fn packet_id(&self) -> Option<u16> {
self.packet_id
}
}
impl<Bytes> TryFromIterator for Publish<Bytes>
where
Bytes: AnyVec<u8>,
{
fn try_from_iter<T>(iter: T) -> Result<Self, DecoderError>
where
T: IntoIterator<Item = u8>,
{
let mut decoder = Decoder::new(iter);
let (Self::TYPE, [dup, qos0, qos1, retain]) = decoder.header()? else {
return Err(err!(Data::SpecViolation, "invalid packet type"))?;
};
let len = decoder.packetlen()?;
let mut decoder = decoder.limit(len);
let topic = decoder.bytes()?;
let packet_id = decoder.optional_u16(qos0 || qos1)?;
let payload = decoder.raw_remainder()?;
let qos = ((qos0 as u8) << 1) | (qos1 as u8);
Ok(Self { dup, qos, retain, topic, packet_id, payload })
}
}
impl<Bytes> IntoIterator for Publish<Bytes>
where
Bytes: AnyVec<u8>,
{
type Item = u8;
#[rustfmt::skip]
type IntoIter =
Chain<Chain<Chain<Chain<Chain<
Unit, U8Iter>,
PacketLenIter>,
BytesIter<Bytes>>,
OptionalU16Iter>,
<Bytes as IntoIterator>::IntoIter>;
fn into_iter(self) -> Self::IntoIter {
#[rustfmt::skip]
let flags = [
self.dup,
(self.qos >> 1) != 0,
(self.qos & 1) != 0,
self.retain
];
#[rustfmt::skip]
let len = Length::new()
.bytes(&self.topic)
.optional_u16(&self.packet_id)
.raw(&self.payload)
.into();
Encoder::default()
.header(Self::TYPE, flags)
.packetlen(len)
.bytes(self.topic)
.optional_u16(self.packet_id)
.raw(self.payload)
.into_iter()
}
}