• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 19774894729

28 Nov 2025 10:22PM UTC coverage: 59.711% (-0.6%) from 60.346%
19774894729

push

github

fasterthanlime
Add DynamicValue support for deserializing into facet_value::Value

This adds support for deserializing JSON (and potentially other formats)
into facet_value::Value without format crates needing to depend on facet-value.

Key changes:
- Add Def::DynamicValue variant with vtable for building dynamic values
- Implement Facet trait for Value in facet-value
- Extend Partial to handle DynamicValue scalars via set_into_dynamic_value
- Add deserialize_dynamic_value handler in facet-json

Currently supports scalar values (null, bool, numbers, strings).
Arrays and objects are stubbed out with TODO errors.

451 of 922 new or added lines in 20 files covered. (48.92%)

29 existing lines in 3 files now uncovered.

16657 of 27896 relevant lines covered (59.71%)

153.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.48
/facet-value/src/bytes.rs
1
//! Bytes value type for binary data.
2

3
#[cfg(feature = "alloc")]
4
use alloc::alloc::{Layout, alloc, dealloc};
5
#[cfg(feature = "alloc")]
6
use alloc::vec::Vec;
7
use core::borrow::Borrow;
8
use core::cmp::Ordering;
9
use core::fmt::{self, Debug, Formatter};
10
use core::hash::{Hash, Hasher};
11
use core::ops::Deref;
12
use core::ptr;
13

14
use crate::value::{TypeTag, Value};
15

16
/// Header for heap-allocated bytes.
17
#[repr(C, align(8))]
18
struct 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)]
30
pub struct VBytes(pub(crate) Value);
31

32
impl VBytes {
33
    fn layout(len: usize) -> Layout {
20✔
34
        Layout::new::<BytesHeader>()
20✔
35
            .extend(Layout::array::<u8>(len).unwrap())
20✔
36
            .unwrap()
20✔
37
            .0
20✔
38
            .pad_to_align()
20✔
39
    }
20✔
40

41
    #[cfg(feature = "alloc")]
42
    fn alloc(data: &[u8]) -> *mut BytesHeader {
9✔
43
        unsafe {
44
            let layout = Self::layout(data.len());
9✔
45
            let ptr = alloc(layout).cast::<BytesHeader>();
9✔
46
            (*ptr).len = data.len();
9✔
47

48
            // Copy byte data
49
            let data_ptr = ptr.add(1).cast::<u8>();
9✔
50
            ptr::copy_nonoverlapping(data.as_ptr(), data_ptr, data.len());
9✔
51

52
            ptr
9✔
53
        }
54
    }
9✔
55

56
    #[cfg(feature = "alloc")]
57
    fn dealloc_ptr(ptr: *mut BytesHeader) {
10✔
58
        unsafe {
10✔
59
            let len = (*ptr).len;
10✔
60
            let layout = Self::layout(len);
10✔
61
            dealloc(ptr.cast::<u8>(), layout);
10✔
62
        }
10✔
63
    }
10✔
64

65
    fn header(&self) -> &BytesHeader {
30✔
66
        unsafe { &*(self.0.heap_ptr() as *const BytesHeader) }
30✔
67
    }
30✔
68

69
    fn data_ptr(&self) -> *const u8 {
13✔
70
        unsafe { (self.header() as *const BytesHeader).add(1).cast() }
13✔
71
    }
13✔
72

73
    /// Creates new bytes from a byte slice.
74
    #[cfg(feature = "alloc")]
75
    #[must_use]
76
    pub fn new(data: &[u8]) -> Self {
9✔
77
        if data.is_empty() {
9✔
78
            return Self::empty();
×
79
        }
9✔
80
        unsafe {
81
            let ptr = Self::alloc(data);
9✔
82
            VBytes(Value::new_ptr(ptr.cast(), TypeTag::BytesOrFalse))
9✔
83
        }
84
    }
9✔
85

86
    /// Creates empty bytes.
87
    #[cfg(feature = "alloc")]
88
    #[must_use]
89
    pub fn empty() -> Self {
1✔
90
        unsafe {
91
            let layout = Self::layout(0);
1✔
92
            let ptr = alloc(layout).cast::<BytesHeader>();
1✔
93
            (*ptr).len = 0;
1✔
94
            VBytes(Value::new_ptr(ptr.cast(), TypeTag::BytesOrFalse))
1✔
95
        }
96
    }
1✔
97

98
    /// Returns the length of the bytes.
99
    #[must_use]
100
    pub fn len(&self) -> usize {
17✔
101
        self.header().len
17✔
102
    }
17✔
103

104
    /// Returns `true` if the bytes are empty.
105
    #[must_use]
106
    pub fn is_empty(&self) -> bool {
2✔
107
        self.len() == 0
2✔
108
    }
2✔
109

110
    /// Returns the data as a byte slice.
111
    #[must_use]
112
    pub fn as_slice(&self) -> &[u8] {
13✔
113
        unsafe { core::slice::from_raw_parts(self.data_ptr(), self.len()) }
13✔
114
    }
13✔
115

116
    pub(crate) fn clone_impl(&self) -> Value {
1✔
117
        VBytes::new(self.as_slice()).0
1✔
118
    }
1✔
119

120
    pub(crate) fn drop_impl(&mut self) {
10✔
121
        unsafe {
10✔
122
            Self::dealloc_ptr(self.0.heap_ptr().cast());
10✔
123
        }
10✔
124
    }
10✔
125
}
126

