• 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

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

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Field selection
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl Partial<'_> {
7
    /// Find the index of a field by name in the current struct
8
    ///
9
    /// If the current frame isn't a struct or an enum (with a selected variant)
10
    /// then this returns `None` for sure.
11
    pub fn field_index(&self, field_name: &str) -> Option<usize> {
96✔
12
        let frame = self.frames().last()?;
96✔
13

14
        match frame.shape.ty {
96✔
15
            Type::User(UserType::Struct(struct_def)) => {
93✔
16
                struct_def.fields.iter().position(|f| f.name == field_name)
145✔
17
            }
18
            Type::User(UserType::Enum(_)) => {
19
                // If we're in an enum variant, check its fields
20
                if let Tracker::Enum { variant, .. } = &frame.tracker {
3✔
21
                    variant
3✔
22
                        .data
3✔
23
                        .fields
3✔
24
                        .iter()
3✔
25
                        .position(|f| f.name == field_name)
6✔
26
                } else {
27
                    None
×
28
                }
29
            }
30
            _ => None,
×
31
        }
32
    }
96✔
33

34
    /// Check if a struct field at the given index has been set
35
    pub fn is_field_set(&self, index: usize) -> Result<bool, ReflectError> {
441✔
36
        let frame = self.frames().last().ok_or(ReflectError::NoActiveFrame)?;
441✔
37

38
        match &frame.tracker {
441✔
39
            Tracker::Scalar => Ok(frame.is_init),
108✔
40
            Tracker::Struct { iset, .. } => Ok(iset.get(index)),
326✔
41
            Tracker::Enum { data, variant, .. } => {
7✔
42
                // Check if the field is already marked as set
43
                if data.get(index) {
7✔
44
                    return Ok(true);
7✔
45
                }
×
46

47
                // For enum variant fields that are empty structs, they are always initialized
48
                if let Some(field) = variant.data.fields.get(index) {
×
49
                    if let Type::User(UserType::Struct(field_struct)) = field.shape().ty {
×
50
                        if field_struct.fields.is_empty() {
×
51
                            return Ok(true);
×
52
                        }
×
53
                    }
×
54
                }
×
55

56
                Ok(false)
×
57
            }
58
            Tracker::Option { building_inner } => {
×
59
                // For Options, index 0 represents the inner value
60
                if index == 0 {
×
61
                    Ok(!building_inner)
×
62
                } else {
63
                    Err(ReflectError::InvalidOperation {
×
64
                        operation: "is_field_set",
×
65
                        reason: "Option only has one field (index 0)",
×
66
                    })
×
67
                }
68
            }
69
            _ => Err(ReflectError::InvalidOperation {
×
70
                operation: "is_field_set",
×
71
                reason: "Current frame is not a struct, enum variant, or option",
×
72
            }),
×
73
        }
74
    }
441✔
75

76
    /// Selects a field (by name) of a struct or enum data.
77
    ///
78
    /// For enums, the variant needs to be selected first, see [Self::select_nth_variant]
79
    /// and friends.
80
    pub fn begin_field(self, field_name: &str) -> Result<Self, ReflectError> {
1,917✔
81
        let frame = self.frames().last().unwrap();
1,917✔
82
        let fields = self.get_fields()?;
1,917✔
83
        let Some(idx) = fields.iter().position(|f| f.name == field_name) else {
3,169✔
84
            return Err(ReflectError::FieldError {
8✔
85
                shape: frame.shape,
8✔
86
                field_error: facet_core::FieldError::NoSuchField,
8✔
87
            });
8✔
88
        };
89
        self.begin_nth_field(idx)
1,905✔
90
    }
1,917✔
91

92
    /// Begins the nth field of a struct, enum variant, or array, by index.
93
    ///
94
    /// On success, this pushes a new frame which must be ended with a call to [Partial::end]
