mqtt_protocol_core/mqtt/
arc_payload.rs

1/**
2 * MIT License
3 *
4 * Copyright (c) 2025 Takatoshi Kondo
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24use serde::{Serialize, Serializer};
25use std::sync::Arc;
26
27/// A reference-counted byte payload with slice semantics
28///
29/// `ArcPayload` provides an efficient way to handle byte data by using `Arc<[u8]>`
30/// for reference counting, combined with offset and length information to represent
31/// a slice view of the underlying data. This allows for zero-copy sharing of payload
32/// data across multiple consumers while maintaining slice-like semantics.
33#[derive(Clone, Debug)]
34pub struct ArcPayload {
35    data: Arc<[u8]>,
36    start: usize,
37    length: usize,
38}
39
40impl PartialEq for ArcPayload {
41    fn eq(&self, other: &Self) -> bool {
42        self.as_slice() == other.as_slice()
43    }
44}
45
46impl Eq for ArcPayload {}
47
48impl Serialize for ArcPayload {
49    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50    where
51        S: Serializer,
52    {
53        self.as_slice().serialize(serializer)
54    }
55}
56
57impl ArcPayload {
58    /// Create a new `ArcPayload` from reference-counted data with specified range
59    ///
60    /// Creates a new payload that represents a slice view of the provided `Arc<[u8]>` data
61    /// starting at the specified offset with the given length.
62    ///
63    /// # Parameters
64    ///
65    /// * `data` - The reference-counted byte data
66    /// * `start` - The starting offset within the data
67    /// * `length` - The length of the payload slice
68    ///
69    /// # Panics
70    ///
71    /// Panics in debug mode if `start + length > data.len()` (payload out of bounds)
72    ///
73    /// # Examples
74    ///
75    /// ```ignore
76    /// use std::sync::Arc;
77    /// use mqtt_protocol_core::mqtt::ArcPayload;
78    ///
79    /// let data = Arc::from(&b"hello world"[..]);
80    /// let payload = ArcPayload::new(data, 0, 5); // "hello"
81    /// ```
82    pub fn new(data: Arc<[u8]>, start: usize, length: usize) -> Self {
83        debug_assert!(start + length <= data.len(), "payload out of bounds",);
84        Self {
85            data,
86            start,
87            length,
88        }
89    }
90
91    /// Get a slice view of the payload data
92    ///
93    /// Returns a byte slice representing the payload data within the specified range.
94    ///
95    /// # Returns
96    ///
97    /// A `&[u8]` slice of the payload data
98    pub fn as_slice(&self) -> &[u8] {
99        &self.data[self.start..self.start + self.length]
100    }
101
102    /// Get the length of the payload
103    ///
104    /// Returns the number of bytes in the payload slice.
105    ///
106    /// # Returns
107    ///
108    /// The length of the payload in bytes
109    pub fn len(&self) -> usize {
110        self.length
111    }
112
113    /// Check if the payload is empty
114    ///
115    /// Returns `true` if the payload contains no bytes.
116    ///
117    /// # Returns
118    ///
119    /// `true` if the payload length is zero, `false` otherwise
120    pub fn is_empty(&self) -> bool {
121        self.length == 0
122    }
123
124    /// Get a reference to the underlying `Arc<[u8]>` data
125    ///
126    /// Returns a reference to the reference-counted byte array that contains
127    /// the actual data. This provides access to the full underlying data,
128    /// not just the slice view represented by this payload.
129    ///
130    /// # Returns
131    ///
132    /// A reference to the underlying `Arc<[u8]>` data
133    pub fn arc_data(&self) -> &Arc<[u8]> {
134        &self.data
135    }
136}
137
138impl Default for ArcPayload {
139    fn default() -> Self {
140        ArcPayload {
141            data: Arc::from(&[] as &[u8]),
142            start: 0,
143            length: 0,
144        }
145    }
146}
147
148/// Trait for converting various types into `ArcPayload`
149///
150/// This trait provides a uniform interface for converting different data types
151/// into `ArcPayload` instances. It allows for convenient creation of payloads
152/// from common types like strings, byte slices, vectors, and arrays.
153pub trait IntoPayload {
154    /// Convert the value into an `ArcPayload`
155    ///
156    /// # Returns
157    ///
158    /// An `ArcPayload` containing the converted data
159    fn into_payload(self) -> ArcPayload;
160}
161
162/// Convert a string slice (`&str`) into an `ArcPayload`
163impl IntoPayload for &str {
164    fn into_payload(self) -> ArcPayload {
165        let bytes = self.as_bytes();
166        ArcPayload::new(Arc::from(bytes), 0, bytes.len())
167    }
168}
169
170/// Convert an owned string (`String`) into an `ArcPayload`
171impl IntoPayload for String {
172    fn into_payload(self) -> ArcPayload {
173        let bytes = self.as_bytes();
174        ArcPayload::new(Arc::from(bytes), 0, bytes.len())
175    }
176}
177
178/// Convert a byte slice (`&[u8]`) into an `ArcPayload`
179impl IntoPayload for &[u8] {
180    fn into_payload(self) -> ArcPayload {
181        ArcPayload::new(Arc::from(self), 0, self.len())
182    }
183}
184
185/// Convert an owned byte vector (`Vec<u8>`) into an `ArcPayload`
186impl IntoPayload for Vec<u8> {
187    fn into_payload(self) -> ArcPayload {
188        let len = self.len();
189        ArcPayload::new(Arc::from(self), 0, len)
190    }
191}
192
193/// Convert a reference to a byte vector (`&Vec<u8>`) into an `ArcPayload`
194impl IntoPayload for &Vec<u8> {
195    fn into_payload(self) -> ArcPayload {
196        let slice: &[u8] = self.as_slice();
197        ArcPayload::new(Arc::from(slice), 0, slice.len())
198    }
199}
200
201/// Convert a reference to a byte array (`&[u8; N]`) into an `ArcPayload`
202impl<const N: usize> IntoPayload for &[u8; N] {
203    fn into_payload(self) -> ArcPayload {
204        let slice: &[u8] = self.as_slice();
205        ArcPayload::new(Arc::from(slice), 0, slice.len())
206    }
207}
208
209/// Convert an `Arc<[u8]>` directly into an `ArcPayload`
210impl IntoPayload for Arc<[u8]> {
211    fn into_payload(self) -> ArcPayload {
212        let len = self.len();
213        ArcPayload::new(self, 0, len)
214    }
215}
216
217/// Convert unit type (`()`) into an empty `ArcPayload`
218impl IntoPayload for () {
219    fn into_payload(self) -> ArcPayload {
220        ArcPayload::default() // Empty payload
221    }
222}
223
224/// Identity conversion for `ArcPayload` (no-op)
225impl IntoPayload for ArcPayload {
226    fn into_payload(self) -> ArcPayload {
227        self
228    }
229}