facet_value/
bytes.rs

1//! Bytes value type for binary data.
2
3#[cfg(feature = "alloc")]
4use alloc::alloc::{Layout, alloc, dealloc};
5#[cfg(feature = "alloc")]
6use alloc::vec::Vec;
7use core::borrow::Borrow;
8use core::cmp::Ordering;
9use core::fmt::{self, Debug, Formatter};
10use core::hash::{Hash, Hasher};
11use core::ops::Deref;
12use core::ptr;
13
14use crate::value::{TypeTag, Value};
15
16/// Header for heap-allocated bytes.
17#[repr(C, align(8))]
18struct BytesHeader {
19    /// Length of the data in bytes
20    len: usize,
21    // Byte data follows immediately after
22}
23
24/// A binary data value.
25///
26/// `VBytes` stores arbitrary binary data. This is useful for binary serialization
27/// formats like MessagePack, CBOR, etc. that support raw bytes.
28#[repr(transparent)]
29#[derive(Clone)]
30pub struct VBytes(pub(crate) Value);
31
32impl VBytes {
33    fn layout(len: usize) -> Layout {
34        Layout::new::<BytesHeader>()
35            .extend(Layout::array::<u8>(len).unwrap())
36            .unwrap()
37            .0
38            .pad_to_align()
39    }
40
41    #[cfg(feature = "alloc")]
42    fn alloc(data: &[u8]) -> *mut BytesHeader {
43        unsafe {
44            let layout = Self::layout(data.len());
45            let ptr = alloc(layout).cast::<BytesHeader>();
46            (*ptr).len = data.len();
47
48            // Copy byte data
49            let data_ptr = ptr.add(1).cast::<u8>();
50            ptr::copy_nonoverlapping(data.as_ptr(), data_ptr, data.len());
51
52            ptr
53        }
54    }
55
56    #[cfg(feature = "alloc")]
57    fn dealloc_ptr(ptr: *mut BytesHeader) {
58        unsafe {
59            let len = (*ptr).len;
60            let layout = Self::layout(len);
61            dealloc(ptr.cast::<u8>(), layout);
62        }
63    }
64
65    fn header(&self) -> &BytesHeader {
66        unsafe { &*(self.0.heap_ptr() as *const BytesHeader) }
67    }
68
69    fn data_ptr(&self) -> *const u8 {
70        // Go through heap_ptr directly to avoid creating intermediate reference
71        // that would limit provenance to just the header
72        unsafe { (self.0.heap_ptr() as *const BytesHeader).add(1).cast() }
73    }
74
75    /// Creates new bytes from a byte slice.
76    #[cfg(feature = "alloc")]
77    #[must_use]
78    pub fn new(data: &[u8]) -> Self {
79        if data.is_empty() {
80            return Self::empty();
81        }
82        unsafe {
83            let ptr = Self::alloc(data);
84            VBytes(Value::new_ptr(ptr.cast(), TypeTag::BytesOrFalse))
85        }
86    }
87
88    /// Creates empty bytes.
89    #[cfg(feature = "alloc")]
90    #[must_use]
91    pub fn empty() -> Self {
92        unsafe {
93            let layout = Self::layout(0);
94            let ptr = alloc(layout).cast::<BytesHeader>();
95            (*ptr).len = 0;
96            VBytes(Value::new_ptr(ptr.cast(), TypeTag::BytesOrFalse))
97        }
98    }
99
100    /// Returns the length of the bytes.
101    #[must_use]
102    pub fn len(&self) -> usize {
103        self.header().len
104    }
105
106    /// Returns `true` if the bytes are empty.
107    #[must_use]
108    pub fn is_empty(&self) -> bool {
109        self.len() == 0
110    }
111
112    /// Returns the data as a byte slice.
113    #[must_use]
114    pub fn as_slice(&self) -> &[u8] {
115        unsafe { core::slice::from_raw_parts(self.data_ptr(), self.len()) }
116    }
117
118    pub(crate) fn clone_impl(&self) -> Value {
119        VBytes::new(self.as_slice()).0
120    }
121
122    pub(crate) fn drop_impl(&mut self) {
123        unsafe {
124            Self::dealloc_ptr(self.0.heap_ptr_mut().cast());
125        }
126    }
127}
128
129impl Deref for VBytes {
130    type Target = [u8];
131
132    fn deref(&self) -> &[u8] {
133        self.as_slice()
134    }
135}
136
137impl Borrow<[u8]> for VBytes {
138    fn borrow(&self) -> &[u8] {
139        self.as_slice()
140    }
141}
142
143impl AsRef<[u8]> for VBytes {
144    fn as_ref(&self) -> &[u8] {
145        self.as_slice()
146    }
147}
148
149impl PartialEq for VBytes {
150    fn eq(&self, other: &Self) -> bool {
151        self.as_slice() == other.as_slice()
152    }
153}
154
155impl Eq for VBytes {}
156
157impl PartialOrd for VBytes {
158    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
159        Some(self.cmp(other))
160    }
161}
162
163impl Ord for VBytes {
164    fn cmp(&self, other: &Self) -> Ordering {
165        self.as_slice().cmp(other.as_slice())
166    }
167}
168
169impl Hash for VBytes {
170    fn hash<H: Hasher>(&self, state: &mut H) {
171        self.as_slice().hash(state);
172    }
173}
174
175impl Debug for VBytes {
176    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
177        // Display as hex for readability
178        write!(f, "b\"")?;
179        for byte in self.as_slice() {
180            write!(f, "\\x{byte:02x}")?;
181        }
182        write!(f, "\"")
183    }
184}
185
186impl Default for VBytes {
187    fn default() -> Self {
188        Self::empty()
189    }
190}
191
192// === PartialEq with [u8] ===
193
194impl PartialEq<[u8]> for VBytes {
195    fn eq(&self, other: &[u8]) -> bool {
196        self.as_slice() == other
197    }
198}
199
200impl PartialEq<VBytes> for [u8] {
201    fn eq(&self, other: &VBytes) -> bool {
202        self == other.as_slice()
203    }
204}
205
206impl PartialEq<&[u8]> for VBytes {
207    fn eq(&self, other: &&[u8]) -> bool {
208        self.as_slice() == *other
209    }
210}
211
212#[cfg(feature = "alloc")]
213impl PartialEq<Vec<u8>> for VBytes {
214    fn eq(&self, other: &Vec<u8>) -> bool {
215        self.as_slice() == other.as_slice()
216    }
217}
218
219#[cfg(feature = "alloc")]
220impl PartialEq<VBytes> for Vec<u8> {
221    fn eq(&self, other: &VBytes) -> bool {
222        self.as_slice() == other.as_slice()
223    }
224}
225
226// === From implementations ===
227
228#[cfg(feature = "alloc")]
229impl From<&[u8]> for VBytes {
230    fn from(data: &[u8]) -> Self {
231        Self::new(data)
232    }
233}
234
235#[cfg(feature = "alloc")]
236impl From<Vec<u8>> for VBytes {
237    fn from(data: Vec<u8>) -> Self {
238        Self::new(&data)
239    }
240}
241
242#[cfg(feature = "alloc")]
243impl From<&Vec<u8>> for VBytes {
244    fn from(data: &Vec<u8>) -> Self {
245        Self::new(data)
246    }
247}
248
249#[cfg(feature = "alloc")]
250impl From<VBytes> for Vec<u8> {
251    fn from(b: VBytes) -> Self {
252        b.as_slice().to_vec()
253    }
254}
255
256// === Value conversions ===
257
258impl AsRef<Value> for VBytes {
259    fn as_ref(&self) -> &Value {
260        &self.0
261    }
262}
263
264impl AsMut<Value> for VBytes {
265    fn as_mut(&mut self) -> &mut Value {
266        &mut self.0
267    }
268}
269
270impl From<VBytes> for Value {
271    fn from(b: VBytes) -> Self {
272        b.0
273    }
274}
275
276impl VBytes {
277    /// Converts this VBytes into a Value, consuming self.
278    #[inline]
279    pub fn into_value(self) -> Value {
280        self.0
281    }
282}
283
284#[cfg(feature = "alloc")]
285impl From<&[u8]> for Value {
286    fn from(data: &[u8]) -> Self {
287        VBytes::new(data).0
288    }
289}
290
291#[cfg(feature = "alloc")]
292impl From<Vec<u8>> for Value {
293    fn from(data: Vec<u8>) -> Self {
294        VBytes::new(&data).0
295    }
296}
297
298#[cfg(test)]
299mod tests {
300    use super::*;
301
302    #[test]
303    fn test_new() {
304        let b = VBytes::new(&[1, 2, 3, 4, 5]);
305        assert_eq!(b.as_slice(), &[1, 2, 3, 4, 5]);
306        assert_eq!(b.len(), 5);
307        assert!(!b.is_empty());
308    }
309
310    #[test]
311    fn test_empty() {
312        let b = VBytes::empty();
313        assert_eq!(b.as_slice(), &[] as &[u8]);
314        assert_eq!(b.len(), 0);
315        assert!(b.is_empty());
316    }
317
318    #[test]
319    fn test_equality() {
320        let a = VBytes::new(&[1, 2, 3]);
321        let b = VBytes::new(&[1, 2, 3]);
322        let c = VBytes::new(&[4, 5, 6]);
323
324        assert_eq!(a, b);
325        assert_ne!(a, c);
326        assert_eq!(a, [1, 2, 3].as_slice());
327    }
328
329    #[test]
330    fn test_clone() {
331        let a = VBytes::new(&[0xDE, 0xAD, 0xBE, 0xEF]);
332        let b = a.clone();
333        assert_eq!(a, b);
334    }
335
336    #[test]
337    fn test_ordering() {
338        let a = VBytes::new(&[1, 2, 3]);
339        let b = VBytes::new(&[1, 2, 4]);
340        assert!(a < b);
341    }
342
343    #[test]
344    fn test_debug() {
345        let b = VBytes::new(&[0xDE, 0xAD]);
346        let s = format!("{b:?}");
347        assert_eq!(s, "b\"\\xde\\xad\"");
348    }
349}