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

facet-rs / facet / 19870848606

02 Dec 2025 07:24PM UTC coverage: 58.759% (-0.2%) from 58.959%
19870848606

Pull #991

github

web-flow
Merge 674638beb into e0459e2a8
Pull Request #991: Add Facet implementation for Result<T, E>

145 of 365 new or added lines in 9 files covered. (39.73%)

2 existing lines in 2 files now uncovered.

20467 of 34832 relevant lines covered (58.76%)

539.42 hits per line

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

72.22
/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(
262✔
16
        &mut self,
262✔
17
        enum_type: &EnumType,
262✔
18
        variant: &'static Variant,
262✔
19
    ) -> Result<(), ReflectError> {
262✔
20
        // Check all invariants early before making any changes
21
        let frame = self.frames().last().unwrap();
262✔
22

23
        // Check enum representation early
24
        match enum_type.enum_repr {
262✔
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 => {
262✔
41
                // These are supported, continue
262✔
42
            }
262✔
43
        }
44

45
        let Some(discriminant) = variant.discriminant else {
262✔
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();
262✔
54

55
        // Write the discriminant to memory
56
        unsafe {
57
            match enum_type.enum_repr {
262✔
58
                EnumRepr::U8 => {
232✔
59
                    let ptr = fr.data.as_mut_byte_ptr();
232✔
60
                    *ptr = discriminant as u8;
232✔
61
                }
232✔
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 {
262✔
104
            variant,
262✔
105
            data: ISet::new(variant.data.fields.len()),
262✔
106
            current_child: None,
262✔
107
        };
262✔
108

109
        Ok(())
262✔
110
    }
262✔
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,978✔
115
        let frame = self.frames().last().unwrap();
1,978✔
116
        match frame.shape.ty {
1,978✔
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,977✔
126
                UserType::Struct(struct_type) => Ok(struct_type.fields),
1,812✔
127
                UserType::Enum(_) => {
128
                    let Tracker::Enum { variant, .. } = &frame.tracker else {
163✔
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)
162✔
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 {
2✔
141
                    shape: frame.shape,
2✔
142
                    operation: "opaque types cannot be reflected upon",
2✔
143
                }),
2✔
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,978✔
151

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

166
        if !matches!(frame.tracker, Tracker::Struct { .. }) {
2,569✔
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,740✔
171
            let mut iset = ISet::new(struct_type.fields.len());
1,740✔
172
            if was_fully_init {
1,740✔
173
                iset.set_all();
×
174
            }
1,740✔
175
            frame.tracker = Tracker::Struct {
1,740✔
176
                iset,
1,740✔
177
                current_child: None,
1,740✔
178
            }
1,740✔
179
        }
829✔
180

181
        let was_field_init = match &mut frame.tracker {
2,569✔
182
            Tracker::Struct {
183
                iset,
2,569✔
184
                current_child,
2,569✔
185
            } => {
186
                *current_child = Some(idx);
2,569✔
187
                let was_init = iset.get(idx);
2,569✔
188
                iset.unset(idx); // Parent relinquishes responsibility
2,569✔
189
                was_init
2,569✔
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) };
2,569✔
196
        let field_shape = field.shape();
2,569✔
197

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

210
        Ok(next_frame)
2,569✔
211
    }
2,569✔
212

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

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

233
        // Ensure frame is in Array state
234
        match &frame.tracker {
45✔
235
            Tracker::Scalar if !frame.is_init => {
45✔
236
                // this is fine, transition to Array tracker
45✔
237
                frame.tracker = Tracker::Array {
45✔
238
                    iset: ISet::default(),
45✔
239
                    current_child: None,
45✔
240
                };
45✔
241
            }
45✔
242
            Tracker::Array { .. } => {
100✔
243
                // fine too
100✔
244
            }
100✔
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 {
145✔
254
            Tracker::Array {
255
                iset,
145✔
256
                current_child,
145✔
257
            } => {
258
                *current_child = Some(idx);
145✔
259
                let was_field_init = iset.get(idx);
145✔
260
                iset.unset(idx); // Parent relinquishes responsibility
145✔
261

262
                // Calculate the offset for this array element
263
                let Ok(element_layout) = array_type.t.layout.sized_layout() else {
145✔
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;
145✔
270
                let element_data = unsafe { frame.data.field_uninit_at(offset) };
145✔
271

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

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

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

304
        // Update tracker
305
        let was_field_init = match &mut frame.tracker {
256✔
306
            Tracker::Enum {
307
                data,
256✔
308
                current_child,
256✔
309
                ..
310
            } => {
311
                *current_child = Some(idx);
256✔
312
                let was_init = data.get(idx);
256✔
313
                data.unset(idx); // Parent relinquishes responsibility
256✔
314
                was_init
256✔
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) };
256✔
327
        let field_shape = field.shape();
256✔
328

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

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

344
    /// Prepares the current frame for re-initialization by dropping any existing
345
    /// value and unmarking it in the parent's iset.
346
    ///
347
    /// This should be called at the start of `begin_*` methods that support
348
    /// re-initialization (e.g., `begin_some`, `begin_inner`, `begin_smart_ptr`).
349
    ///
350
    /// Returns `true` if cleanup was performed (frame was previously initialized),
351
    /// `false` if the frame was not initialized.
352
    pub(crate) fn prepare_for_reinitialization(&mut self) -> bool {
115✔
353
        let frame = self.frames().last().unwrap();
115✔
354

355
        // Check if there's anything to reinitialize:
356
        // - For Scalar tracker: check is_init flag
357
        // - For Struct/Array/Enum trackers: these may have initialized fields even if is_init is false
358
        //   (is_init tracks the whole value, iset/data tracks individual fields)
359
        let needs_cleanup = match &frame.tracker {
115✔
360
            Tracker::Scalar => frame.is_init,
115✔
361
            // Non-Scalar trackers indicate fields were accessed, so deinit() will handle them
362
            Tracker::Struct { .. }
363
            | Tracker::Array { .. }
364
            | Tracker::Enum { .. }
365
            | Tracker::SmartPointer
366
            | Tracker::SmartPointerSlice { .. }
367
            | Tracker::List { .. }
368
            | Tracker::Map { .. }
369
            | Tracker::Set { .. }
370
            | Tracker::Option { .. }
371
            | Tracker::Result { .. }
UNCOV
372
            | Tracker::DynamicValue { .. } => true,
×
373
        };
374
        if !needs_cleanup {
115✔
375
            return false;
114✔
376
        }
1✔
377

378
        // Use deinit() to properly handle:
379
        // - Scalar frames: drops the whole value if is_init
380
        // - Struct frames: only drops fields marked in iset (avoiding double-free)
381
        // - Array frames: only drops elements marked in iset
382
        // - Enum frames: only drops fields marked in data
383
        // - Map/Set frames: also cleans up partial insert state (key/value buffers)
384
        let frame = self.frames_mut().last_mut().unwrap();
1✔
385
        frame.deinit();
1✔
386

387
        true
1✔
388
    }
115✔
389
}
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