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

facet-rs / facet / 19871315706

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

push

github

fasterthanlime
Add Facet implementation for Result<T, E>

This adds support for the Result<T, E> type in facet, mirroring the
existing Option<T> implementation.

Changes:
- facet-core: Add ResultDef and ResultVTable in types/def/result.rs
- facet-core: Add Def::Result variant to the Def enum
- facet-core: Implement Facet trait for Result<T, E> with Debug, PartialEq,
  PartialOrd, Ord, and Hash support
- facet-reflect: Add PeekResult for reading Result values
- facet-reflect: Add Partial API support (begin_ok, begin_err) for building
  Result values
- facet-reflect: Add TrackerKind::Result and Tracker::Result for tracking
  Result initialization state

Closes #990

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.41 hits per line

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

61.7
/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> {
97✔
12
        let frame = self.frames().last()?;
97✔
13

14
        match frame.shape.ty {
97✔
15
            Type::User(UserType::Struct(struct_def)) => {
94✔
16
                struct_def.fields.iter().position(|f| f.name == field_name)
146✔
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
    }
97✔
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> {
633✔
36
        let frame = self.frames().last().ok_or(ReflectError::NoActiveFrame)?;
633✔
37

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

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

56
                Ok(false)
13✔
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
            }
NEW
69
            Tracker::Result { building_inner, .. } => {
×
70
                // For Results, index 0 represents the inner value (Ok or Err)
NEW
71
                if index == 0 {
×
NEW
72
                    Ok(!building_inner)
×
73
                } else {
NEW
74
                    Err(ReflectError::InvalidOperation {
×
NEW
75
                        operation: "is_field_set",
×
NEW
76
                        reason: "Result only has one field (index 0)",
×
NEW
77
                    })
×
78
                }
79
            }
80
            _ => Err(ReflectError::InvalidOperation {
×
81
                operation: "is_field_set",
×
NEW
82
                reason: "Current frame is not a struct, enum variant, option, or result",
×
83
            }),
×
84
        }
85
    }
633✔
86

87
    /// Selects a field (by name) of a struct or enum data.
88
    ///
89
    /// For enums, the variant needs to be selected first, see [Self::select_nth_variant]
90
    /// and friends.
91
    pub fn begin_field(self, field_name: &str) -> Result<Self, ReflectError> {
1,945✔
92
        let frame = self.frames().last().unwrap();
1,945✔
93
        let fields = self.get_fields()?;
1,945✔
94
        let Some(idx) = fields.iter().position(|f| f.name == field_name) else {
3,199✔
95
            return Err(ReflectError::FieldError {
8✔
96
                shape: frame.shape,
8✔
97
                field_error: facet_core::FieldError::NoSuchField,
8✔
98
            });
8✔
99
        };
100
        self.begin_nth_field(idx)
1,933✔
101
    }
1,945✔
102

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

113
        // Update current_path in deferred mode
114
        if let FrameMode::Deferred {
115
            stack,
1,012✔
116
            start_depth,
1,012✔
117
            current_path,
1,012✔
118
            stored_frames,
1,012✔
119
            ..
120
        } = &mut self.mode
3,031✔
121
        {
122
            // Only track path if we're at the expected navigable depth
123
            // Path should have (frames.len() - start_depth) entries before we add this field
124
            let relative_depth = stack.len() - *start_depth;
1,012✔
125
            let should_track = current_path.len() == relative_depth;
1,012✔
126

127
            if let Some(name) = field_name {
1,012✔
128
                if should_track {
999✔
129
                    current_path.push(name);
905✔
130

131
                    // Check if we have a stored frame for this path
132
                    if let Some(stored_frame) = stored_frames.remove(current_path) {
905✔
133
                        trace!("begin_nth_field: Restoring stored frame for path {current_path:?}");
134

135
                        // Update parent's current_child tracking
136
                        let frame = stack.last_mut().unwrap();
61✔
137
                        frame.tracker.set_current_child(idx);
61✔
138

139
                        stack.push(stored_frame);
61✔
140
                        return Ok(self);
61✔
141
                    }
844✔
142
                }
94✔
143
            }
13✔
144
        }
2,019✔
145

146
        let frame = self.frames_mut().last_mut().unwrap();
2,970✔
147

148
        let next_frame = match frame.shape.ty {
2,970✔
149
            Type::User(user_type) => match user_type {
2,824✔
150
                UserType::Struct(struct_type) => {
2,568✔
151
                    Self::begin_nth_struct_field(frame, struct_type, idx)?
2,568✔
152
                }
153
                UserType::Enum(_) => {
154
                    // Check if we have a variant selected
155
                    match &frame.tracker {
256✔
156
                        Tracker::Enum { variant, .. } => {
256✔
157
                            Self::begin_nth_enum_field(frame, variant, idx)?
256✔
158
                        }
159
                        _ => {
160
                            return Err(ReflectError::OperationFailed {
×
161
                                shape: frame.shape,
×
162
                                operation: "must call select_variant before selecting enum fields",
×
163
                            });
×
164
                        }
165
                    }
166
                }
167
                UserType::Union(_) => {
168
                    return Err(ReflectError::OperationFailed {
×
169
                        shape: frame.shape,
×
170
                        operation: "cannot select a field from a union",
×
171
                    });
×
172
                }
173
                UserType::Opaque => {
174
                    return Err(ReflectError::OperationFailed {
×
175
                        shape: frame.shape,
×
176
                        operation: "cannot select a field from an opaque type",
×
177
                    });
×
178
                }
179
            },
180
            Type::Sequence(sequence_type) => match sequence_type {
146✔
181
                SequenceType::Array(array_type) => {
146✔
182
                    Self::begin_nth_array_element(frame, array_type, idx)?
146✔
183
                }
184
                SequenceType::Slice(_) => {
185
                    return Err(ReflectError::OperationFailed {
×
186
                        shape: frame.shape,
×
187
                        operation: "cannot select a field from slices yet",
×
188
                    });
×
189
                }
190
            },
191
            _ => {
192
                return Err(ReflectError::OperationFailed {
×
193
                    shape: frame.shape,
×
194
                    operation: "cannot select a field from this type",
×
195
                });
×
196
            }
197
        };
198

199
        self.frames_mut().push(next_frame);
2,969✔
200
        Ok(self)
2,969✔
201
    }
3,031✔
202

203
    /// Get the field name for path tracking (used in deferred mode)
204
    fn get_field_name_for_path(&self, idx: usize) -> Option<&'static str> {
3,031✔
205
        let frame = self.frames().last()?;
3,031✔
206
        match frame.shape.ty {
2,885✔
207
            Type::User(UserType::Struct(struct_type)) => {
2,629✔
208
                struct_type.fields.get(idx).map(|f| f.name)
2,629✔
209
            }
210
            Type::User(UserType::Enum(_)) => {
211
                if let Tracker::Enum { variant, .. } = &frame.tracker {
256✔
212
                    variant.data.fields.get(idx).map(|f| f.name)
256✔
213
                } else {
214
                    None
×
215
                }
216
            }
217
            // For arrays, we could use index as string, but for now return None
218
            _ => None,
146✔
219
        }
220
    }
3,031✔
221

222
    /// Sets the given field to its default value, preferring:
223
    ///
224
    ///   * A `default = some_fn()` function
225
    ///   * The field's `Default` implementation if any
226
    ///
227
    /// But without going all the way up to the parent struct's `Default` impl.
228
    ///
229
    /// Errors out if idx is out of bound, if the field has no default method or Default impl.
230
    pub fn set_nth_field_to_default(mut self, idx: usize) -> Result<Self, ReflectError> {
33✔
231
        let frame = self.frames().last().unwrap();
33✔
232
        let fields = self.get_fields()?;
33✔
233

234
        if idx >= fields.len() {
33✔
235
            return Err(ReflectError::OperationFailed {
×
236
                shape: frame.shape,
×
237
                operation: "field index out of bounds",
×
238
            });
×
239
        }
33✔
240

241
        let field = fields[idx];
33✔
242

243
        // Check for field-level default function first, then type-level default
244
        if let Some(field_default_fn) = field.default_fn() {
33✔
245
            self = self.begin_nth_field(idx)?;
8✔
246
            // the field default fn should be well-behaved
247
            self = unsafe {
8✔
248
                self.set_from_function(|ptr| {
8✔
249
                    field_default_fn(ptr);
8✔
250
                    Ok(())
8✔
251
                })?
8✔
252
            };
253
            self.end()
8✔
254
        } else if field.shape().is(Characteristic::Default) {
25✔
255
            self = self.begin_nth_field(idx)?;
25✔
256
            self = self.set_default()?;
25✔
257
            self.end()
25✔
258
        } else {
259
            Err(ReflectError::DefaultAttrButNoDefaultImpl {
×
260
                shape: field.shape(),
×
261
            })
×
262
        }
263
    }
33✔
264

265
    /// Given a `Partial` for the same shape, and assuming that partial has the nth
266
    /// field initialized, move the value from `src` to `self`, marking it as deinitialized
267
    /// in `src`.
268
    pub fn steal_nth_field(
2✔
269
        mut self,
2✔
270
        src: &mut Partial,
2✔
271
        field_index: usize,
2✔
272
    ) -> Result<Self, ReflectError> {
2✔
273
        let dst_shape = self.shape();
2✔
274
        let src_shape = src.shape();
2✔
275
        if dst_shape != src_shape {
2✔
276
            return Err(ReflectError::HeistCancelledDifferentShapes {
×
277
                src_shape,
×
278
                dst_shape,
×
279
            });
×
280
        }
2✔
281

282
        // FIXME: what about enums? we don't check that the right variant is
283
        // selected here.
284
        if !src.is_field_set(field_index)? {
2✔
285
            return Err(ReflectError::InvariantViolation {
×
286
                invariant: "stolen field must be initialized",
×
287
            });
×
288
        }
2✔
289

290
        let maybe_fields = match src_shape.ty {
2✔
291
            Type::Primitive(_primitive_type) => None,
×
292
            Type::Sequence(_sequence_type) => None,
×
293
            Type::User(user_type) => match user_type {
2✔
294
                UserType::Struct(struct_type) => Some(struct_type.fields),
2✔
295
                UserType::Enum(_enum_type) => match self.selected_variant() {
×
296
                    Some(variant) => Some(variant.data.fields),
×
297
                    None => {
298
                        return Err(ReflectError::InvariantViolation {
×
299
                            invariant: "enum field thief must have variant selected",
×
300
                        });
×
301
                    }
302
                },
303
                UserType::Union(_union_type) => None,
×
304
                UserType::Opaque => None,
×
305
            },
306
            Type::Pointer(_pointer_type) => None,
×
307
        };
308

309
        let Some(fields) = maybe_fields else {
2✔
310
            return Err(ReflectError::OperationFailed {
×
311
                shape: src_shape,
×
312
                operation: "fetching field list for steal_nth_field",
×
313
            });
×
314
        };
315

316
        if field_index >= fields.len() {
2✔
317
            return Err(ReflectError::OperationFailed {
×
318
                shape: src_shape,
×
319
                operation: "field index out of bounds",
×
320
            });
×
321
        }
2✔
322
        let field = fields[field_index];
2✔
323

324
        let src_frame = src.frames_mut().last_mut().unwrap();
2✔
325

326
        self = self.begin_nth_field(field_index)?;
2✔
327
        self = unsafe {
2✔
328
            self.set_from_function(|dst_field_ptr| {
2✔
329
                let src_field_ptr = src_frame.data.field_init_at(field.offset).as_const();
2✔
330
                dst_field_ptr
2✔
331
                    .copy_from(src_field_ptr, field.shape())
2✔
332
                    .unwrap();
2✔
333
                Ok(())
2✔
334
            })?
2✔
335
        };
336
        self = self.end()?;
2✔
337

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

392
        Ok(self)
2✔
393
    }
2✔
394
}
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