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

facet-rs / facet / 19770016110

28 Nov 2025 05:06PM UTC coverage: 60.673% (+0.3%) from 60.41%
19770016110

push

github

fasterthanlime
Add facet-value crate for memory-efficient dynamic values

A new crate inspired by ijson that provides a pointer-sized Value type
using tagged pointers. Key features:

- Seven value types: Null, Bool, Number, String, Bytes, Array, Object
- Inline values for null/true/false (no heap allocation)
- VBytes type for binary format support (MessagePack, CBOR, etc.)
- no_std compatible with alloc feature
- Struct-based API with destructure() methods (not exposed enum)

995 of 1530 new or added lines in 6 files covered. (65.03%)

16306 of 26875 relevant lines covered (60.67%)

152.08 hits per line

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

64.84
/facet-value/src/array.rs
1
//! Array value type.
2

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

16
use crate::value::{TypeTag, Value};
17

18
/// Header for heap-allocated arrays.
19
#[repr(C, align(8))]
20
struct ArrayHeader {
21
    /// Number of elements
22
    len: usize,
23
    /// Capacity (number of elements that can be stored)
24
    cap: usize,
25
    // Array of Value follows immediately after
26
}
27

28
/// An array value.
29
///
30
/// `VArray` is a dynamic array of `Value`s, similar to `Vec<Value>`.
31
/// The length and capacity are stored in a heap-allocated header.
32
#[repr(transparent)]
33
#[derive(Clone)]
34
pub struct VArray(pub(crate) Value);
35

36
impl VArray {
37
    fn layout(cap: usize) -> Layout {
22✔
38
        Layout::new::<ArrayHeader>()
22✔
39
            .extend(Layout::array::<Value>(cap).unwrap())
22✔
40
            .unwrap()
22✔
41
            .0
22✔
42
            .pad_to_align()
22✔
43
    }
22✔
44

45
    #[cfg(feature = "alloc")]
46
    fn alloc(cap: usize) -> *mut ArrayHeader {
7✔
47
        unsafe {
48
            let layout = Self::layout(cap);
7✔
49
            let ptr = alloc(layout).cast::<ArrayHeader>();
7✔
50
            (*ptr).len = 0;
7✔
51
            (*ptr).cap = cap;
7✔
52
            ptr
7✔
53
        }
54
    }
7✔
55

56
    #[cfg(feature = "alloc")]
57
    fn realloc_ptr(ptr: *mut ArrayHeader, new_cap: usize) -> *mut ArrayHeader {
4✔
58
        unsafe {
59
            let old_cap = (*ptr).cap;
4✔
60
            let old_layout = Self::layout(old_cap);
4✔
61
            let new_layout = Self::layout(new_cap);
4✔
62
            let new_ptr =
4✔
63
                realloc(ptr.cast::<u8>(), old_layout, new_layout.size()).cast::<ArrayHeader>();
4✔
64
            (*new_ptr).cap = new_cap;
4✔
65
            new_ptr
4✔
66
        }
67
    }
4✔
68

69
    #[cfg(feature = "alloc")]
70
    fn dealloc_ptr(ptr: *mut ArrayHeader) {
7✔
71
        unsafe {
7✔
72
            let cap = (*ptr).cap;
7✔
73
            let layout = Self::layout(cap);
7✔
74
            dealloc(ptr.cast::<u8>(), layout);
7✔
75
        }
7✔
76
    }
7✔
77

78
    fn header(&self) -> &ArrayHeader {
89✔
79
        unsafe { &*(self.0.heap_ptr() as *const ArrayHeader) }
89✔
80
    }
89✔
81

82
    fn header_mut(&mut self) -> &mut ArrayHeader {
60✔
83
        unsafe { &mut *(self.0.heap_ptr() as *mut ArrayHeader) }
60✔
84
    }
60✔
85

86
    fn items_ptr(&self) -> *const Value {
7✔
87
        unsafe { (self.header() as *const ArrayHeader).add(1).cast() }
7✔
88
    }
7✔
89

90
    fn items_ptr_mut(&mut self) -> *mut Value {
30✔
91
        unsafe { (self.header_mut() as *mut ArrayHeader).add(1).cast() }
30✔
92
    }
30✔
93

94
    /// Creates a new empty array.
95
    #[cfg(feature = "alloc")]
96
    #[must_use]
97
    pub fn new() -> Self {
5✔
98
        Self::with_capacity(0)
5✔
99
    }
5✔
100

101
    /// Creates a new array with the specified capacity.
102
    #[cfg(feature = "alloc")]
103
    #[must_use]
104
    pub fn with_capacity(cap: usize) -> Self {
7✔
105
        unsafe {
106
            let ptr = Self::alloc(cap);
7✔
107
            VArray(Value::new_ptr(ptr.cast(), TypeTag::ArrayOrTrue))
7✔
108
        }
109
    }
7✔
110

111
    /// Returns the number of elements.
112
    #[must_use]
113
    pub fn len(&self) -> usize {
53✔
114
        self.header().len
53✔
115
    }
53✔
116

117
    /// Returns `true` if the array is empty.
118
    #[must_use]
119
    pub fn is_empty(&self) -> bool {
1✔
120
        self.len() == 0
1✔
121
    }
1✔
122

123
    /// Returns the capacity.
124
    #[must_use]
125
    pub fn capacity(&self) -> usize {
15✔
126
        self.header().cap
15✔
127
    }
15✔
128

129
    /// Returns a slice of the elements.
130
    #[must_use]
131
    pub fn as_slice(&self) -> &[Value] {
7✔
132
        unsafe { core::slice::from_raw_parts(self.items_ptr(), self.len()) }
7✔
133
    }
7✔
134

135
    /// Returns a mutable slice of the elements.
NEW
136
    pub fn as_mut_slice(&mut self) -> &mut [Value] {
×
NEW
137
        unsafe { core::slice::from_raw_parts_mut(self.items_ptr_mut(), self.len()) }
×
NEW
138
    }
×
139

140
    /// Reserves capacity for at least `additional` more elements.
141
    #[cfg(feature = "alloc")]
142
    pub fn reserve(&mut self, additional: usize) {
15✔
143
        let current_cap = self.capacity();
15✔
144
        let desired_cap = self
15✔
145
            .len()
15✔
146
            .checked_add(additional)
15✔
147
            .expect("capacity overflow");
15✔
148

149
        if current_cap >= desired_cap {
15✔
150
            return;
11✔
151
        }
4✔
152

153
        let new_cap = cmp::max(current_cap * 2, desired_cap.max(4));
4✔
154

155
        unsafe {
4✔
156
            let new_ptr = Self::realloc_ptr(self.0.heap_ptr().cast(), new_cap);
4✔
157
            self.0.set_ptr(new_ptr.cast());
4✔
158
        }
4✔
159
    }
15✔
160

161
    /// Pushes an element onto the back.
162
    #[cfg(feature = "alloc")]
163
    pub fn push(&mut self, value: impl Into<Value>) {
14✔
164
        self.reserve(1);
14✔
165
        unsafe {
14✔
166
            let len = self.header().len;
14✔
167
            let ptr = self.items_ptr_mut().add(len);
14✔
168
            ptr.write(value.into());
14✔
169
            self.header_mut().len = len + 1;
14✔
170
        }
14✔
171
    }
14✔
172

173
    /// Pops an element from the back.
174
    pub fn pop(&mut self) -> Option<Value> {
22✔
175
        let len = self.len();
22✔
176
        if len == 0 {
22✔
177
            return None;
8✔
178
        }
14✔
179
        unsafe {
180
            self.header_mut().len = len - 1;
14✔
181
            let ptr = self.items_ptr_mut().add(len - 1);
14✔
182
            Some(ptr.read())
14✔
183
        }
184
    }
22✔
185

186
    /// Inserts an element at the specified index.
187
    #[cfg(feature = "alloc")]
188
    pub fn insert(&mut self, index: usize, value: impl Into<Value>) {
1✔
189
        let len = self.len();
1✔
190
        assert!(index <= len, "index out of bounds");
1✔
191

192
        self.reserve(1);
1✔
193

194
        unsafe {
195
            let ptr = self.items_ptr_mut().add(index);
1✔
196
            // Shift elements to the right
197
            if index < len {
1✔
198
                ptr::copy(ptr, ptr.add(1), len - index);
1✔
199
            }
1✔
200
            ptr.write(value.into());
1✔
201
            self.header_mut().len = len + 1;
1✔
202
        }
203
    }
1✔
204

205
    /// Removes and returns the element at the specified index.
206
    pub fn remove(&mut self, index: usize) -> Option<Value> {
1✔
207
        let len = self.len();
1✔
208
        if index >= len {
1✔
NEW
209
            return None;
×
210
        }
1✔
211

212
        unsafe {
213
            let ptr = self.items_ptr_mut().add(index);
1✔
214
            let value = ptr.read();
1✔
215
            // Shift elements to the left
216
            if index < len - 1 {
1✔
217
                ptr::copy(ptr.add(1), ptr, len - index - 1);
1✔
218
            }
1✔
219
            self.header_mut().len = len - 1;
1✔
220
            Some(value)
1✔
221
        }
222
    }
1✔
223

224
    /// Removes an element by swapping it with the last element.
225
    /// More efficient than `remove` but doesn't preserve order.
NEW
226
    pub fn swap_remove(&mut self, index: usize) -> Option<Value> {
×
NEW
227
        let len = self.len();
×
NEW
228
        if index >= len {
×
NEW
229
            return None;
×
NEW
230
        }
×
231

NEW
232
        self.as_mut_slice().swap(index, len - 1);
×
NEW
233
        self.pop()
×
NEW
234
    }
×
235

236
    /// Clears the array.
237
    pub fn clear(&mut self) {
7✔
238
        while self.pop().is_some() {}
18✔
239
    }
7✔
240

241
    /// Truncates the array to the specified length.
NEW
242
    pub fn truncate(&mut self, len: usize) {
×
NEW
243
        while self.len() > len {
×
NEW
244
            self.pop();
×
NEW
245
        }
×
NEW
246
    }
×
247

248
    /// Gets an element by index.
249
    #[must_use]
NEW
250
    pub fn get(&self, index: usize) -> Option<&Value> {
×
NEW
251
        self.as_slice().get(index)
×
NEW
252
    }
×
253

254
    /// Gets a mutable element by index.
NEW
255
    pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> {
×
NEW
256
        self.as_mut_slice().get_mut(index)
×
NEW
257
    }
×
258

259
    /// Shrinks the capacity to match the length.
260
    #[cfg(feature = "alloc")]
NEW
261
    pub fn shrink_to_fit(&mut self) {
×
NEW
262
        let len = self.len();
×
NEW
263
        let cap = self.capacity();
×
264

NEW
265
        if len < cap {
×
NEW
266
            unsafe {
×
NEW
267
                let new_ptr = Self::realloc_ptr(self.0.heap_ptr().cast(), len);
×
NEW
268
                self.0.set_ptr(new_ptr.cast());
×
NEW
269
            }
×
NEW
270
        }
×
NEW
271
    }
×
272

273
    pub(crate) fn clone_impl(&self) -> Value {
1✔
274
        let mut new = VArray::with_capacity(self.len());
1✔
275
        for v in self.as_slice() {
2✔
276
            new.push(v.clone());
2✔
277
        }
2✔
278
        new.0
1✔
279
    }
1✔
280

281
    pub(crate) fn drop_impl(&mut self) {
7✔
282
        self.clear();
7✔
283
        unsafe {
7✔
284
            Self::dealloc_ptr(self.0.heap_ptr().cast());
7✔
285
        }
7✔
286
    }
7✔
287
}
288

289
// === Iterator ===
290

291
/// Iterator over owned `Value`s from a `VArray`.
292
pub struct ArrayIntoIter {
293
    array: VArray,
294
}
295

296
impl Iterator for ArrayIntoIter {
297
    type Item = Value;
298

NEW
299
    fn next(&mut self) -> Option<Self::Item> {
×
NEW
300
        if self.array.is_empty() {
×
NEW
301
            None
×
302
        } else {
NEW
303
            self.array.remove(0)
×
304
        }
NEW
305
    }
×
306

NEW
307
    fn size_hint(&self) -> (usize, Option<usize>) {
×
NEW
308
        let len = self.array.len();
×
NEW
309
        (len, Some(len))
×
NEW
310
    }
×
311
}
312

313
impl ExactSizeIterator for ArrayIntoIter {}
314

315
impl IntoIterator for VArray {
316
    type Item = Value;
317
    type IntoIter = ArrayIntoIter;
318

NEW
319
    fn into_iter(self) -> Self::IntoIter {
×
NEW
320
        ArrayIntoIter { array: self }
×
NEW
321
    }
×
322
}
323

324
impl<'a> IntoIterator for &'a VArray {
325
    type Item = &'a Value;
326
    type IntoIter = core::slice::Iter<'a, Value>;
327

NEW
328
    fn into_iter(self) -> Self::IntoIter {
×
NEW
329
        self.as_slice().iter()
×
NEW
330
    }
×
331
}
332