95
    pub fn begin_nth_field(mut self, idx: usize) -> Result<Self, ReflectError> {
2,364✔
96
        // In deferred mode, get the field name for path tracking and check for stored frames.
97
        // Only track the path if we're at a "navigable" level - i.e., the path length matches
98
        // the expected depth (frames.len() - 1). If we're inside a collection item, the path
99
        // will be shorter than expected, so we shouldn't add to it.
100
        let field_name = self.get_field_name_for_path(idx);
2,364✔
101

102
        // Update current_path in deferred mode
103
        if let FrameMode::Deferred {
104
            stack,
1,007✔
105
            start_depth,
1,007✔
106
            current_path,
1,007✔
107
            stored_frames,
1,007✔
108
            ..
109
        } = &mut self.mode
2,364✔
110
        {
111
            // Only track path if we're at the expected navigable depth
112
            // Path should have (frames.len() - start_depth) entries before we add this field
113
            let relative_depth = stack.len() - *start_depth;
1,007✔
114
            let should_track = current_path.len() == relative_depth;
1,007✔
115

116
            if let Some(name) = field_name {
1,007✔
117
                if should_track {
994✔
118
                    current_path.push(name);
900✔
119

120
                    // Check if we have a stored frame for this path
121
                    if let Some(stored_frame) = stored_frames.remove(current_path) {
900✔
122
                        trace!("begin_nth_field: Restoring stored frame for path {current_path:?}");
123

124
                        // Update parent's current_child tracking
125
                        let frame = stack.last_mut().unwrap();
61✔
126
                        frame.tracker.set_current_child(idx);
61✔
127

128
                        stack.push(stored_frame);
61✔
129
                        return Ok(self);
61✔
130
                    }
839✔
131
                }
94✔
132
            }
13✔
133
        }
1,357✔
134

135
        let frame = self.frames_mut().last_mut().unwrap();
2,303✔
136

137
        let next_frame = match frame.shape.ty {
2,303✔
138
            Type::User(user_type) => match user_type {
2,207✔
139
                UserType::Struct(struct_type) => {
1,994✔
140
                    Self::begin_nth_struct_field(frame, struct_type, idx)?
1,994✔
141
                }
142
                UserType::Enum(_) => {
143
                    // Check if we have a variant selected
144
                    match &frame.tracker {
213✔
145
                        Tracker::Enum { variant, .. } => {
213✔
146
                            Self::begin_nth_enum_field(frame, variant, idx)?
213✔
147
                        }
148
                        _ => {
UNCOV
149
                            return Err(ReflectError::OperationFailed {
×
UNCOV
150
                                shape: frame.shape,
×
UNCOV
151
                                operation: "must call select_variant before selecting enum fields",
×
UNCOV
152
                            });
×
153
                        }
154
                    }
155
                }
156
                UserType::Union(_) => {
UNCOV
157
                    return Err(ReflectError::OperationFailed {
×
UNCOV
158
                        shape: frame.shape,
×
UNCOV
159
                        operation: "cannot select a field from a union",
×
UNCOV
160
                    });
×
161
                }
162
                UserType::Opaque => {
163
                    return Err(ReflectError::OperationFailed {
×
164
                        shape: frame.shape,
×
UNCOV
165
                        operation: "cannot select a field from an opaque type",
×
UNCOV
166
                    });
×
167
                }
168
            },
169
            Type::Sequence(sequence_type) => match sequence_type {
96✔
170
                SequenceType::Array(array_type) => {
96✔
171
                    Self::begin_nth_array_element(frame, array_type, idx)?
96✔
172
                }
173
                SequenceType::Slice(_) => {
UNCOV
174
                    return Err(ReflectError::OperationFailed {
×
UNCOV
175
                        shape: frame.shape,
×
UNCOV
176
                        operation: "cannot select a field from slices yet",
×
UNCOV
177
                    });
×
178
                }
179
            },
180
            _ => {
181
                return Err(ReflectError::OperationFailed {
×
UNCOV
182
                    shape: frame.shape,
×
UNCOV
183
                    operation: "cannot select a field from this type",
×
UNCOV
184
                });
×
185
            }
186
        };
187

188
        self.frames_mut().push(next_frame);
2,302✔
189
        Ok(self)
2,302✔
190
    }
2,364✔
191

192
    /// Get the field name for path tracking (used in deferred mode)
193
    fn get_field_name_for_path(&self, idx: usize) -> Option<&'static str> {
2,364✔
194
        let frame = self.frames().last()?;
2,364✔
195
        match frame.shape.ty {
2,268✔
196
            Type::User(UserType::Struct(struct_type)) => {
2,055✔
197
                struct_type.fields.get(idx).map(|f| f.name)
2,055✔
198
            }
199
            Type::User(UserType::Enum(_)) => {
200
                if let Tracker::Enum { variant, .. } = &frame.tracker {
213✔
201
                    variant.data.fields.get(idx).map(|f| f.name)
213✔
202
                } else {
UNCOV
203
                    None
×
204
                }
205
            }
206
            // For arrays, we could use index as string, but for now return None
207
            _ => None,
96✔
208
        }
209
    }
2,364✔
210

211
    /// Sets the given field to its default value, preferring:
212
    ///
213
    ///   * A `default = some_fn()` function
214
    ///   * The field's `Default` implementation if any
215
    ///
216
    /// But without going all the way up to the parent struct's `Default` impl.
217
    ///
218
    /// Errors out if idx is out of bound, if the field has no default method or Default impl.
219
    pub fn set_nth_field_to_default(mut self, idx: usize) -> Result<Self, ReflectError> {
28✔
220
        let frame = self.frames().last().unwrap();
28✔
221
        let fields = self.get_fields()?;
28✔
222

223
        if idx >= fields.len() {
28✔
UNCOV
224
            return Err(ReflectError::OperationFailed {
×
UNCOV
225
                shape: frame.shape,
×
UNCOV
226
                operation: "field index out of bounds",
×
UNCOV
227
            });
×
228
        }
28✔
229

230
        let field = fields[idx];
28✔
231

232
        // Check for field-level default function first, then type-level default
233
        if let Some(field_default_fn) = field.vtable.default_fn {
28✔
234
            self = self.begin_nth_field(idx)?;
8✔
235
            // the field default fn should be well-behaved
236
            self = unsafe {
8✔
237
                self.set_from_function(|ptr| {
8✔
238
                    field_default_fn(ptr);
8✔
239
                    Ok(())
8✔
240
                })?
8✔
241
            };
242
            self.end()
8✔
243
        } else if field.shape().is(Characteristic::Default) {
20✔
244
            self = self.begin_nth_field(idx)?;
20✔
245
            self = self.set_default()?;
20✔
246
            self.end()
20✔
247
        } else {
UNCOV
248
            Err(ReflectError::DefaultAttrButNoDefaultImpl {
×
UNCOV
249
                shape: field.shape(),
×
UNCOV
250
            })
×
251
        }
252
    }
28✔
253

254
    /// Given a `Partial` for the same shape, and assuming that partial has the nth
255
    /// field initialized, move the value from `src` to `self`, marking it as deinitialized
256
    /// in `src`.
