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

facet-rs / facet / 19774894729

28 Nov 2025 10:22PM UTC coverage: 59.711% (-0.6%) from 60.346%
19774894729

push

github

fasterthanlime
Add DynamicValue support for deserializing into facet_value::Value

This adds support for deserializing JSON (and potentially other formats)
into facet_value::Value without format crates needing to depend on facet-value.

Key changes:
- Add Def::DynamicValue variant with vtable for building dynamic values
- Implement Facet trait for Value in facet-value
- Extend Partial to handle DynamicValue scalars via set_into_dynamic_value
- Add deserialize_dynamic_value handler in facet-json

Currently supports scalar values (null, bool, numbers, strings).
Arrays and objects are stubbed out with TODO errors.

451 of 922 new or added lines in 20 files covered. (48.92%)

29 existing lines in 3 files now uncovered.

16657 of 27896 relevant lines covered (59.71%)

153.76 hits per line

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

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

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Lists
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl Partial<'_> {
7
    /// Initializes a list (Vec, etc.) if it hasn't been initialized before.
8
    /// This is a prerequisite to `begin_push_item`/`set`/`end` or the shorthand
9
    /// `push`.
10
    ///
11
    /// `begin_list` does not clear the list if it was previously initialized.
12
    /// `begin_list` does not push a new frame to the stack, and thus does not
13
    /// require `end` to be called afterwards.
14
    pub fn begin_list(&mut self) -> Result<&mut Self, ReflectError> {
194✔
15
        crate::trace!("begin_list()");
16
        self.require_active()?;
194✔
17
        let frame = self.frames_mut().last_mut().unwrap();
194✔
18

19
        match &frame.tracker {
178✔
20
            Tracker::Scalar if !frame.is_init => {
171✔
21
                // that's good, let's initialize it
171✔
22
            }
171✔
23
            Tracker::Scalar => {
24
                // is_init is true - initialized (perhaps from a previous round?) but should be a list tracker
25
                // First verify this is actually a list type before changing tracker
26
                if !matches!(frame.shape.def, Def::List(_)) {
7✔
27
                    return Err(ReflectError::OperationFailed {
×
28
                        shape: frame.shape,
×
29
                        operation: "begin_list can only be called on List types",
×
30
                    });
×
31
                }
7✔
32
                frame.tracker = Tracker::List {
7✔
33
                    current_child: false,
7✔
34
                };
7✔
35
                return Ok(self);
7✔
36
            }
37
            Tracker::List { .. } => {
38
                if frame.is_init {
7✔
39
                    // already initialized, nothing to do
40
                    return Ok(self);
7✔
41
                }
×
42
            }
43
            Tracker::DynamicValue { state } => {
3✔
44
                // Already initialized as a dynamic array
45
                if matches!(state, DynamicValueState::Array { .. }) {
3✔
46
                    return Ok(self);
3✔
NEW
47
                }
×
48
                // Otherwise (Scalar or other state), we need to deinit before reinitializing
NEW
49
                frame.deinit();
×
50
            }
51
            Tracker::SmartPointerSlice { .. } => {
52
                // begin_list is kinda superfluous when we're in a SmartPointerSlice state
53
                return Ok(self);
6✔
54
            }
55
            _ => {
56
                return Err(ReflectError::UnexpectedTracker {
×
57
                    message: "begin_list called but tracker isn't something list-like",
×
58
                    current_tracker: frame.tracker.kind(),
×
59
                });
×
60
            }
61
        };
62

63
        // Check that we have a List or DynamicValue
64
        match &frame.shape.def {
171✔
65
            Def::List(list_def) => {
154✔
66
                // Check that we have init_in_place_with_capacity function
67
                let init_fn = match list_def.vtable.init_in_place_with_capacity {
154✔
68
                    Some(f) => f,
154✔
69
                    None => {
NEW
70
                        return Err(ReflectError::OperationFailed {
×
NEW
71
                            shape: frame.shape,
×
NEW
72
                            operation: "list type does not support initialization with capacity",
×
NEW
73
                        });
×
74
                    }
75
                };
76

77
                // Initialize the list with default capacity (0)
78
                unsafe {
154✔
79
                    init_fn(frame.data, 0);
154✔
80
                }
154✔
81

82
                // Update tracker to List state and mark as initialized
83
                frame.tracker = Tracker::List {
154✔
84
                    current_child: false,
154✔
85
                };
154✔
86
                frame.is_init = true;
154✔
87
            }
88
            Def::DynamicValue(dyn_def) => {
14✔
89
                // Initialize as a dynamic array
14✔
90
                unsafe {
14✔
91
                    (dyn_def.vtable.begin_array)(frame.data);
14✔
92
                }
14✔
93

14✔
94
                // Update tracker to DynamicValue array state and mark as initialized
14✔
95
                frame.tracker = Tracker::DynamicValue {
14✔
96
                    state: DynamicValueState::Array {
14✔
97
                        building_element: false,
14✔
98
                    },
14✔
99
                };
14✔
100
                frame.is_init = true;
14✔
101
            }
14✔
102
            _ => {
103
                return Err(ReflectError::OperationFailed {
3✔
104
                    shape: frame.shape,
3✔
105
                    operation: "begin_list can only be called on List or DynamicValue types",
3✔
106
                });
3✔
107
            }
108
        }
109

110
        Ok(self)
168✔
111
    }
194✔
112

113
    /// Pushes an element to the list
114
    /// The element should be set using `set()` or similar methods, then `pop()` to complete
115
    pub fn begin_list_item(&mut self) -> Result<&mut Self, ReflectError> {
690✔
116
        crate::trace!("begin_list_item()");
117
        self.require_active()?;
690✔
118
        let frame = self.frames_mut().last_mut().unwrap();
690✔
119

120
        // Check if we're building a smart pointer slice
121
        if let Tracker::SmartPointerSlice {
122
            building_item,
33✔
123
            vtable: _,
124
        } = &frame.tracker
690✔
125
        {
126
            if *building_item {
33✔
127
                return Err(ReflectError::OperationFailed {
×
128
                    shape: frame.shape,
×
129
                    operation: "already building an item, call end() first",
×
130
                });
×
131
            }
33✔
132

133
            // Get the element type from the smart pointer's pointee
134
            let element_shape = match &frame.shape.def {
33✔
135
                Def::Pointer(smart_ptr_def) => match smart_ptr_def.pointee() {
33✔
136
                    Some(pointee_shape) => match &pointee_shape.ty {
33✔
137
                        Type::Sequence(SequenceType::Slice(slice_type)) => slice_type.t,
33✔
138
                        _ => {
139
                            return Err(ReflectError::OperationFailed {
×
140
                                shape: frame.shape,
×
141
                                operation: "smart pointer pointee is not a slice",
×
142
                            });
×
143
                        }
144
                    },
145
                    None => {
146
                        return Err(ReflectError::OperationFailed {
×
147
                            shape: frame.shape,
×
148
                            operation: "smart pointer has no pointee",
×
149
                        });
×
150
                    }
151
                },
152
                _ => {
153
                    return Err(ReflectError::OperationFailed {
×
154
                        shape: frame.shape,
×
155
                        operation: "expected smart pointer definition",
×
156
                    });
×
157
                }
158
            };
159

160
            // Allocate space for the element
161
            crate::trace!("Pointee is a slice of {element_shape}");
162
            let element_layout = match element_shape.layout.sized_layout() {
33✔
163
                Ok(layout) => layout,
33✔
164
                Err(_) => {
165
                    return Err(ReflectError::OperationFailed {
×
166
                        shape: element_shape,
×
167
                        operation: "cannot allocate unsized element",
×
168
                    });
×
169
                }
170
            };
171

172
            let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
33✔
173
            let Some(element_ptr) = NonNull::new(element_ptr) else {
33✔
174
                return Err(ReflectError::OperationFailed {
×
175
                    shape: frame.shape,
×
176
                    operation: "failed to allocate memory for list element",
×
177
                });
×
178
            };
179

180
            // Create and push the element frame
181
            crate::trace!("Pushing element frame, which we just allocated");
182
            let element_frame = Frame::new(
33✔
183
                PtrUninit::new(element_ptr),
33✔
184
                element_shape,
33✔
185
                FrameOwnership::Owned,
33✔
186
            );
187
            self.frames_mut().push(element_frame);
33✔
188

189
            // Mark that we're building an item
190
            // We need to update the tracker after pushing the frame
191
            let parent_idx = self.frames().len() - 2;
33✔
192
            if let Tracker::SmartPointerSlice { building_item, .. } =
33✔
193
                &mut self.frames_mut()[parent_idx].tracker
33✔
194
            {
33✔
195
                crate::trace!("Marking element frame as building item");
33✔
196
                *building_item = true;
33✔
197
            }
33✔
198

199
            return Ok(self);
33✔
200
        }
657✔
201

202
        // Check if we're building a DynamicValue array
203
        if let Tracker::DynamicValue {
204
            state: DynamicValueState::Array { building_element },
21✔
205
        } = &frame.tracker
21✔
206
        {
207
            if *building_element {
21✔
NEW
208
                return Err(ReflectError::OperationFailed {
×
NEW
209
                    shape: frame.shape,
×
NEW
210
                    operation: "already building an element, call end() first",
×
NEW
211
                });
×
212
            }
21✔
213

214
            // For DynamicValue arrays, the element shape is the same DynamicValue shape
215
            // (Value arrays contain Value elements)
216
            let element_shape = frame.shape;
21✔
217
            let element_layout = match element_shape.layout.sized_layout() {
21✔
218
                Ok(layout) => layout,
21✔
219
                Err(_) => {
NEW
220
                    return Err(ReflectError::Unsized {
×
NEW
221
                        shape: element_shape,
×
NEW
222
                        operation: "begin_list_item: calculating element layout",
×
NEW
223
                    });
×
224
                }
225
            };
226

227
            let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
21✔
228
            let Some(element_ptr) = NonNull::new(element_ptr) else {
21✔
NEW
229
                return Err(ReflectError::OperationFailed {
×
NEW
230
                    shape: frame.shape,
×
NEW
231
                    operation: "failed to allocate memory for list element",
×
NEW
232
                });
×
233
            };
234

235
            // Push a new frame for the element
236
            self.frames_mut().push(Frame::new(
21✔
237
                PtrUninit::new(element_ptr),
21✔
238
                element_shape,
21✔
239
                FrameOwnership::Owned,
21✔
240
            ));
241

242
            // Mark that we're building an element
243
            let parent_idx = self.frames().len() - 2;
21✔
244
            if let Tracker::DynamicValue {
245
                state: DynamicValueState::Array { building_element },
21✔
246
            } = &mut self.frames_mut()[parent_idx].tracker
21✔
247
            {
21✔
248
                *building_element = true;
21✔
249
            }
21✔
250

251
            return Ok(self);
21✔
252
        }
636✔
253

254
        // Check that we have a List that's been initialized
255
        let list_def = match &frame.shape.def {
636✔
256
            Def::List(list_def) => list_def,
635✔
257
            _ => {
258
                return Err(ReflectError::OperationFailed {
1✔
259
                    shape: frame.shape,
1✔
260
                    operation: "push can only be called on List or DynamicValue types",
1✔
261
                });
1✔
262
            }
263
        };
264

265
        // Verify the tracker is in List state and initialized
266
        match &mut frame.tracker {
635✔
267
            Tracker::List { current_child } if frame.is_init => {
635✔
268
                if *current_child {
635✔
269
                    return Err(ReflectError::OperationFailed {
×
270
                        shape: frame.shape,
×
271
                        operation: "already pushing an element, call pop() first",
×
272
                    });
×
273
                }
635✔
274
                *current_child = true;
635✔
275
            }
276
            _ => {
277
                return Err(ReflectError::OperationFailed {
×
278
                    shape: frame.shape,
×
279
                    operation: "must call begin_list() before push()",
×
280
                });
×
281
            }
282
        }
283

284
        // Get the element shape
285
        let element_shape = list_def.t();
635✔
286

287
        // Allocate space for the new element
288
        let element_layout = match element_shape.layout.sized_layout() {
635✔
289
            Ok(layout) => layout,
635✔
290
            Err(_) => {
291
                return Err(ReflectError::Unsized {
×
292
                    shape: element_shape,
×
293
                    operation: "begin_list_item: calculating element layout",
×
294
                });
×
295
            }
296
        };
297
        let element_ptr: *mut u8 = unsafe { ::alloc::alloc::alloc(element_layout) };
635✔
298

299
        let Some(element_ptr) = NonNull::new(element_ptr) else {
635✔
300
            return Err(ReflectError::OperationFailed {
×
301
                shape: frame.shape,
×
302
                operation: "failed to allocate memory for list element",
×
303
            });
×
304
        };
305

306
        // Push a new frame for the element
307
        self.frames_mut().push(Frame::new(
635✔
308
            PtrUninit::new(element_ptr),
635✔
309
            element_shape,
635✔
310
            FrameOwnership::Owned,
635✔
311
        ));
312

313
        Ok(self)
635✔
314
    }
690✔
315
}
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