mqute_codec/protocol/common/
payload.rs

1//! # Codes and Topic Filters
2//!
3//! This module provides utilities for handling MQTT protocol-specific data structures,
4//! specifically `Codes` and `TopicFilters`. These structures are used to encode and decode
5//! MQTT protocol data, such as return codes and topic filters, which are essential for
6//! MQTT communication.
7
8use crate::codec::util::{decode_string, encode_string};
9use crate::Error;
10use bytes::{Buf, BufMut, Bytes, BytesMut};
11use std::borrow::Borrow;
12use std::ops::{Index, IndexMut};
13
14/// The `Codes` module provides a generic structure to handle a collection of MQTT return codes.
15/// These codes are used in various MQTT control packets, such as ConnAck, SubAck, and UnsubAck.
16///
17/// # Example
18///
19/// ```rust
20/// use mqute_codec::protocol::{Codes, QoS};
21/// use mqute_codec::protocol::v4::ReturnCode;
22///
23/// let values = vec![ReturnCode::Failure, ReturnCode::Success(QoS::AtLeastOnce)];
24/// let codes: Codes<ReturnCode> = Codes::new(values);
25/// assert_eq!(codes.len(), 2);
26/// ```
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Codes<T>(Vec<T>);
29
30#[allow(clippy::len_without_is_empty)]
31impl<T> Codes<T>
32where
33    T: TryFrom<u8, Error = Error> + Into<u8> + Copy,
34{
35    /// Creates a new `Codes` instance from an iterator of codes.
36    ///
37    /// # Panics
38    ///
39    /// Panics if the iterator is empty, as at least one code is required.
40    pub fn new<I: IntoIterator<Item = T>>(codes: I) -> Self {
41        let values: Vec<T> = codes.into_iter().collect();
42
43        if values.is_empty() {
44            panic!("At least one code is required");
45        }
46
47        Codes(values)
48    }
49
50    /// Decodes a `Codes` instance from a byte buffer.
51    pub(crate) fn decode(payload: &mut Bytes) -> Result<Self, Error> {
52        let mut codes: Vec<T> = Vec::with_capacity(payload.len());
53        while payload.has_remaining() {
54            codes.push(payload.get_u8().try_into()?);
55        }
56
57        if codes.is_empty() {
58            return Err(Error::NoCodes);
59        }
60
61        Ok(codes.into())
62    }
63
64    /// Encodes the `Codes` instance into a byte buffer.
65    pub(crate) fn encode(&self, buf: &mut BytesMut) {
66        self.0.iter().for_each(|&value| {
67            buf.put_u8(value.into());
68        });
69    }
70
71    /// Returns the number of codes in the `Codes` instance.
72    pub fn len(&self) -> usize {
73        self.0.len()
74    }
75}
76
77impl<T> AsRef<Vec<T>> for Codes<T> {
78    #[inline]
79    fn as_ref(&self) -> &Vec<T> {
80        self.0.as_ref()
81    }
82}
83
84impl<T> Borrow<Vec<T>> for Codes<T> {
85    fn borrow(&self) -> &Vec<T> {
86        self.0.as_ref()
87    }
88}
89
90impl<T> IntoIterator for Codes<T> {
91    type Item = T;
92    type IntoIter = std::vec::IntoIter<T>;
93
94    fn into_iter(self) -> Self::IntoIter {
95        self.0.into_iter()
96    }
97}
98
99impl<T> FromIterator<T> for Codes<T> {
100    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
101        Codes(Vec::from_iter(iter))
102    }
103}
104
105impl<T> From<Codes<T>> for Vec<T> {
106    #[inline]
107    fn from(value: Codes<T>) -> Self {
108        value.0
109    }
110}
111
112impl<T> From<Vec<T>> for Codes<T> {
113    #[inline]
114    fn from(value: Vec<T>) -> Self {
115        Codes(value)
116    }
117}
118
119/// The `TopicFilters` provides a structure to handle a collection of MQTT topic filters.
120/// Topic filters are used in MQTT subscriptions and unsubscriptions.
121///
122/// # Example
123///
124/// ```rust
125/// use mqute_codec::protocol::TopicFilters;
126///
127/// let filters = TopicFilters::new(vec!["topic1", "topic2"]);
128///
129/// assert_eq!(filters.len(), 2);
130/// ```
131#[derive(Debug, Clone, PartialEq, Eq)]
132pub struct TopicFilters(Vec<String>);
133
134#[allow(clippy::len_without_is_empty)]
135impl TopicFilters {
136    /// Creates a new `TopicFilters` instance from an iterator of topic filters.
137    ///
138    /// # Panics
139    ///
140    /// Panics if the iterator is empty, as at least one topic filter is required.
141    pub fn new<T: IntoIterator<Item: Into<String>>>(filters: T) -> Self {
142        let values: Vec<String> = filters.into_iter().map(|x| x.into()).collect();
143
144        if values.is_empty() {
145            panic!("At least one topic filter is required");
146        }
147
148        TopicFilters(values)
149    }
150
151    /// Returns the number of topic filters in the `TopicFilters` instance.
152    pub fn len(&self) -> usize {
153        self.0.len()
154    }
155
156    /// Decodes a `TopicFilters` instance from a byte buffer.
157    pub(crate) fn decode(payload: &mut Bytes) -> Result<Self, Error> {
158        let mut filters = Vec::with_capacity(1);
159
160        while payload.has_remaining() {
161            let filter = decode_string(payload)?;
162
163            filters.push(filter);
164        }
165
166        if filters.is_empty() {
167            return Err(Error::NoTopic);
168        }
169
170        Ok(TopicFilters(filters))
171    }
172
173    /// Encodes the `TopicFilters` instance into a byte buffer.
174    pub(crate) fn encode(&self, buf: &mut BytesMut) {
175        self.0.iter().for_each(|filter| {
176            encode_string(buf, filter);
177        });
178    }
179
180    /// Calculates the encoded length of the `TopicFilters` instance.
181    pub(crate) fn encoded_len(&self) -> usize {
182        self.0.iter().fold(0, |acc, filter| acc + 2 + filter.len())
183    }
184}
185
186impl AsRef<Vec<String>> for TopicFilters {
187    #[inline]
188    fn as_ref(&self) -> &Vec<String> {
189        self.0.as_ref()
190    }
191}
192
193impl Borrow<Vec<String>> for TopicFilters {
194    fn borrow(&self) -> &Vec<String> {
195        self.0.as_ref()
196    }
197}
198
199impl IntoIterator for TopicFilters {
200    type Item = String;
201    type IntoIter = std::vec::IntoIter<String>;
202
203    fn into_iter(self) -> Self::IntoIter {
204        self.0.into_iter()
205    }
206}
207
208impl FromIterator<String> for TopicFilters {
209    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
210        TopicFilters(Vec::from_iter(iter))
211    }
212}
213
214impl From<TopicFilters> for Vec<String> {
215    #[inline]
216    fn from(value: TopicFilters) -> Self {
217        value.0
218    }
219}
220
221impl From<Vec<String>> for TopicFilters {
222    #[inline]
223    fn from(value: Vec<String>) -> Self {
224        TopicFilters(value)
225    }
226}
227
228impl<T> Index<usize> for Codes<T> {
229    type Output = T;
230    fn index(&self, index: usize) -> &Self::Output {
231        self.0.index(index)
232    }
233}
234
235impl<T> IndexMut<usize> for Codes<T> {
236    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
237        self.0.index_mut(index)
238    }
239}