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

facet-rs / facet / 19803020611

30 Nov 2025 06:23PM UTC coverage: 57.923% (-3.0%) from 60.927%
19803020611

push

github

fasterthanlime
Convert facet-kdl to use define_attr_grammar!

- Replace ~140 lines of hand-written macros with concise grammar DSL
- Enhance make_parse_attr.rs grammar compiler:
  - Add `ns "kdl";` syntax for namespace declaration
  - Add to_snake_case() helper (NodeName → node_name)
  - Generate __attr! macro with proper ExtensionAttr return
  - Use () data for unit variants, full dispatch for complex ones
  - Add #[repr(u8)] to generated enums for Facet derive
  - Use HashMap for O(1) struct lookup
- Update design diagrams with namespace fixes

50 of 53 new or added lines in 1 file covered. (94.34%)

3583 existing lines in 40 files now uncovered.

18788 of 32436 relevant lines covered (57.92%)

179.8 hits per line

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

67.09
/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 {
312✔
38
        Layout::new::<ArrayHeader>()
312✔
39
            .extend(Layout::array::<Value>(cap).unwrap())
312✔
40
            .unwrap()
312✔
41
            .0
312✔
42
            .pad_to_align()
312✔
43
    }
312✔
44

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

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

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

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

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

86
    fn items_ptr(&self) -> *const Value {
247✔
87
        // Go through heap_ptr directly to avoid creating intermediate reference
88
        // that would limit provenance to just the header
89
        unsafe { (self.0.heap_ptr() as *const ArrayHeader).add(1).cast() }
247✔
90
    }
247✔
91

92
    fn items_ptr_mut(&mut self) -> *mut Value {
440✔
93
        // Use heap_ptr_mut directly to preserve mutable provenance
94
        unsafe { (self.0.heap_ptr_mut() as *mut ArrayHeader).add(1).cast() }
440✔
95
    }
440✔
96

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

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

114
    /// Returns the number of elements.
115
    #[must_use]
116
    pub fn len(&self) -> usize {
862✔
117
        self.header().len
862✔
118
    }
862✔
119

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

126
    /// Returns the capacity.
127
    #[must_use]
128
    pub fn capacity(&self) -> usize {
220✔
129
        self.header().cap
220✔
130
    }
220✔
131

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

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

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

152
        if current_cap >= desired_cap {
220✔
153
            return;
145✔
154
        }
75✔
155

156
        let new_cap = cmp::max(current_cap * 2, desired_cap.max(4));
75✔
157

158
        unsafe {
75✔
159
            let new_ptr = Self::realloc_ptr(self.0.heap_ptr_mut().cast(), new_cap);
75✔
160
            self.0.set_ptr(new_ptr.cast());
75✔
161
        }
75✔
162
    }
220✔
163

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

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

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

195
        self.reserve(1);
1✔
196

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

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

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

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

235
        self.as_mut_slice().swap(index, len - 1);
×
UNCOV
236
        self.pop()
×
UNCOV
237
    }
×
238

239
    /// Clears the array.
240
    pub fn clear(&mut self) {
81✔
241
        while self.pop().is_some() {}
297✔
242
    }
81✔
243

244
    /// Truncates the array to the specified length.
245
    pub fn truncate(&mut self, len: usize) {
×
246
        while self.len() > len {
×
247
            self.pop();
×
UNCOV
248
        }
×
UNCOV
249
    }
×
250

251
    /// Gets an element by index.
252
    #[must_use]
253
    pub fn get(&self, index: usize) -> Option<&Value> {
186✔
254
        self.as_slice().get(index)
186✔
255
    }
186✔
256

257
    /// Gets a mutable element by index.
258
    pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> {
×
UNCOV
259
        self.as_mut_slice().get_mut(index)
×
UNCOV
260
    }
×
261

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

268
        if len < cap {
×
269
            unsafe {
×
270
                let new_ptr = Self::realloc_ptr(self.0.heap_ptr_mut().cast(), len);
×
271
                self.0.set_ptr(new_ptr.cast());
×
272
            }
×
UNCOV
273
        }
×
UNCOV
274
    }
×
275