333
impl<'a> IntoIterator for &'a mut VArray {
334
    type Item = &'a mut Value;
335
    type IntoIter = core::slice::IterMut<'a, Value>;
336

NEW
337
    fn into_iter(self) -> Self::IntoIter {
×
NEW
338
        self.as_mut_slice().iter_mut()
×
NEW
339
    }
×
340
}
341

342
// === Deref ===
343

344
impl Deref for VArray {
345
    type Target = [Value];
346

347
    fn deref(&self) -> &[Value] {
1✔
348
        self.as_slice()
1✔
349
    }
1✔
350
}
351

352
impl DerefMut for VArray {
NEW
353
    fn deref_mut(&mut self) -> &mut [Value] {
×
NEW
354
        self.as_mut_slice()
×
NEW
355
    }
×
356
}
357

358
impl Borrow<[Value]> for VArray {
NEW
359
    fn borrow(&self) -> &[Value] {
×
NEW
360
        self.as_slice()
×
NEW
361
    }
×
362
}
363

364
impl BorrowMut<[Value]> for VArray {
NEW
365
    fn borrow_mut(&mut self) -> &mut [Value] {
×
NEW
366
        self.as_mut_slice()
×
NEW
367
    }
×
368
}
369

370
impl AsRef<[Value]> for VArray {
NEW
371
    fn as_ref(&self) -> &[Value] {
×
NEW
372
        self.as_slice()
×
NEW
373
    }
×
374
}
375

376
// === Index ===
377

378
impl<I: SliceIndex<[Value]>> Index<I> for VArray {
379
    type Output = I::Output;
380

381
    fn index(&self, index: I) -> &Self::Output {
3✔
382
        &self.as_slice()[index]
3✔
383
    }
3✔
384
}
385

386
impl<I: SliceIndex<[Value]>> IndexMut<I> for VArray {
NEW
387
    fn index_mut(&mut self, index: I) -> &mut Self::Output {
×
NEW
388
        &mut self.as_mut_slice()[index]
×
NEW
389
    }
×
390
}
391

392
// === Comparison ===
393

394
impl PartialEq for VArray {
395
    fn eq(&self, other: &Self) -> bool {
1✔
396
        self.as_slice() == other.as_slice()
1✔
397
    }
1✔
398
}
399

400
impl Eq for VArray {}
401

402
impl PartialOrd for VArray {
NEW
403
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
×
404
        // Element-wise comparison
NEW
405
        let mut iter1 = self.iter();
×
NEW
406
        let mut iter2 = other.iter();
×
407
        loop {
NEW
408
            match (iter1.next(), iter2.next()) {
×
NEW
409
                (Some(a), Some(b)) => match a.partial_cmp(b) {
×
NEW
410
                    Some(Ordering::Equal) => continue,
×
NEW
411
                    other => return other,
×
412
                },
NEW
413
                (None, None) => return Some(Ordering::Equal),
×
NEW
414
                (Some(_), None) => return Some(Ordering::Greater),
×
NEW
415
                (None, Some(_)) => return Some(Ordering::Less),
×
416
            }
417
        }
NEW
418
    }
×
419
}
420

421
impl Hash for VArray {
NEW
422
    fn hash<H: Hasher>(&self, state: &mut H) {
×
NEW
423
        self.as_slice().hash(state);
×
NEW
424
    }
×
425
}
426

427
impl Debug for VArray {
NEW
428
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
×
NEW
429
        Debug::fmt(self.as_slice(), f)
×
NEW
430
    }
×
431
}
432

433
impl Default for VArray {
NEW
434
    fn default() -> Self {
×
NEW
435
        Self::new()
×
NEW
436
    }
×
437
}
438

439
// === FromIterator / Extend ===
440

441
#[cfg(feature = "alloc")]
442
impl<T: Into<Value>> FromIterator<T> for VArray {
443
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1✔
444
        let iter = iter.into_iter();
1✔
445
        let (lower, _) = iter.size_hint();
1✔
446
        let mut array = VArray::with_capacity(lower);
1✔
447
        for v in iter {
4✔
448
            array.push(v);
3✔
449
        }
3✔
450
        array
1✔
451
    }
1✔
452
}
453