127
impl Deref for VBytes {
128
    type Target = [u8];
129

130
    fn deref(&self) -> &[u8] {
×
131
        self.as_slice()
×
132
    }
×
133
}
134

135
impl Borrow<[u8]> for VBytes {
136
    fn borrow(&self) -> &[u8] {
×
137
        self.as_slice()
×
138
    }
×
139
}
140

141
impl AsRef<[u8]> for VBytes {
142
    fn as_ref(&self) -> &[u8] {
×
143
        self.as_slice()
×
144
    }
×
145
}
146

147
impl PartialEq for VBytes {
148
    fn eq(&self, other: &Self) -> bool {
3✔
149
        self.as_slice() == other.as_slice()
3✔
150
    }
3✔
151
}
152

153
impl Eq for VBytes {}
154

155
impl PartialOrd for VBytes {
156
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1✔
157
        Some(self.cmp(other))
1✔
158
    }
1✔
159
}
160

161
impl Ord for VBytes {
162
    fn cmp(&self, other: &Self) -> Ordering {
1✔
163
        self.as_slice().cmp(other.as_slice())
1✔
164
    }
1✔
165
}
166

167
impl Hash for VBytes {
168
    fn hash<H: Hasher>(&self, state: &mut H) {
×
169
        self.as_slice().hash(state);
×
170
    }
×
171
}
172

173
impl Debug for VBytes {
174
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1✔
175
        // Display as hex for readability
176
        write!(f, "b\"")?;
1✔
177
        for byte in self.as_slice() {
2✔
178
            write!(f, "\\x{byte:02x}")?;
2✔
179
        }
180
        write!(f, "\"")
1✔
181
    }
1✔
182
}
183

184
impl Default for VBytes {
185
    fn default() -> Self {
×
186
        Self::empty()
×
187
    }
×
188
}
189

190
// === PartialEq with [u8] ===
191

192
impl PartialEq<[u8]> for VBytes {
193
    fn eq(&self, other: &[u8]) -> bool {
×
194
        self.as_slice() == other
×
195
    }
×
196
}
197

198
impl PartialEq<VBytes> for [u8] {
199
    fn eq(&self, other: &VBytes) -> bool {
×
200
        self == other.as_slice()
×
201
    }
×
202
}
203

204
impl PartialEq<&[u8]> for VBytes {
205
    fn eq(&self, other: &&[u8]) -> bool {
1✔
206
        self.as_slice() == *other
1✔
207
    }
1✔
208
}
209

210
#[cfg(feature = "alloc")]
211
impl PartialEq<Vec<u8>> for VBytes {
212
    fn eq(&self, other: &Vec<u8>) -> bool {
×
213
        self.as_slice() == other.as_slice()
×
214
    }
×
215
}
216

217
#[cfg(feature = "alloc")]
218
impl PartialEq<VBytes> for Vec<u8> {
219
    fn eq(&self, other: &VBytes) -> bool {
×
220
        self.as_slice() == other.as_slice()
×
221
    }
×
222
}
223

224
// === From implementations ===
225

226
#[cfg(feature = "alloc")]
227
impl From<&[u8]> for VBytes {
228
    fn from(data: &[u8]) -> Self {
×
229
        Self::new(data)
×
230
    }
×
231
}
232

233
#[cfg(feature = "alloc")]
234
impl From<Vec<u8>> for VBytes {
235
    fn from(data: Vec<u8>) -> Self {
×
236
        Self::new(&data)
×
237
    }
×
238
}
239

240
#[cfg(feature = "alloc")]
241
impl From<&Vec<u8>> for VBytes {
242
    fn from(data: &Vec<u8>) -> Self {
×
243
        Self::new(data)
×
244
    }
×
245
}
246

247
#[cfg(feature = "alloc")]
248
impl From<VBytes> for Vec<u8> {
249
    fn from(b: VBytes) -> Self {
×
250
        b.as_slice().to_vec()
×
251
    }
×
252
}
253

254
// === Value conversions ===
255

256
impl AsRef<Value> for VBytes {
257
    fn as_ref(&self) -> &Value {
×
258
        &self.0
×
259
    }
×
260
}
261

262
impl AsMut<Value> for VBytes {
263
    fn as_mut(&mut self) -> &mut Value {
×
264
        &mut self.0
×
265
    }
×
266
}
267

268
impl From<VBytes> for Value {
269
    fn from(b: VBytes) -> Self {
×
270
        b.0
×
271
    }
×
272
}
273

274
impl VBytes {
275
    /// Converts this VBytes into a Value, consuming self.
276
    #[inline]
NEW
277
    pub fn into_value(self) -> Value {
×
NEW
278
        self.0
×
NEW
279
    }
×
280
}
281

282
#[cfg(feature = "alloc")]
283
impl From<&[u8]> for Value {
284
    fn from(data: &[u8]) -> Self {
×
285
        VBytes::new(data).0
×
286
    }
×
287
}
288

289
#[cfg(feature = "alloc")]
290
impl From<Vec<u8>> for Value {
291
    fn from(data: Vec<u8>) -> Self {
×
292
        VBytes::new(&data).0
×
293
    }
×
294
}
295

296
#[cfg(test)]
297
mod tests {
298
    use super::*;
299

300
    #[test]
301
    fn test_new() {
1✔
302
        let b = VBytes::new(&[1, 2, 3, 4, 5]);
1✔
303
        assert_eq!(b.as_slice(), &[1, 2, 3, 4, 5]);
1✔
304
        assert_eq!(b.len(), 5);
1✔
305
        assert!(!b.is_empty());
1✔
306
    }
1✔
307

308
    #[test]
309
    fn test_empty() {
1✔
310
        let b = VBytes::empty();
1✔
311
        assert_eq!(b.as_slice(), &[]);
1✔
312
        assert_eq!(b.len(), 0);
1✔
313
        assert!(b.is_empty());
1✔
314
    }
1✔
315

316
    #[test]
317
    fn test_equality() {
1✔
318
        let a = VBytes::new(&[1, 2, 3]);
1✔
319
        let b = VBytes::new(&[1, 2, 3]);
1✔
320
        let c = VBytes::new(&[4, 5, 6]);
1✔
321

322
        assert_eq!(a, b);
1✔
323
        assert_ne!(a, c);
1✔
324
        assert_eq!(a, [1, 2, 3].as_slice());
1✔
325
    }
1✔
326

327
    #[test]
328
    fn test_clone() {
1✔
329
        let a = VBytes::new(&[0xDE, 0xAD, 0xBE, 0xEF]);
1✔
330
        let b = a.clone();
1✔
331
        assert_eq!(a, b);
1✔
332
    }
1✔
333

334
    #[test]
335
    fn test_ordering() {
1✔
336
        let a = VBytes::new(&[1, 2, 3]);
1✔
337
        let b = VBytes::new(&[1, 2, 4]);
1✔
338
        assert!(a < b);
1✔
339
    }
1✔
340

341
    #[test]
342
    fn test_debug() {
1✔
343
        let b = VBytes::new(&[0xDE, 0xAD]);
1✔
344
        let s = format!("{b:?}");
1✔
345
        assert_eq!(s, "b\"\\xde\\xad\"");
1✔
346
    }
1✔
347
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc