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

facet-rs / facet / 19777793341

29 Nov 2025 02:37AM UTC coverage: 61.03% (+0.2%) from 60.834%
19777793341

push

github

fasterthanlime
Fix clippy warnings and update compile test expectations

- Use direct comparison instead of to_string() in process_struct.rs
- Use starts_with() instead of chars().next() in format.rs
- Collapse nested if let patterns in facet-yaml
- Update compile_tests to expect "unknown extension attribute" error

2 of 6 new or added lines in 4 files covered. (33.33%)

249 existing lines in 9 files now uncovered.

17255 of 28273 relevant lines covered (61.03%)

156.0 hits per line

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

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

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Internal methods
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl<'facet> Partial<'facet> {
7
    /// Preconditions:
8
    ///
9
    /// - `require_active()` check was made
10
    /// - frame.shape.ty is an Enum
11
    /// - `discriminant` is a valid discriminant
12
    ///
13
    /// Panics if current tracker is anything other than `Uninit`
14
    /// (switching variants is not supported for now).
15
    pub(crate) fn select_variant_internal(
208✔
16
        &mut self,
208✔
17
        enum_type: &EnumType,
208✔
18
        variant: &'static Variant,
208✔
19
    ) -> Result<(), ReflectError> {
208✔
20
        // Check all invariants early before making any changes
21
        let frame = self.frames().last().unwrap();
208✔
22

23
        // Check enum representation early
24
        match enum_type.enum_repr {
208✔
25
            EnumRepr::RustNPO => {
26
                return Err(ReflectError::OperationFailed {
×
27
                    shape: frame.shape,
×
28
                    operation: "RustNPO enums are not supported for incremental building",
×
29
                });
×
30
            }
31
            EnumRepr::U8
32
            | EnumRepr::U16
33
            | EnumRepr::U32
34
            | EnumRepr::U64
35
            | EnumRepr::I8
36
            | EnumRepr::I16
37
            | EnumRepr::I32
38
            | EnumRepr::I64
39
            | EnumRepr::USize
40
            | EnumRepr::ISize => {
208✔
41
                // These are supported, continue
208✔
42
            }
208✔
43
        }
44

45
        let Some(discriminant) = variant.discriminant else {
208✔
46
            return Err(ReflectError::OperationFailed {
×
47
                shape: frame.shape,
×
48
                operation: "trying to select an enum variant without a discriminant",
×
49
            });
×
50
        };
51

52
        // All checks passed, now we can safely make changes
53
        let fr = self.frames_mut().last_mut().unwrap();
208✔
54

55
        // Write the discriminant to memory
56
        unsafe {
57
            match enum_type.enum_repr {
208✔
58
                EnumRepr::U8 => {
178✔
59
                    let ptr = fr.data.as_mut_byte_ptr();
178✔
60
                    *ptr = discriminant as u8;
178✔
61
                }
178✔
62
                EnumRepr::U16 => {
2✔
63
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u16;
2✔
64
                    *ptr = discriminant as u16;
2✔
65
                }
2✔
66
                EnumRepr::U32 => {
23✔
67
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u32;
23✔
68
                    *ptr = discriminant as u32;
23✔
69
                }
23✔
70
                EnumRepr::U64 => {
×
71
                    let ptr = fr.data.as_mut_byte_ptr() as *mut u64;
×
72
                    *ptr = discriminant as u64;
×
73
                }
×
74
                EnumRepr::I8 => {
×
75
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i8;
×
76
                    *ptr = discriminant as i8;
×
77
                }
×
78
                EnumRepr::I16 => {
4✔
79
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i16;
4✔
80
                    *ptr = discriminant as i16;
4✔
81
                }
4✔
82
                EnumRepr::I32 => {
1✔
83
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i32;
1✔
84
                    *ptr = discriminant as i32;
1✔
85
                }
1✔
86
                EnumRepr::I64 => {
×
87
                    let ptr = fr.data.as_mut_byte_ptr() as *mut i64;
×
88
                    *ptr = discriminant;
×
89
                }
×
90
                EnumRepr::USize => {
×
91
                    let ptr = fr.data.as_mut_byte_ptr() as *mut usize;
×
92
                    *ptr = discriminant as usize;
×
93
                }
×
94
                EnumRepr::ISize => {
×
95
                    let ptr = fr.data.as_mut_byte_ptr() as *mut isize;
×
96
                    *ptr = discriminant as isize;
×
97
                }
×
98
                _ => unreachable!("Already checked enum representation above"),
×
99
            }
100
        }
101

102
        // Update tracker to track the variant
103
        fr.tracker = Tracker::Enum {
208✔
104
            variant,
208✔
105
            data: ISet::new(variant.data.fields.len()),
208✔
106
            current_child: None,
208✔
107
        };
208✔
108

109
        Ok(())
208✔
110
    }
208✔
111

112
    /// Used by `begin_field` etc. to get a list of fields to look through, errors out
113
    /// if we're not pointing to a struct or an enum with an already-selected variant
114
    pub(crate) fn get_fields(&self) -> Result<&'static [Field], ReflectError> {
1,969✔
115
        let frame = self.frames().last().unwrap();
1,969✔
116
        match frame.shape.ty {
1,969✔
117
            Type::Primitive(_) => Err(ReflectError::OperationFailed {
1✔
118
                shape: frame.shape,
1✔
119
                operation: "cannot select a field from a primitive type",
1✔
120
            }),
1✔
121
            Type::Sequence(_) => Err(ReflectError::OperationFailed {
×
122
                shape: frame.shape,
×
123
                operation: "cannot select a field from a sequence type",
×
124
            }),
×
125
            Type::User(user_type) => match user_type {
1,968✔
126
                UserType::Struct(struct_type) => Ok(struct_type.fields),
1,804✔
127
                UserType::Enum(_) => {
128
                    let Tracker::Enum { variant, .. } = &frame.tracker else {
159✔
129
                        return Err(ReflectError::OperationFailed {
1✔
130
                            shape: frame.shape,
1✔
131
                            operation: "must select variant before selecting enum fields",
1✔
132
                        });
1✔
133
                    };
134
                    Ok(variant.data.fields)
158✔
135
                }
136
                UserType::Union(_) => Err(ReflectError::OperationFailed {
×
137
                    shape: frame.shape,
×
138
                    operation: "cannot select a field from a union type",
×
139
                }),
×
140
                UserType::Opaque => Err(ReflectError::OperationFailed {
5✔
141
                    shape: frame.shape,
5✔
142
                    operation: "opaque types cannot be reflected upon",
5✔
143
                }),
5✔
144
            },
145
            Type::Pointer(_) => Err(ReflectError::OperationFailed {
×
146
                shape: frame.shape,
×
147
                operation: "cannot select a field from a pointer type",
×
148
            }),
×
149
        }
150
    }