276
    pub(crate) fn clone_impl(&self) -> Value {
3✔
277
        let mut new = VArray::with_capacity(self.len());
3✔
278
        for v in self.as_slice() {
8✔
279
            new.push(v.clone());
8✔
280
        }
8✔
281
        new.0
3✔
282
    }
3✔
283

284
    pub(crate) fn drop_impl(&mut self) {
81✔
285
        self.clear();
81✔
286
        unsafe {
81✔
287
            Self::dealloc_ptr(self.0.heap_ptr_mut().cast());
81✔
288
        }
81✔
289
    }
81✔
290
}
291

292
// === Iterator ===
293

294
/// Iterator over owned `Value`s from a `VArray`.
295
pub struct ArrayIntoIter {
296
    array: VArray,
297
}
298

299
impl Iterator for ArrayIntoIter {
300
    type Item = Value;
301

302
    fn next(&mut self) -> Option<Self::Item> {
×
UNCOV
303
        if self.array.is_empty() {
×
304
            None
×
305
        } else {
306
            self.array.remove(0)
×
307
        }
308
    }
×
309

310
    fn size_hint(&self) -> (usize, Option<usize>) {
×
311
        let len = self.array.len();
×
UNCOV
312
        (len, Some(len))
×
UNCOV
313
    }
×
314
}
315

316
impl ExactSizeIterator for ArrayIntoIter {}
317

318
impl IntoIterator for VArray {
319
    type Item = Value;
320
    type IntoIter = ArrayIntoIter;
321

322
    fn into_iter(self) -> Self::IntoIter {
×
UNCOV
323
        ArrayIntoIter { array: self }
×
UNCOV
324
    }
×
325
}
326

327
impl<'a> IntoIterator for &'a VArray {
328
    type Item = &'a Value;
329
    type IntoIter = core::slice::Iter<'a, Value>;
330

331
    fn into_iter(self) -> Self::IntoIter {
×
UNCOV
332
        self.as_slice().iter()
×
UNCOV
333
    }
×
334
}
335

336
impl<'a> IntoIterator for &'a mut VArray {
337
    type Item = &'a mut Value;
338
    type IntoIter = core::slice::IterMut<'a, Value>;
339

340
    fn into_iter(self) -> Self::IntoIter {
×
UNCOV
341
        self.as_mut_slice().iter_mut()
×
UNCOV
342
    }
×
343
}
344

345
// === Deref ===
346

347
impl Deref for VArray {
348
    type Target = [Value];
349

350
    fn deref(&self) -> &[Value] {
7✔
351
        self.as_slice()
7✔
352
    }
7✔
353
}
354

355
impl DerefMut for VArray {
356
    fn deref_mut(&mut self) -> &mut [Value] {
×
UNCOV
357
        self.as_mut_slice()
×
UNCOV
358
    }
×
359
}
360

361
impl Borrow<[Value]> for VArray {
362
    fn borrow(&self) -> &[Value] {
×
UNCOV
363
        self.as_slice()
×
UNCOV
364
    }
×
365
}
366

367
impl BorrowMut<[Value]> for VArray {
368
    fn borrow_mut(&mut self) -> &mut [Value] {
×
UNCOV
369
        self.as_mut_slice()
×
UNCOV
370
    }
×
371
}
372

373
impl AsRef<[Value]> for VArray {
374
    fn as_ref(&self) -> &[Value] {
×
UNCOV
375
        self.as_slice()
×
UNCOV
376
    }
×
377
}
378

379
// === Index ===
380

381
impl<I: SliceIndex<[Value]>> Index<I> for VArray {
382
    type Output = I::Output;
383

384
    fn index(&self, index: I) -> &Self::Output {
25✔
385
        &self.as_slice()[index]
25✔
386
    }
25✔
387
}
388

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

395
// === Comparison ===
396

397
impl PartialEq for VArray {
398
    fn eq(&self, other: &Self) -> bool {
13✔
399
        self.as_slice() == other.as_slice()
13✔
400
    }
13✔
401
}
402

403
impl Eq for VArray {}
404

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

424
impl Hash for VArray {
425
    fn hash<H: Hasher>(&self, state: &mut H) {
×
UNCOV
426
        self.as_slice().hash(state);
×
UNCOV
427
    }
×
428
}
429

430
impl Debug for VArray {
431
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
×
UNCOV
432
        Debug::fmt(self.as_slice(), f)
×
UNCOV
433
    }
×
434
}
435

436
impl Default for VArray {
437
    fn default() -> Self {
×
UNCOV
438
        Self::new()
×
UNCOV
439
    }
×
440
}
441

442
// === FromIterator / Extend ===
443

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

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

469
// === From implementations ===
470

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

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

485
// === Value conversions ===
486

487
impl AsRef<Value> for VArray {
488
    fn as_ref(&self) -> &Value {
×
UNCOV
489
        &self.0
×
UNCOV
490
    }
×
491
}
492

493
impl AsMut<Value> for VArray {
494
    fn as_mut(&mut self) -> &mut Value {
×
UNCOV
495
        &mut self.0
×
UNCOV
496
    }
×
497
}
498

499
impl From<VArray> for Value {
500
    fn from(arr: VArray) -> Self {
62✔
501
        arr.0
62✔
502
    }
62✔
503
}
504

505
impl VArray {
506
    /// Converts this VArray into a Value, consuming self.
507
    #[inline]
508
    pub fn into_value(self) -> Value {
10✔
509
        self.0
10✔
510
    }
10✔
511
}
512

513
#[cfg(test)]
514
mod tests {
515
    use super::*;
516

517
    #[test]
518
    fn test_new() {
1✔
519
        let arr = VArray::new();
1✔
520
        assert!(arr.is_empty());
1✔
521
        assert_eq!(arr.len(), 0);
1✔
522
    }
1✔
523

524
    #[test]
525
    fn test_push_pop() {
1✔
526
        let mut arr = VArray::new();
1✔
527
        arr.push(Value::from(1));
1✔
528
        arr.push(Value::from(2));
1✔
529
        arr.push(Value::from(3));
1✔
530

531
        assert_eq!(arr.len(), 3);
1✔
532
        assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(3));
1✔
533
        assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(2));
1✔
534
        assert_eq!(arr.pop().unwrap().as_number().unwrap().to_i64(), Some(1));
1✔
535
        assert!(arr.pop().is_none());
1✔
536
    }
1✔
537

538
    #[test]
539
    fn test_insert_remove() {
1✔
540
        let mut arr = VArray::new();
1✔
541
        arr.push(Value::from(1));
1✔
542
        arr.push(Value::from(3));
1✔
543
        arr.insert(1, Value::from(2));
1✔
544

545
        assert_eq!(arr.len(), 3);
1✔
546
        assert_eq!(arr[0].as_number().unwrap().to_i64(), Some(1));
1✔
547
        assert_eq!(arr[1].as_number().unwrap().to_i64(), Some(2));
1✔
548
        assert_eq!(arr[2].as_number().unwrap().to_i64(), Some(3));
1✔
549

550
        let removed = arr.remove(1).unwrap();
1✔
551
        assert_eq!(removed.as_number().unwrap().to_i64(), Some(2));
1✔
552
        assert_eq!(arr.len(), 2);
1✔
553
    }
1✔
554

555
    #[test]
556
    fn test_clone() {
1✔
557
        let mut arr = VArray::new();
1✔
558
        arr.push(Value::from("hello"));
1✔
559
        arr.push(Value::from(42));
1✔
560

561
        let arr2 = arr.clone();
1✔
562
        assert_eq!(arr, arr2);
1✔
563
    }
1✔
564

565
    #[test]
566
    fn test_iter() {
1✔
567
        let mut arr = VArray::new();
1✔
568
        arr.push(Value::from(1));
1✔
569
        arr.push(Value::from(2));
1✔
570

571
        let sum: i64 = arr
1✔
572
            .iter()
1✔
573
            .map(|v| v.as_number().unwrap().to_i64().unwrap())
2✔
574
            .sum();
1✔
575
        assert_eq!(sum, 3);
1✔
576
    }
1✔
577

578
    #[test]
579
    fn test_collect() {
1✔
580
        let arr: VArray = vec![1i64, 2, 3].into_iter().map(Value::from).collect();
1✔
581
        assert_eq!(arr.len(), 3);
1✔
582
    }
1✔
583
}
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