• 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

63.08
/facet-reflect/src/partial/partial_api/maps.rs
1
use super::*;
2

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Maps
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl Partial<'_> {
7
    /// Begins a map initialization operation
8
    ///
9
    /// This initializes the map with default capacity and allows inserting key-value pairs
10
    /// It does _not_ push a new frame onto the stack.
11
    ///
12
    /// For `Def::DynamicValue` types, this initializes as an object instead of a map.
13
    pub fn begin_map(mut self) -> Result<Self, ReflectError> {
111✔
14
        let frame = self.frames_mut().last_mut().unwrap();
111✔
15

16
        // Check tracker state before initializing
17
        match &frame.tracker {
91✔
18
            Tracker::Scalar if !frame.is_init => {
90✔
19
                // Good, will initialize below
90✔
20
            }
90✔
21
            Tracker::Scalar => {
22
                // is_init is true - already initialized (from a previous round), just update tracker
23
                match frame.shape.def {
1✔
24
                    Def::Map(_) => {
25
                        frame.tracker = Tracker::Map {
×
26
                            insert_state: MapInsertState::Idle,
×
27
                        };
×
28
                        return Ok(self);
×
29
                    }
30
                    Def::DynamicValue(_) => {
31
                        frame.tracker = Tracker::DynamicValue {
1✔
32
                            state: DynamicValueState::Object {
1✔
33
                                insert_state: DynamicObjectInsertState::Idle,
1✔
34
                            },
1✔
35
                        };
1✔
36
                        return Ok(self);
1✔
37
                    }
38
                    _ => {
UNCOV
39
                        return Err(ReflectError::OperationFailed {
×
40
                            shape: frame.shape,
×
41
                            operation: "begin_map can only be called on Map or DynamicValue types",
×
42
                        });
×
43
                    }
44
                }
45
            }
46
            Tracker::Map { .. } => {
47
                if frame.is_init {
7✔
48
                    // Already initialized, nothing to do
49
                    return Ok(self);
7✔
UNCOV
50
                }
×
51
            }
52
            Tracker::DynamicValue { state } => {
13✔
53
                // Already initialized as a dynamic object
54
                if matches!(state, DynamicValueState::Object { .. }) {
13✔
55
                    return Ok(self);
13✔
UNCOV
56
                }
×
57
                // Otherwise (Scalar or Array state), we need to deinit before reinitializing
UNCOV
58
                frame.deinit();
×
59
            }
60
            _ => {
UNCOV
61
                return Err(ReflectError::UnexpectedTracker {
×
UNCOV
62
                    message: "begin_map called but tracker isn't Scalar, Map, or DynamicValue",
×
UNCOV
63
                    current_tracker: frame.tracker.kind(),
×
UNCOV
64
                });
×
65
            }
66
        }
67

68
        // Check that we have a Map or DynamicValue
69
        match &frame.shape.def {
90✔
70
            Def::Map(map_def) => {
68✔
71
                let init_fn = map_def.vtable.init_in_place_with_capacity_fn;
68✔
72

68✔
73
                // Initialize the map with default capacity (0)
68✔
74
                unsafe {
68✔
75
                    init_fn(frame.data, 0);
68✔
76
                }
68✔
77

68✔
78
                // Update tracker to Map state and mark as initialized
68✔
79
                frame.tracker = Tracker::Map {
68✔
80
                    insert_state: MapInsertState::Idle,
68✔
81
                };
68✔
82
                frame.is_init = true;
68✔
83
            }
68✔
84
            Def::DynamicValue(dyn_def) => {
22✔
85
                // Initialize as a dynamic object
22✔
86
                unsafe {
22✔
87
                    (dyn_def.vtable.begin_object)(frame.data);
22✔
88
                }
22✔
89

22✔
90
                // Update tracker to DynamicValue object state and mark as initialized
22✔
91
                frame.tracker = Tracker::DynamicValue {
22✔
92
                    state: DynamicValueState::Object {
22✔
93
                        insert_state: DynamicObjectInsertState::Idle,
22✔
94
                    },
22✔
95
                };
22✔
96
                frame.is_init = true;
22✔
97
            }
22✔
98
            _ => {
UNCOV
99
                return Err(ReflectError::OperationFailed {
×
UNCOV
100
                    shape: frame.shape,
×
UNCOV
101
                    operation: "begin_map can only be called on Map or DynamicValue types",
×
UNCOV
102
                });
×
103
            }
104
        }
105

106
        Ok(self)
90✔
107
    }
