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

facet-rs / facet / 20059345204

09 Dec 2025 09:57AM UTC coverage: 58.683% (-0.4%) from 59.082%
20059345204

push

github

fasterthanlime
Refactor VTable system: Direct/Indirect styles, OxRef/OxMut, builder patterns

Major architectural refactor of the facet vtable system for better code sharing
and reduced binary bloat.

- Remove ThinPtr/WidePtr in favor of PtrConst<'a>/PtrMut<'a>/PtrUninit<'a>
- Add OxRef<'a>/OxMut<'a> - shaped pointers bundling ptr + shape
- Add Ox<'a> enum for ownership tracking (like Cow for shaped pointers)

- VTableDirect: for concrete types, uses raw *const ()/*mut (), returns T directly
- VTableIndirect: for generic containers, uses OxRef/OxMut, returns Option<T>
- VTableErased enum wraps both styles
- Shape::call_* helpers dispatch to either style transparently

- vtable_direct! macro for sized types with compile-time known traits
- VTableIndirect::builder() for generic containers with runtime dispatch
- All container vtables (Array, Option, Result, List, Map, Set) use builders
- No more positional arguments - named builder methods only

- Hash trait is generic over H: Hasher, can't store directly in vtable
- HashProxy type-erases the hasher for vtable storage
- Enables hash support without wrapper function bloat

- impls_core/impls_alloc/impls_std -> impls/core/alloc/std/crates
- New internal/ module for facet's own types (Shape, Def, etc.)
- Cleaner separation of concerns

- Copy, Send, Sync, Eq, Unpin stored as bitflags on Shape
- Set via ShapeBuilder methods: .copy(), .send(), .sync(), .eq()

- ThinPtr -> *const () or PtrConst<'a>
- WidePtr -> OxRef<'a> or OxMut<'a>
- vtable_ref! -> vtable_direct! or VTableIndirect::builder()
- ValueVTable -> VTableDirect or VTableIndirect
- Closures in vtables -> named fn items

WIP: Some impl modules still need migration to new API.

4092 of 8007 new or added lines in 112 files covered. (51.11%)

117 existing lines in 26 files now uncovered.

26173 of 44601 relevant lines covered (58.68%)

635.02 hits per line

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

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

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Field selection
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl<const BORROW: bool> Partial<'_, BORROW> {
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> {
104✔
12
        let frame = self.frames().last()?;
104✔
13

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

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

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

55
                Ok(false)
14✔
56
            }
57
            Tracker::Option { building_inner } => {
×
58
                // For Options, index 0 represents the inner value
59
                if index == 0 {
×
60
                    Ok(!building_inner)
×
61
                } else {
62
                    Err(ReflectError::InvalidOperation {
×
63
                        operation: "is_field_set",
×
64
                        reason: "Option only has one field (index 0)",
×
65
                    })
×
66
                }
67
            }
68
            Tracker::Result { building_inner, .. } => {
×
69
                // For Results, index 0 represents the inner value (Ok or Err)
70
                if index == 0 {
×
71
                    Ok(!building_inner)
×
72
                } else {
73
                    Err(ReflectError::InvalidOperation {
×
74
                        operation: "is_field_set",
×
75
                        reason: "Result only has one field (index 0)",
×
76
                    })
×
77
                }
78
            }
79
            _ => Err(ReflectError::InvalidOperation {
×
80
                operation: "is_field_set",
×
81
                reason: "Current frame is not a struct, enum variant, option, or result",
×
82
            }),
×
83
        }
84
    }
1,065✔
85

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

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

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

126
            if let Some(name) = field_name
1,024✔
127
                && should_track
1,011✔
128
            {
129
                current_path.push(name);
938✔
130

131
                // Check if we have a stored frame for this path
132
                if let Some(stored_frame) = stored_frames.remove(current_path) {
938✔
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();
63✔
137
                    frame.tracker.set_current_child(idx);
63✔
138

139
                    stack.push(stored_frame);
63✔
140
                    return Ok(self);
63✔
141
                }
875✔
142
            }
86✔
143
        }
4,619✔
144

145
        let frame = self.frames_mut().last_mut().unwrap();
5,580✔
146

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

198
        self.frames_mut().push(next_frame);
5,579✔
199
        Ok(self)
5,579✔
200
    }
5,643✔
201

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

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

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

240
        let field = fields[idx];
90✔
241

242
        // Check for field-level default first, then type-level default
243
        if let Some(default_source) = field.default {
90✔
244
            self = self.begin_nth_field(idx)?;
62✔
245
            match default_source {
62✔
246
                facet_core::DefaultSource::Custom(field_default_fn) => {
10✔
247
                    // Custom default function provided via #[facet(default = expr)]
248
                    self = unsafe {
10✔
249
                        self.set_from_function(|ptr| {
10✔
250
                            field_default_fn(ptr);
10✔
251
                            Ok(())
10✔
252
                        })?
10✔
253
                    };
254
                }
255
                facet_core::DefaultSource::FromTrait => {
256
                    // Use the type's Default trait via #[facet(default)]
257
                    self = self.set_default()?;
52✔
258
                }
259
            }
260
            self.end()
62✔
261
        } else if field.shape().is(Characteristic::Default) {
28✔
262
            self = self.begin_nth_field(idx)?;
28✔
263
            self = self.set_default()?;
28✔
264
            self.end()
28✔
265
        } else {
266
            Err(ReflectError::DefaultAttrButNoDefaultImpl {
×
267
                shape: field.shape(),
×
268
            })
×
269
        }
270
    }
90✔
271
}
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