scuffle_bytes_util/cow/
bytes.rs

1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::hash::Hash;
4
5use bytes::Bytes;
6
7#[cfg(feature = "serde")]
8pub(crate) mod serde;
9
10/// A [`Cow`] type for bytes.
11#[derive(Clone, Eq)]
12pub enum BytesCow<'a> {
13    /// A borrowed [`Bytes`] object.
14    Slice(&'a [u8]),
15    /// A staticly borrowed [`Bytes`] object.
16    StaticSlice(&'static [u8]),
17    /// An owned [`Vec`] of bytes.
18    Vec(Vec<u8>),
19    /// An owned [`Bytes`] object.
20    Bytes(Bytes),
21}
22
23impl Debug for BytesCow<'_> {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        // Taken from `bytes::Bytes` implementation
26        // https://github.com/tokio-rs/bytes/blob/f29e93951da599095f54d57667c1988960ceff71/src/fmt/debug.rs
27        write!(f, "b\"")?;
28        for &b in self.as_bytes() {
29            // https://doc.rust-lang.org/reference/tokens.html#byte-escapes
30            if b == b'\n' {
31                write!(f, "\\n")?;
32            } else if b == b'\r' {
33                write!(f, "\\r")?;
34            } else if b == b'\t' {
35                write!(f, "\\t")?;
36            } else if b == b'\\' || b == b'"' {
37                write!(f, "\\{}", b as char)?;
38            } else if b == b'\0' {
39                write!(f, "\\0")?;
40            // ASCII printable
41            } else if (0x20..0x7f).contains(&b) {
42                write!(f, "{}", b as char)?;
43            } else {
44                write!(f, "\\x{b:02x}")?;
45            }
46        }
47        write!(f, "\"")?;
48        Ok(())
49    }
50}
51
52impl Default for BytesCow<'_> {
53    fn default() -> Self {
54        Self::new()
55    }
56}
57
58impl<'a> BytesCow<'a> {
59    /// Creates an empty [`BytesCow`] object.
60    pub fn new() -> Self {
61        Self::from_static(b"")
62    }
63
64    /// Creates a new [`BytesCow`] from a static slice.
65    pub fn from_static(slice: &'static [u8]) -> Self {
66        Self::StaticSlice(slice)
67    }
68
69    /// Creates a new [`BytesCow`] from a slice of bytes.
70    pub fn from_slice(slice: &'a [u8]) -> Self {
71        Self::Slice(slice)
72    }
73
74    /// Creates a new [`BytesCow`] from a [`Bytes`] object.
75    pub fn from_bytes(bytes: Bytes) -> Self {
76        Self::Bytes(bytes)
77    }
78
79    /// Creates a new [`BytesCow`] from a [`Cow`] of a [`Bytes`] object.
80    pub fn from_cow(cow: Cow<'a, [u8]>) -> Self {
81        match cow {
82            Cow::Borrowed(slice) => Self::Slice(slice),
83            Cow::Owned(bytes) => Self::Vec(bytes),
84        }
85    }
86
87    /// Creates a new [`BytesCow`] from a [`Vec`] of bytes.
88    pub fn from_vec(bytes: Vec<u8>) -> Self {
89        Self::Vec(bytes)
90    }
91
92    /// Converts the object into a [`Bytes`] object.
93    pub fn into_bytes(self) -> Bytes {
94        match self {
95            Self::Slice(slice) => Bytes::copy_from_slice(slice),
96            Self::StaticSlice(slice) => Bytes::from_static(slice),
97            Self::Vec(bytes) => Bytes::from(bytes),
98            Self::Bytes(bytes) => bytes,
99        }
100    }
101
102    /// Returns a reference to the inner data as a slice.
103    pub fn as_bytes(&self) -> &[u8] {
104        match self {
105            Self::Slice(slice) => slice,
106            Self::StaticSlice(slice) => slice,
107            Self::Vec(bytes) => bytes.as_slice(),
108            Self::Bytes(bytes) => bytes.as_ref(),
109        }
110    }
111
112    /// Returns the length of this [`BytesCow`].
113    pub fn len(&self) -> usize {
114        match self {
115            Self::Slice(slice) => slice.len(),
116            Self::StaticSlice(slice) => slice.len(),
117            Self::Vec(bytes) => bytes.len(),
118            Self::Bytes(bytes) => bytes.len(),
119        }
120    }
121
122    /// Returns `true` if this [`BytesCow`] is empty.
123    pub fn is_empty(&self) -> bool {
124        match self {
125            Self::Slice(slice) => slice.is_empty(),
126            Self::StaticSlice(slice) => slice.is_empty(),
127            Self::Vec(bytes) => bytes.is_empty(),
128            Self::Bytes(bytes) => bytes.is_empty(),
129        }
130    }
131
132    /// Pads the bytes to a [`u64`].
133    ///
134    /// The bytes are expected to be in big-endian order.
135    ///
136    /// # Panics
137    ///
138    /// The caller must ensure that the length of the bytes is less than or equal to 8,
139    /// otherwise this function will panic.
140    pub fn pad_to_u64_be(&self) -> u64 {
141        assert!(self.len() <= 8);
142
143        // We copy the bytes into an 8 byte array and convert it to a u64
144        let mut buf = [0u8; 8];
145        buf[8 - self.len()..].copy_from_slice(self.as_bytes());
146        u64::from_be_bytes(buf)
147    }
148
149    /// Pads the bytes to a [`u32`].
150    ///
151    /// The bytes are expected to be in big-endian order.
152    ///
153    /// # Panics
154    ///
155    /// The caller must ensure that the length of the bytes is less than or equal to 4,
156    /// otherwise this function will panic.
157    pub fn pad_to_u32_be(&self) -> u32 {
158        assert!(self.len() <= 4);
159
160        // We copy the bytes into a 4 byte array and convert it to a u32
161        let mut buf = [0u8; 4];
162        buf[4 - self.len()..].copy_from_slice(self.as_bytes());
163        u32::from_be_bytes(buf)
164    }
165}
166
167impl<T> PartialEq<T> for BytesCow<'_>
168where
169    T: AsRef<[u8]>,
170{
171    fn eq(&self, other: &T) -> bool {
172        self.as_bytes() == other.as_ref()
173    }
174}
175
176impl Hash for BytesCow<'_> {
177    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
178        self.as_bytes().hash(state);
179    }
180}
181
182impl AsRef<[u8]> for BytesCow<'_> {
183    fn as_ref(&self) -> &[u8] {
184        self.as_bytes()
185    }
186}
187
188impl<'a> From<Cow<'a, [u8]>> for BytesCow<'a> {
189    fn from(cow: Cow<'a, [u8]>) -> Self {
190        BytesCow::from_cow(cow)
191    }
192}
193
194impl From<Bytes> for BytesCow<'_> {
195    fn from(bytes: Bytes) -> Self {
196        BytesCow::from_bytes(bytes)
197    }
198}
199
200impl<'a> From<&'a [u8]> for BytesCow<'a> {
201    fn from(bytes: &'a [u8]) -> Self {
202        BytesCow::from_slice(bytes)
203    }
204}
205
206impl From<Vec<u8>> for BytesCow<'_> {
207    fn from(bytes: Vec<u8>) -> Self {
208        BytesCow::from_vec(bytes)
209    }
210}
211
212#[cfg(test)]
213#[cfg_attr(all(test, coverage_nightly), coverage(off))]
214mod tests {
215    use super::BytesCow;
216
217    #[test]
218    fn constructors() {
219        let cow = BytesCow::default();
220        assert_eq!(cow.as_bytes(), b"");
221
222        let cow = BytesCow::from_static(b"hello");
223        assert_eq!(cow.as_bytes(), b"hello");
224
225        let cow = BytesCow::from_slice(b"world");
226        assert_eq!(cow.as_bytes(), b"world");
227
228        let cow = BytesCow::from_vec(vec![1, 2, 3]);
229        assert_eq!(cow.as_bytes(), &[1, 2, 3]);
230        let cow = BytesCow::from(vec![1, 2, 3]);
231        assert_eq!(cow.as_bytes(), &[1, 2, 3]);
232
233        let cow = BytesCow::from_bytes(bytes::Bytes::from_static(b"foo"));
234        assert_eq!(cow.as_bytes(), b"foo");
235        let cow = BytesCow::from(bytes::Bytes::from(vec![7, 8, 9]));
236        assert_eq!(cow.as_bytes(), &[7, 8, 9]);
237
238        let cow = BytesCow::from_cow(std::borrow::Cow::Borrowed(b"bar"));
239        assert_eq!(cow.as_bytes(), b"bar");
240        let cow = BytesCow::from_cow(std::borrow::Cow::Owned(vec![10, 11, 12]));
241        assert_eq!(cow.as_bytes(), &[10, 11, 12]);
242        let cow = BytesCow::from(std::borrow::Cow::Owned(vec![4, 5, 6]));
243        assert_eq!(cow.as_bytes(), &[4, 5, 6]);
244
245        let cow = BytesCow::from(&b"hello world"[..]);
246        assert_eq!(cow.as_bytes(), b"hello world");
247    }
248
249    #[test]
250    fn into_bytes() {
251        let cow = BytesCow::from_static(b"hello");
252        assert_eq!(cow.into_bytes(), bytes::Bytes::from_static(b"hello"));
253
254        let cow = BytesCow::from_slice(b"world");
255        assert_eq!(cow.into_bytes(), bytes::Bytes::from_static(b"world"));
256
257        let cow = BytesCow::from_vec(vec![1, 2, 3]);
258        assert_eq!(cow.into_bytes(), bytes::Bytes::from(vec![1, 2, 3]));
259
260        let cow = BytesCow::from_bytes(bytes::Bytes::from_static(b"foo"));
261        assert_eq!(cow.into_bytes(), bytes::Bytes::from_static(b"foo"));
262
263        let cow = BytesCow::from_cow(std::borrow::Cow::Borrowed(b"bar"));
264        assert_eq!(cow.into_bytes(), bytes::Bytes::from_static(b"bar"));
265
266        let cow = BytesCow::from_cow(std::borrow::Cow::Owned(vec![10, 11, 12]));
267        assert_eq!(cow.into_bytes(), bytes::Bytes::from(vec![10, 11, 12]));
268    }
269
270    #[test]
271    fn as_ref() {
272        let cow = BytesCow::from_static(b"hello");
273        assert_eq!(cow.as_ref(), b"hello");
274
275        let cow = BytesCow::from_slice(b"world");
276        assert_eq!(cow.as_ref(), b"world");
277
278        let cow = BytesCow::from_vec(vec![1, 2, 3]);
279        assert_eq!(cow.as_ref(), &[1, 2, 3]);
280
281        let cow = BytesCow::from_bytes(bytes::Bytes::from_static(b"foo"));
282        assert_eq!(cow.as_ref(), b"foo");
283    }
284
285    #[test]
286    fn partial_eq() {
287        let cow = BytesCow::from_static(b"hello");
288        assert!(cow == b"hello");
289        assert!(cow != b"world");
290
291        let cow = BytesCow::from_slice(b"world");
292        assert!(cow == b"world");
293        assert!(cow != b"hello");
294
295        let cow = BytesCow::from_vec(vec![1, 2, 3]);
296        assert!(cow == [1, 2, 3]);
297        assert!(cow != [4, 5, 6]);
298    }
299
300    #[test]
301    fn hash() {
302        use std::collections::hash_map::DefaultHasher;
303        use std::hash::{Hash, Hasher};
304
305        let mut hasher = DefaultHasher::new();
306        b"hello".hash(&mut hasher);
307        let expected_hash = hasher.finish();
308
309        let cow = BytesCow::from_static(b"hello");
310        let mut hasher = DefaultHasher::new();
311        cow.hash(&mut hasher);
312        assert_eq!(hasher.finish(), expected_hash);
313    }
314}