111✔
108

109
    /// Pushes a frame for the map key. After that, `set()` should be called
110
    /// (or the key should be initialized somehow) and `end()` should be called
111
    /// to pop the frame.
112
    pub fn begin_key(mut self) -> Result<Self, ReflectError> {
101✔
113
        let frame = self.frames_mut().last_mut().unwrap();
101✔
114

115
        // Check that we have a Map in Idle state
116
        let map_def = match (&frame.shape.def, &frame.tracker) {
101✔
117
            (
118
                Def::Map(map_def),
101✔
119
                Tracker::Map {
120
                    insert_state: MapInsertState::Idle,
121
                },
122
            ) if frame.is_init => map_def,
101✔
123
            (
124
                Def::Map(_),
125
                Tracker::Map {
126
                    insert_state: MapInsertState::PushingKey { .. },
127
                },
128
            ) => {
129
                return Err(ReflectError::OperationFailed {
×
UNCOV
130
                    shape: frame.shape,
×
UNCOV
131
                    operation: "already pushing a key, call end() first",
×
UNCOV
132
                });
×
133
            }
134
            (
135
                Def::Map(_),
136
                Tracker::Map {
137
                    insert_state: MapInsertState::PushingValue { .. },
138
                },
139
            ) => {
UNCOV
140
                return Err(ReflectError::OperationFailed {
×
UNCOV
141
                    shape: frame.shape,
×
UNCOV
142
                    operation: "must complete current operation before begin_key()",
×
UNCOV
143
                });
×
144
            }
145
            _ => {
UNCOV
146
                return Err(ReflectError::OperationFailed {
×
UNCOV
147
                    shape: frame.shape,
×
UNCOV
148
                    operation: "must call begin_map() before begin_key()",
×
UNCOV
149
                });
×
150
            }
151
        };
152

153
        // Get the key shape
154
        let key_shape = map_def.k();
101✔
155

156
        // Allocate space for the key
157
        let key_layout = match key_shape.layout.sized_layout() {
101✔
158
            Ok(layout) => layout,
101✔
159
            Err(_) => {
UNCOV
160
                return Err(ReflectError::Unsized {
×
UNCOV
161
                    shape: key_shape,
×
UNCOV
162
                    operation: "begin_key allocating key",
×
UNCOV
163
                });
×
164
            }
165
        };
166
        let key_ptr_raw: *mut u8 = unsafe { ::alloc::alloc::alloc(key_layout) };
101✔
167

168
        let Some(key_ptr_raw) = NonNull::new(key_ptr_raw) else {
101✔
UNCOV
169
            return Err(ReflectError::OperationFailed {
×
UNCOV
170
                shape: frame.shape,
×
UNCOV
171
                operation: "failed to allocate memory for map key",
×
UNCOV
172
            });
×
173
        };
174

175
        let key_ptr = PtrUninit::new(key_ptr_raw);
101✔
176

177
        // Store the key pointer in the insert state
178
        match &mut frame.tracker {
101✔
179
            Tracker::Map { insert_state, .. } => {
101✔
180
                *insert_state = MapInsertState::PushingKey {
101✔
181
                    key_ptr,
101✔
182
                    key_initialized: false,
101✔
183
                };
101✔
184
            }
101✔
UNCOV
185
            _ => unreachable!(),
×
186
        }
187

188
        // Push a new frame for the key
189
        self.frames_mut().push(Frame::new(
101✔
190
            PtrUninit::new(key_ptr_raw),
101✔
191
            key_shape,
101✔
192
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
101✔
193
        ));
194

195
        Ok(self)
101✔
196
    }
101✔
197

198
    /// Pushes a frame for the map value
199
    /// Must be called after the key has been set and popped
200
    pub fn begin_value(mut self) -> Result<Self, ReflectError> {
98✔
201
        let frame = self.frames_mut().last_mut().unwrap();
98✔
202

203
        // Check that we have a Map in PushingValue state with no value_ptr yet
204
        let (map_def, key_ptr) = match (&frame.shape.def, &frame.tracker) {
98✔
205
            (
206
                Def::Map(map_def),
98✔
207
                Tracker::Map {
208
                    insert_state:
209
                        MapInsertState::PushingValue {
210
                            value_ptr: None,
211
                            key_ptr,
98✔
212
                            ..
213
                        },
214
                    ..
215
                },
216
            ) => (map_def, *key_ptr),
98✔
217
            (
218
                Def::Map(_),
219
                Tracker::Map {
220
                    insert_state:
221
                        MapInsertState::PushingValue {
222
                            value_ptr: Some(_), ..
223
                        },
224
                    ..
225
                },
226
            ) => {
UNCOV
227
                return Err(ReflectError::OperationFailed {
×
UNCOV
228
                    shape: frame.shape,
×
UNCOV
229
                    operation: "already pushing a value, call end() first",
×
UNCOV
230
                });
×
231
            }
232
            _ => {
UNCOV
233
                return Err(ReflectError::OperationFailed {
×
UNCOV
234
                    shape: frame.shape,
×
UNCOV
235
                    operation: "must complete key before begin_value()",
×
UNCOV
236
                });
×
237
            }
238
        };
239

240
        // Get the value shape
241
        let value_shape = map_def.v();
98✔
242

243
        // Allocate space for the value
244
        let value_layout = match value_shape.layout.sized_layout() {
98✔
245
            Ok(layout) => layout,
98✔
246
            Err(_) => {
UNCOV
247
                return Err(ReflectError::Unsized {
×
UNCOV
248
                    shape: value_shape,
×
UNCOV
249
                    operation: "begin_value allocating value",
×
UNCOV
250
                });
×
251
            }
252
        };
253
        let value_ptr_raw: *mut u8 = unsafe { ::alloc::alloc::alloc(value_layout) };
98✔
254

255
        let Some(value_ptr_raw) = NonNull::new(value_ptr_raw) else {
98✔
UNCOV
256
            return Err(ReflectError::OperationFailed {
×
UNCOV
257
                shape: frame.shape,
×
UNCOV
258
                operation: "failed to allocate memory for map value",
×
UNCOV
259
            });
×
260
        };
261

262
        let value_ptr = PtrUninit::new(value_ptr_raw);
98✔
263

264
        // Store the value pointer in the insert state
265
        match &mut frame.tracker {
98✔
266
            Tracker::Map { insert_state, .. } => {
98✔
267
                *insert_state = MapInsertState::PushingValue {
98✔
268
                    key_ptr,
98✔
269
                    value_ptr: Some(value_ptr),
98✔
270
                    value_initialized: false,
98✔
271
                };
98✔
272
            }
98✔
UNCOV
273
            _ => unreachable!(),
×
274
        }
275

276
        // Push a new frame for the value
277
        self.frames_mut().push(Frame::new(
98✔
278
            value_ptr,
98✔
279
            value_shape,
98✔
280
            FrameOwnership::ManagedElsewhere, // Ownership tracked in MapInsertState
98✔
281
        ));
282

283
        Ok(self)
98✔
284
    }
98✔
285

286
    /// Begins an object entry for a DynamicValue object.
287
    ///
288
    /// This is a simpler API than begin_key/begin_value for DynamicValue objects,
289
    /// where keys are always strings. The key is stored and a frame is pushed for
290
    /// the value. After setting the value and calling `end()`, the key-value pair
291
    /// will be inserted into the object.
292
    ///
293
    /// For `Def::Map` types, use `begin_key()` / `begin_value()` instead.
294
    pub fn begin_object_entry(mut self, key: &str) -> Result<Self, ReflectError> {
27✔
295
        crate::trace!("begin_object_entry({key:?})");
296
        let frame = self.frames_mut().last_mut().unwrap();
27✔
297

298
        // Check that we have a DynamicValue in Object state with Idle insert_state
299
        let dyn_def = match (&frame.shape.def, &frame.tracker) {
27✔
300
            (
301
                Def::DynamicValue(dyn_def),
27✔
302
                Tracker::DynamicValue {
303
                    state:
304
                        DynamicValueState::Object {
305
                            insert_state: DynamicObjectInsertState::Idle,
306
                        },
307
                },
308
            ) if frame.is_init => {
27✔
309
                // Good, proceed
310
                dyn_def
27✔
311
            }
312
            (
313
                Def::DynamicValue(_),
314
                Tracker::DynamicValue {
315
                    state:
316
                        DynamicValueState::Object {
317
                            insert_state: DynamicObjectInsertState::BuildingValue { .. },
318
                        },
319
                },
320
            ) => {
UNCOV
321
                return Err(ReflectError::OperationFailed {
×
UNCOV
322
                    shape: frame.shape,
×
UNCOV
323
                    operation: "already building a value, call end() first",
×
UNCOV
324
                });
×
325
            }
326
            (Def::DynamicValue(_), _) => {
UNCOV
327
                return Err(ReflectError::OperationFailed {
×
UNCOV
328
                    shape: frame.shape,
×
UNCOV
329
                    operation: "must call begin_map() before begin_object_entry()",
×
UNCOV
330
                });
×
331
            }
332
            _ => {
UNCOV
333
                return Err(ReflectError::OperationFailed {
×
UNCOV
334
                    shape: frame.shape,
×
UNCOV
335
                    operation: "begin_object_entry can only be called on DynamicValue types",
×
UNCOV
336
                });
×
337
            }
338
        };
339

340
        // For DynamicValue objects, the value shape is the same DynamicValue shape
341
        let value_shape = frame.shape;
27✔
342

343
        // Check if key already exists using object_get_mut (for "get or create" semantics)
344
        // This is needed for formats like TOML with implicit tables: [a] followed by [a.b.c]
345
        if let Some(get_mut_fn) = dyn_def.vtable.object_get_mut {
27✔
346
            let object_ptr = unsafe { frame.data.assume_init() };
27✔
347
            if let Some(existing_ptr) = unsafe { get_mut_fn(object_ptr, key) } {
27✔
348
                // Key exists - push a frame pointing to existing value
349
                // Leave insert_state as Idle (no insertion needed on end())
350
                // Use ManagedElsewhere since parent object owns this value
351
                let mut new_frame = Frame::new(
1✔
352
                    existing_ptr.as_uninit(),
1✔
353
                    value_shape,
1✔
354
                    FrameOwnership::ManagedElsewhere,
1✔
355
                );
356
                new_frame.is_init = true;
1✔
357
                // Set tracker to reflect it's an initialized DynamicValue
358
                // The caller will likely call begin_map() which will set proper Object state
359
                new_frame.tracker = Tracker::Scalar;
1✔
360
                self.frames_mut().push(new_frame);
1✔
361
                return Ok(self);
1✔
362
            }
26✔
UNCOV
363
        }
×
364

365
        // Key doesn't exist - allocate new value
366
        let value_layout = match value_shape.layout.sized_layout() {
26✔
367
            Ok(layout) => layout,
26✔
368
            Err(_) => {
UNCOV
369
                return Err(ReflectError::Unsized {
×
UNCOV
370
                    shape: value_shape,
×
UNCOV
371
                    operation: "begin_object_entry: calculating value layout",
×
UNCOV
372
                });
×
373
            }
374
        };
375

376
        let value_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(value_layout) };
26✔
377
        let Some(value_ptr) = NonNull::new(value_ptr) else {
26✔
UNCOV
378
            return Err(ReflectError::OperationFailed {
×
UNCOV
379
                shape: frame.shape,
×
UNCOV
380
                operation: "failed to allocate memory for object value",
×
UNCOV
381
            });
×
382
        };
383

384
        // Update the insert state with the key
385
        match &mut frame.tracker {
26✔
386
            Tracker::DynamicValue {
387
                state: DynamicValueState::Object { insert_state },
26✔
388
            } => {
26✔
389
                *insert_state = DynamicObjectInsertState::BuildingValue {
26✔
390
                    key: String::from(key),
26✔
391
                };
26✔
392
            }
26✔
UNCOV
393
            _ => unreachable!(),
×
394
        }
395

396
        // Push a new frame for the value
397
        self.frames_mut().push(Frame::new(
26✔
398
            PtrUninit::new(value_ptr),
26✔
399
            value_shape,
26✔
400
            FrameOwnership::Owned,
26✔
401
        ));
402

403
        Ok(self)
26✔
404
    }
27✔
405
}
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