257
    pub fn steal_nth_field(
2✔
258
        mut self,
2✔
259
        src: &mut Partial,
2✔
260
        field_index: usize,
2✔
261
    ) -> Result<Self, ReflectError> {
2✔
262
        let dst_shape = self.shape();
2✔
263
        let src_shape = src.shape();
2✔
264
        if dst_shape != src_shape {
2✔
UNCOV
265
            return Err(ReflectError::HeistCancelledDifferentShapes {
×
UNCOV
266
                src_shape,
×
UNCOV
267
                dst_shape,
×
UNCOV
268
            });
×
269
        }
2✔
270

271
        // FIXME: what about enums? we don't check that the right variant is
272
        // selected here.
273
        if !src.is_field_set(field_index)? {
2✔
274
            return Err(ReflectError::InvariantViolation {
×
UNCOV
275
                invariant: "stolen field must be initialized",
×
UNCOV
276
            });
×
277
        }
2✔
278

279
        let maybe_fields = match src_shape.ty {
2✔
280
            Type::Primitive(_primitive_type) => None,
×
281
            Type::Sequence(_sequence_type) => None,
×
282
            Type::User(user_type) => match user_type {
2✔
283
                UserType::Struct(struct_type) => Some(struct_type.fields),
2✔
UNCOV
284
                UserType::Enum(_enum_type) => match self.selected_variant() {
×
UNCOV
285
                    Some(variant) => Some(variant.data.fields),
×
286
                    None => {
287
                        return Err(ReflectError::InvariantViolation {
×
UNCOV
288
                            invariant: "enum field thief must have variant selected",
×
UNCOV
289
                        });
×
290
                    }
291
                },
UNCOV
292
                UserType::Union(_union_type) => None,
×
293
                UserType::Opaque => None,
×
294
            },
295
            Type::Pointer(_pointer_type) => None,
×
296
        };
297

298
        let Some(fields) = maybe_fields else {
2✔
299
            return Err(ReflectError::OperationFailed {
×
UNCOV
300
                shape: src_shape,
×
301
                operation: "fetching field list for steal_nth_field",
×
UNCOV
302
            });
×
303
        };
304

305
        if field_index >= fields.len() {
2✔
306
            return Err(ReflectError::OperationFailed {
×
307
                shape: src_shape,
×
308
                operation: "field index out of bounds",
×
UNCOV
309
            });
×
310
        }
2✔
311
        let field = fields[field_index];
2✔
312

313
        let src_frame = src.frames_mut().last_mut().unwrap();
2✔
314

315
        self = self.begin_nth_field(field_index)?;
2✔
316
        self = unsafe {
2✔
317
            self.set_from_function(|dst_field_ptr| {
2✔
318
                let src_field_ptr = src_frame.data.field_init_at(field.offset).as_const();
2✔
319
                dst_field_ptr
2✔
320
                    .copy_from(src_field_ptr, field.shape())
2✔
321
                    .unwrap();
2✔
322
                Ok(())
2✔
323
            })?
2✔
324
        };
325
        self = self.end()?;
2✔
326

327
        // now mark field as uninitialized in `src`
328
        // Note: we need to get src_frame again since we moved self above
329
        let src_frame = src.frames_mut().last_mut().unwrap();
2✔
330
        match &mut src_frame.tracker {
2✔
331
            Tracker::Scalar => {
332
                if !src_frame.is_init {
1✔
UNCOV
333
                    unreachable!(
×
334
                        "we just stole a field from src, it couldn't have been fully uninit"
335
                    )
336
                }
1✔
337
                // all struct fields were init so we don't even have a struct tracker,
338
                // let's make one!
339
                let mut iset = ISet::new(fields.len());
1✔
340
                iset.set_all();
1✔
341
                iset.unset(field_index);
1✔
342
                src_frame.tracker = Tracker::Struct {
1✔
343
                    iset,
1✔
344
                    current_child: None,
1✔
345
                };
1✔
346
                src_frame.is_init = false; // no longer fully initialized
1✔
347
            }
UNCOV
348
            Tracker::Array { .. } => unreachable!("can't steal fields from arrays"),
×
349
            Tracker::Struct { iset, .. } => {
1✔
350
                iset.unset(field_index);
1✔
351
            }
1✔
352
            Tracker::SmartPointer => {
UNCOV
353
                unreachable!("can't steal fields from smart pointers")
×
354
            }
355
            Tracker::SmartPointerSlice { .. } => {
UNCOV
356
                unreachable!("can't steal fields from smart pointer slices")
×
357
            }
UNCOV
358
            Tracker::Enum { data, .. } => {
×
UNCOV
359
                data.unset(field_index);
×
360
            }
×
361
            Tracker::List { .. } => {
362
                unreachable!("can't steal fields from lists")
×
363
            }
364
            Tracker::Map { .. } => {
UNCOV
365
                unreachable!("can't steal fields from maps")
×
366
            }
367
            Tracker::Set { .. } => {
UNCOV
368
                unreachable!("can't steal fields from sets")
×
369
            }
370
            Tracker::Option { .. } => {
UNCOV
371
                unreachable!("can't steal fields from options")
×
372
            }
373
            Tracker::DynamicValue { .. } => {
UNCOV
374
                unreachable!("can't steal fields from dynamic values")
×
375
            }
376
        }
377

378
        Ok(self)
2✔
379
    }
2✔
380
}
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