mqtt_format/v3/
subscription_acks.rs1use futures::{AsyncWrite, AsyncWriteExt};
8use nom::{error::FromExternalError, multi::many1_count};
9
10use super::{
11 errors::{MPacketHeaderError, MPacketWriteError},
12 MSResult,
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct MSubscriptionAcks<'message> {
17 pub acks: &'message [MSubscriptionAck],
18}
19impl<'message> MSubscriptionAcks<'message> {
20 pub(crate) async fn write_to<W: AsyncWrite>(
21 &self,
22 writer: &mut std::pin::Pin<&mut W>,
23 ) -> Result<(), MPacketWriteError> {
24 writer
25 .write_all(unsafe {
26 std::mem::transmute(self.acks)
29 })
30 .await?;
31 Ok(())
32 }
33 pub(crate) fn get_len(&self) -> usize {
34 1
35 }
36}
37
38#[repr(u8)]
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum MSubscriptionAck {
41 MaximumQualityAtMostOnce = 0x00,
42 MaximumQualityAtLeastOnce = 0x01,
43 MaximumQualityExactlyOnce = 0x02,
44 Failure = 0x80,
45}
46
47fn msubscriptionack(input: &[u8]) -> MSResult<'_, MSubscriptionAck> {
48 let (input, data) = nom::number::complete::u8(input)?;
49
50 Ok((
51 input,
52 match data {
53 0x00 => MSubscriptionAck::MaximumQualityAtMostOnce,
54 0x01 => MSubscriptionAck::MaximumQualityAtLeastOnce,
55 0x02 => MSubscriptionAck::MaximumQualityExactlyOnce,
56 0x80 => MSubscriptionAck::Failure,
57 invalid_ack => {
58 return Err(nom::Err::Error(nom::error::Error::from_external_error(
59 input,
60 nom::error::ErrorKind::MapRes,
61 MPacketHeaderError::InvalidSubscriptionAck(invalid_ack),
62 )))
63 }
64 },
65 ))
66}
67
68pub fn msubscriptionacks<'message>(
69 input: &'message [u8],
70) -> MSResult<'message, MSubscriptionAcks<'message>> {
71 let acks = input;
72 let (input, acks_len) = many1_count(msubscriptionack)(input)?;
73
74 assert!(acks_len <= acks.len());
75
76 let ack_ptr: *const MSubscriptionAck = acks.as_ptr() as *const MSubscriptionAck;
77 let acks: &'message [MSubscriptionAck] = unsafe {
78 std::slice::from_raw_parts(ack_ptr, acks_len)
81 };
82
83 Ok((input, MSubscriptionAcks { acks }))
84}
85
86#[cfg(test)]
87mod tests {
88 use crate::v3::subscription_acks::MSubscriptionAck;
89
90 use super::msubscriptionacks;
91
92 #[test]
93 fn check_valid_subacks() {
94 let input = &[0x1, 0x2, 0x0, 0x80];
95
96 let (rest, sub_acks) = msubscriptionacks(input).unwrap();
97
98 assert_eq!(rest, &[]);
99 assert_eq!(
100 sub_acks.acks,
101 &[
102 MSubscriptionAck::MaximumQualityAtLeastOnce,
103 MSubscriptionAck::MaximumQualityExactlyOnce,
104 MSubscriptionAck::MaximumQualityAtMostOnce,
105 MSubscriptionAck::Failure,
106 ]
107 )
108 }
109
110 #[test]
111 fn check_invalid_subacks() {
112 let input = &[0x1, 0x5];
113
114 nom::combinator::all_consuming(msubscriptionacks)(input).unwrap_err();
115 }
116}