1,969✔
151

152
    /// Selects the nth field of a struct by index
153
    pub(crate) fn begin_nth_struct_field(
1,990✔
154
        frame: &mut Frame,
1,990✔
155
        struct_type: StructType,
1,990✔
156
        idx: usize,
1,990✔
157
    ) -> Result<Frame, ReflectError> {
1,990✔
158
        if idx >= struct_type.fields.len() {
1,990✔
159
            return Err(ReflectError::OperationFailed {
1✔
160
                shape: frame.shape,
1✔
161
                operation: "field index out of bounds",
1✔
162
            });
1✔
163
        }
1,989✔
164
        let field = &struct_type.fields[idx];
1,989✔
165

166
        if !matches!(frame.tracker, Tracker::Struct { .. }) {
1,989✔
167
            // When transitioning from Scalar (fully initialized) to Struct tracker,
168
            // we need to mark all fields as initialized in the iset. Otherwise,
169
            // we'll lose track of which fields were initialized and may double-free.
170
            let was_fully_init = frame.is_init && matches!(frame.tracker, Tracker::Scalar);
1,263✔
171
            let mut iset = ISet::new(struct_type.fields.len());
1,263✔
172
            if was_fully_init {
1,263✔
173
                iset.set_all();
×
174
            }
1,263✔
175
            frame.tracker = Tracker::Struct {
1,263✔
176
                iset,
1,263✔
177
                current_child: None,
1,263✔
178
            }
1,263✔
179
        }
726✔
180

181
        let was_field_init = match &mut frame.tracker {
1,989✔
182
            Tracker::Struct {
183
                iset,
1,989✔
184
                current_child,
1,989✔
185
            } => {
186
                *current_child = Some(idx);
1,989✔
187
                let was_init = iset.get(idx);
1,989✔
188
                iset.unset(idx); // Parent relinquishes responsibility
1,989✔
189
                was_init
1,989✔
190
            }
191
            _ => unreachable!(),
×
192
        };
193

194
        // Push a new frame for this field onto the frames stack.
195
        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
1,989✔
196
        let field_shape = field.shape();
1,989✔
197

198
        let mut next_frame = Frame::new(
1,989✔
199
            field_ptr,
1,989✔
200
            field_shape,
1,989✔
201
            FrameOwnership::Field { field_idx: idx },
1,989✔
202
        );
203
        if was_field_init {
1,989✔
204
            unsafe {
14✔
205
                // the struct field tracker said so!
14✔
206
                next_frame.mark_as_init();
14✔
207
            }
14✔
208
        }
1,975✔
209

210
        Ok(next_frame)
1,989✔
211
    }
1,990✔
212

213
    /// Selects the nth element of an array by index
214
    pub(crate) fn begin_nth_array_element(
93✔
215
        frame: &mut Frame,
93✔
216
        array_type: ArrayType,
93✔
217
        idx: usize,
93✔
218
    ) -> Result<Frame, ReflectError> {
93✔
219
        if idx >= array_type.n {
93✔
220
            return Err(ReflectError::OperationFailed {
1✔
221
                shape: frame.shape,
1✔
222
                operation: "array index out of bounds",
1✔
223
            });
1✔
224
        }
92✔
225

226
        if array_type.n > 63 {
92✔
227
            return Err(ReflectError::OperationFailed {
×
228
                shape: frame.shape,
×
229
                operation: "arrays larger than 63 elements are not yet supported",
×
230
            });
×
231
        }
92✔
232

233
        // Ensure frame is in Array state
234
        match &frame.tracker {
36✔
235
            Tracker::Scalar if !frame.is_init => {
36✔
236
                // this is fine, transition to Array tracker
36✔
237
                frame.tracker = Tracker::Array {
36✔
238
                    iset: ISet::default(),
36✔
239
                    current_child: None,
36✔
240
                };
36✔
241
            }
36✔
242
            Tracker::Array { .. } => {
56✔
243
                // fine too
56✔
244
            }
56✔
245
            _other => {
×
246
                return Err(ReflectError::OperationFailed {
×
247
                    shape: frame.shape,
×
248
                    operation: "unexpected tracker state: expected uninitialized Scalar or Array",
×
249
                });
×
250
            }
251
        }
252

253
        match &mut frame.tracker {
92✔
254
            Tracker::Array {
255
                iset,
92✔
256
                current_child,
92✔
257
            } => {
258
                *current_child = Some(idx);
92✔
259
                let was_field_init = iset.get(idx);
92✔
260
                iset.unset(idx); // Parent relinquishes responsibility
92✔
261

262
                // Calculate the offset for this array element
263
                let Ok(element_layout) = array_type.t.layout.sized_layout() else {
92✔
264
                    return Err(ReflectError::Unsized {
×
265
                        shape: array_type.t,
×
266
                        operation: "begin_nth_element, calculating array element offset",
×
267
                    });
×
268
                };
269
                let offset = element_layout.size() * idx;
92✔
270
                let element_data = unsafe { frame.data.field_uninit_at(offset) };
92✔
271

272
                let mut next_frame = Frame::new(
92✔
273
                    element_data,
92✔
274
                    array_type.t,
92✔
275
                    FrameOwnership::Field { field_idx: idx },
92✔
276
                );
277
                if was_field_init {
92✔
278
                    // safety: `iset` said it was initialized already
279
                    unsafe {
2✔
280
                        next_frame.mark_as_init();
2✔
281
                    }
2✔
282
                }
90✔
283
                Ok(next_frame)
92✔
284
            }
285
            _ => unreachable!(),
×
286
        }
287
    }
93✔
288

289
    /// Selects the nth field of an enum variant by index
290
    pub(crate) fn begin_nth_enum_field(
208✔
291
        frame: &mut Frame,
208✔
292
        variant: &'static Variant,
208✔
293
        idx: usize,
208✔
294
    ) -> Result<Frame, ReflectError> {
208✔
295
        if idx >= variant.data.fields.len() {
208✔
296
            return Err(ReflectError::OperationFailed {
×
297
                shape: frame.shape,
×
298
                operation: "enum field index out of bounds",
×
299
            });
×
300
        }
208✔
301

302
        let field = &variant.data.fields[idx];
208✔
303

304
        // Update tracker
305
        let was_field_init = match &mut frame.tracker {
208✔
306
            Tracker::Enum {
307
                data,
208✔
308
                current_child,
208✔
309
                ..
310
            } => {
311
                *current_child = Some(idx);
208✔
312
                let was_init = data.get(idx);
208✔
313
                data.unset(idx); // Parent relinquishes responsibility
208✔
314
                was_init
208✔
315
            }
316
            _ => {
317
                return Err(ReflectError::OperationFailed {
×
318
                    shape: frame.shape,
×
319
                    operation: "selecting a field on an enum requires selecting a variant first",
×
320
                });
×
321
            }
322
        };
323

324
        // SAFETY: the field offset comes from an unsafe impl of the Facet trait, we trust it.
325
        // also, we checked that the variant was selected.
326
        let field_ptr = unsafe { frame.data.field_uninit_at(field.offset) };
208✔
327
        let field_shape = field.shape();
208✔
328

329
        let mut next_frame = Frame::new(
208✔
330
            field_ptr,
208✔
331
            field_shape,
208✔
332
            FrameOwnership::Field { field_idx: idx },
208✔
333
        );
334
        if was_field_init {
208✔
335
            // SAFETY: `ISet` told us the field was initialized
336
            unsafe {
1✔
337
                next_frame.mark_as_init();
1✔
338
            }
1✔
339
        }
207✔
340

341
        Ok(next_frame)
208✔
342
    }
208✔
343

344
    /// Require that the partial is active
345
    #[inline]
346
    pub(crate) fn require_active(&self) -> Result<(), ReflectError> {
16,360✔
347
        if self.state == PartialState::Active {
16,360✔
348
            Ok(())
16,331✔
349
        } else {
350
            Err(ReflectError::InvariantViolation {
29✔
351
                invariant: "Cannot use Partial after it has been built or poisoned",
29✔
352
            })
29✔
353
        }
354
    }
16,360✔
355

356
    /// Poisons the Partial and cleans up all frames.
357
    ///
358
    /// This is called when an unrecoverable error occurs (e.g., finish_deferred fails).
359
    /// After poisoning:
360
    /// - All frames are deinitialized and deallocated
361
    /// - The Partial's state is set to BuildFailed
362
    /// - All subsequent operations will fail with an error
363
    ///
364
    /// This prevents use-after-error bugs where continuing to use a Partial after
365
    /// a failed operation could lead to memory leaks or double-frees.
366
    pub(crate) fn poison_and_cleanup(&mut self) {
12✔
367
        // First, clean up any stored frames (if we were in deferred mode)
368
        if let FrameMode::Deferred { stored_frames, .. } = &mut self.mode {
12✔
UNCOV
369
            for (_, mut frame) in core::mem::take(stored_frames) {
×
UNCOV
370
                frame.deinit();
×
UNCOV
371
                // Don't deallocate - Field ownership means parent owns the memory
×
UNCOV
372
            }
×
373
        }
12✔
374

375
        // Then clean up all stack frames
376
        while let Some(mut frame) = self.mode.stack_mut().pop() {
25✔
377
            frame.deinit();
13✔
378
            if let FrameOwnership::Owned = frame.ownership {
13✔
379
                frame.dealloc();
12✔
380
            }
12✔
381
        }
382

383
        // Mark as poisoned
384
        self.state = PartialState::BuildFailed;
12✔
385
    }
12✔
386

387
    /// Prepares the current frame for re-initialization by dropping any existing
388
    /// value and unmarking it in the parent's iset.
389
    ///
390
    /// This should be called at the start of `begin_*` methods that support
391
    /// re-initialization (e.g., `begin_some`, `begin_inner`, `begin_smart_ptr`).
392
    ///
393
    /// Returns `true` if cleanup was performed (frame was previously initialized),
394
    /// `false` if the frame was not initialized.
395
    pub(crate) fn prepare_for_reinitialization(&mut self) -> bool {
111✔
396
        let frame = self.frames().last().unwrap();
111✔
397

398
        // Check if there's anything to reinitialize:
399
        // - For Scalar tracker: check is_init flag
400
        // - For Struct/Array/Enum trackers: these may have initialized fields even if is_init is false
401
        //   (is_init tracks the whole value, iset/data tracks individual fields)
402
        let needs_cleanup = match &frame.tracker {
111✔
403
            Tracker::Scalar => frame.is_init,
101✔
404
            // Non-Scalar trackers indicate fields were accessed, so deinit() will handle them
405
            Tracker::Struct { .. }
406
            | Tracker::Array { .. }
407
            | Tracker::Enum { .. }
408
            | Tracker::SmartPointer
409
            | Tracker::SmartPointerSlice { .. }
410
            | Tracker::List { .. }
411
            | Tracker::Map { .. }
412
            | Tracker::Set { .. }
413
            | Tracker::Option { .. }
414
            | Tracker::DynamicValue { .. } => true,
10✔
415
        };
416
        if !needs_cleanup {
111✔
417
            return false;
96✔
418
        }
15✔
419

420
        // Use deinit() to properly handle:
421
        // - Scalar frames: drops the whole value if is_init
422
        // - Struct frames: only drops fields marked in iset (avoiding double-free)
423
        // - Array frames: only drops elements marked in iset
424
        // - Enum frames: only drops fields marked in data
425
        // - Map/Set frames: also cleans up partial insert state (key/value buffers)
426
        let frame = self.frames_mut().last_mut().unwrap();
15✔
427
        frame.deinit();
15✔
428

429
        true
15✔
430
    }
111✔
431
}
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