454
#[cfg(feature = "alloc")]
455
impl<T: Into<Value>> Extend<T> for VArray {
NEW
456
    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
×
NEW
457
        let iter = iter.into_iter();
×
NEW
458
        let (lower, _) = iter.size_hint();
×
NEW
459
        self.reserve(lower);
×
NEW
460
        for v in iter {
×
NEW
461
            self.push(v);
×
NEW
462
        }
×
NEW
463
    }
×
464
}
465

466
// === From implementations ===
467

468
#[cfg(feature = "alloc")]
469
impl<T: Into<Value>> From<Vec<T>> for VArray {
NEW
470
    fn from(vec: Vec<T>) -> Self {
×
NEW
471
        vec.into_iter().collect()
×
NEW
472
    }
×
473
}
474

475
#[cfg(feature = "alloc")]
476
impl<T: Into<Value> + Clone> From<&[T]> for VArray {
NEW
477
    fn from(slice: &[T]) -> Self {
×
NEW
478
        slice.iter().cloned().collect()
×
NEW
479
    }
×
480
}
481

482
// === Value conversions ===
483

484
impl AsRef<Value> for VArray {
NEW
485
    fn as_ref(&self) -> &Value {
×
NEW
486
        &self.0
×
NEW
487
    }
×
488
}
489

490
impl AsMut<Value> for VArray {
NEW
491
    fn as_mut(&mut self) -> &mut Value {
×
NEW
492
        &mut self.0
×
NEW
493
    }
×
494
}
495

496
impl From<VArray> for Value {
NEW
497
    fn from(arr: VArray) -> Self {
×
NEW
498
        arr.0
×
NEW
499
    }
×
500
}
501

502
#[cfg(test)]
503
mod tests {
504
    use super::*;
505

506
    #[test]
507
    fn test_new() {
1✔
508
        let arr = VArray::new();
1✔
509
        assert!(arr.is_empty());
1✔
510
        assert_eq!(arr.len(), 0);
1✔
511
    }
1✔
512

513
    #[test]
514
    fn test_push_pop() {
1✔
515
        let mut arr = VArray::new();
1✔
516
        arr.push(Value::from(1));
1✔
517
        arr.push(Value::from(2));
1✔
518
        arr.push(Value::from(3));
1✔
519

520
        assert_eq!(arr.len(), 3);
1✔
521
        assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(3));
1✔
522
        assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(2));
1✔
523
        assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(1));
1✔
524
        assert!(arr.pop().is_none());
1✔
525
    }
1✔
526

527
    #[test]
528
    fn test_insert_remove() {
1✔
529
        let mut arr = VArray::new();
1✔
530
        arr.push(Value::from(1));
1✔
531
        arr.push(Value::from(3));
1✔
532
        arr.insert(1, Value::from(2));
1✔
533

534
        assert_eq!(arr.len(), 3);
1✔
535
        assert_eq!(arr[0].as_number().unwrap().to_i64(), Some(1));
1✔
536
        assert_eq!(arr[1].as_number().unwrap().to_i64(), Some(2));
1✔
537
        assert_eq!(arr[2].as_number().unwrap().to_i64(), Some(3));
1✔
538

539
        let removed = arr.remove(1).unwrap();
1✔
540
        assert_eq!(removed.as_number().unwrap().to_i64(), Some(2));
1✔
541
        assert_eq!(arr.len(), 2);
1✔
542
    }
1✔
543

544
    #[test]
545
    fn test_clone() {
1✔
546
        let mut arr = VArray::new();
1✔
547
        arr.push(Value::from("hello"));
1✔
548
        arr.push(Value::from(42));
1✔
549

550
        let arr2 = arr.clone();
1✔
551
        assert_eq!(arr, arr2);
1✔
552
    }
1✔
553

554
    #[test]
555
    fn test_iter() {
1✔
556
        let mut arr = VArray::new();
1✔
557
        arr.push(Value::from(1));
1✔
558
        arr.push(Value::from(2));
1✔
559

560
        let sum: i64 = arr
1✔
561
            .iter()
1✔
562
            .map(|v| v.as_number().unwrap().to_i64().unwrap())
2✔
563
            .sum();
1✔
564
        assert_eq!(sum, 3);
1✔
565
    }
1✔
566

567
    #[test]
568
    fn test_collect() {
1✔
569
        let arr: VArray = vec![1i64, 2, 3].into_iter().map(Value::from).collect();
1✔
570
        assert_eq!(arr.len(), 3);
1✔
571
    }
1✔
572
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc