use super::property::check_property_type_list;
use super::{Properties, PropertyType, ReasonCode};
use crate::{
ByteArray, DecodeError, DecodePacket, EncodeError, EncodePacket, FixedHeader, Packet, PacketId,
PacketType, VarIntError,
};
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct SubscribeAckPacket {
packet_id: PacketId,
properties: Properties,
reasons: Vec<ReasonCode>,
}
pub const SUBSCRIBE_REASONS: &[ReasonCode] = &[
ReasonCode::Success,
ReasonCode::GrantedQoS1,
ReasonCode::GrantedQoS2,
ReasonCode::UnspecifiedError,
ReasonCode::ImplementationSpecificError,
ReasonCode::NotAuthorized,
ReasonCode::TopicFilterInvalid,
ReasonCode::PacketIdentifierInUse,
ReasonCode::QuotaExceeded,
ReasonCode::SharedSubscriptionNotSupported,
ReasonCode::SubscriptionIdentifiersNotSupported,
ReasonCode::WildcardSubscriptionsNotSupported,
];
pub const SUBSCRIBE_ACK_PROPERTIES: &[PropertyType] = &[
PropertyType::ReasonString,
PropertyType::UserProperty,
];
impl SubscribeAckPacket {
#[must_use]
pub fn new(packet_id: PacketId, reason: ReasonCode) -> Self {
Self {
packet_id,
properties: Properties::new(),
reasons: vec![reason],
}
}
#[must_use]
pub fn with_vec(packet_id: PacketId, reasons: Vec<ReasonCode>) -> Self {
Self {
packet_id,
properties: Properties::new(),
reasons,
}
}
pub fn set_packet_id(&mut self, packet_id: PacketId) -> &mut Self {
self.packet_id = packet_id;
self
}
#[must_use]
pub const fn packet_id(&self) -> PacketId {
self.packet_id
}
pub fn properties_mut(&mut self) -> &mut Properties {
&mut self.properties
}
#[must_use]
pub const fn properties(&self) -> &Properties {
&self.properties
}
pub fn reasons_mut(&mut self) -> &mut Vec<ReasonCode> {
&mut self.reasons
}
#[must_use]
pub fn reasons(&self) -> &[ReasonCode] {
&self.reasons
}
fn get_fixed_header(&self) -> Result<FixedHeader, VarIntError> {
let remaining_length =
PacketId::bytes() + self.properties.bytes() + self.reasons.len() * ReasonCode::bytes();
FixedHeader::new(PacketType::SubscribeAck, remaining_length)
}
}
impl DecodePacket for SubscribeAckPacket {
fn decode(ba: &mut ByteArray) -> Result<Self, DecodeError> {
let fixed_header = FixedHeader::decode(ba)?;
if fixed_header.packet_type() != PacketType::SubscribeAck {
return Err(DecodeError::InvalidPacketType);
}
let packet_id = PacketId::decode(ba)?;
let properties = Properties::decode(ba)?;
if let Err(property_type) =
check_property_type_list(properties.props(), SUBSCRIBE_ACK_PROPERTIES)
{
log::error!(
"v5/SubscribeAckPacket: property type {:?} cannot be used in properties!",
property_type
);
return Err(DecodeError::InvalidPropertyType);
}
let mut reasons = Vec::new();
let mut remaining_length = PacketId::bytes() + properties.bytes();
while remaining_length < fixed_header.remaining_length() {
let reason = ReasonCode::decode(ba)?;
if !SUBSCRIBE_REASONS.contains(&reason) {
return Err(DecodeError::InvalidReasonCode);
}
reasons.push(reason);
remaining_length += ReasonCode::bytes();
}
Ok(Self {
packet_id,
properties,
reasons,
})
}
}
impl EncodePacket for SubscribeAckPacket {
fn encode(&self, buf: &mut Vec<u8>) -> Result<usize, EncodeError> {
let old_len = buf.len();
let fixed_header = self.get_fixed_header()?;
fixed_header.encode(buf)?;
self.packet_id.encode(buf)?;
self.properties.encode(buf)?;
for reason in &self.reasons {
reason.encode(buf)?;
}
Ok(buf.len() - old_len)
}
}
impl Packet for SubscribeAckPacket {
fn packet_type(&self) -> PacketType {
PacketType::SubscribeAck
}
fn bytes(&self) -> Result<usize, VarIntError> {
let fixed_header = self.get_fixed_header()?;
Ok(fixed_header.bytes() + fixed_header.remaining_length())
}
}