• 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

69.59
/facet-reflect/src/partial/partial_api/set.rs
1
use super::*;
2
use facet_core::{Def, NumericType, PrimitiveType, Type};
3

4
////////////////////////////////////////////////////////////////////////////////////////////////////
5
// `Set` and set helpers
6
////////////////////////////////////////////////////////////////////////////////////////////////////
7
impl<'facet> Partial<'facet> {
8
    /// Sets a value wholesale into the current frame.
9
    ///
10
    /// If the current frame was already initialized, the previous value is
11
    /// dropped. If it was partially initialized, the fields that were initialized
12
    /// are dropped, etc.
13
    pub fn set<U>(&mut self, value: U) -> Result<&mut Self, ReflectError>
2,057✔
14
    where
2,057✔
15
        U: Facet<'facet>,
2,057✔
16
    {
17
        self.require_active()?;
2,057✔
18
        struct DropVal<U> {
19
            ptr: *mut U,
20
        }
21
        impl<U> Drop for DropVal<U> {
22
            #[inline]
23
            fn drop(&mut self) {
4✔
24
                unsafe { core::ptr::drop_in_place(self.ptr) };
4✔
25
            }
4✔
26
        }
27

28
        let mut value = ManuallyDrop::new(value);
2,057✔
29
        let drop = DropVal {
2,057✔
30
            ptr: (&mut value) as *mut ManuallyDrop<U> as *mut U,
2,057✔
31
        };
2,057✔
32

33
        let ptr_const = PtrConst::new(unsafe { NonNull::new_unchecked(drop.ptr) });
2,057✔
34
        unsafe {
35
            // Safety: We are calling set_shape with a valid shape and a valid pointer
36
            self.set_shape(ptr_const, U::SHAPE)?
2,057✔
37
        };
38
        core::mem::forget(drop);
2,053✔
39

40
        Ok(self)
2,053✔
41
    }
2,057✔
42

43
    /// Sets a value into the current frame by [PtrConst] / [Shape].
44
    ///
45
    /// # Safety
46
    ///
47
    /// The caller must ensure that `src_value` points to a valid instance of a value
48
    /// whose memory layout and type matches `src_shape`, and that this value can be
49
    /// safely copied (bitwise) into the destination specified by the Partial's current frame.
50
    ///
51
    /// After a successful call, the ownership of the value at `src_value` is effectively moved
52
    /// into the Partial (i.e., the destination), and the original value should not be used
53
    /// or dropped by the caller; you should use `core::mem::forget` on the passed value.
54
    ///
55
    /// If an error is returned, the destination remains unmodified and safe for future operations.
56
    #[inline]
57
    pub unsafe fn set_shape(
2,057✔
58
        &mut self,
2,057✔
59
        src_value: PtrConst<'_>,
2,057✔
60
        src_shape: &'static Shape,
2,057✔
61
    ) -> Result<&mut Self, ReflectError> {
2,057✔
62
        self.require_active()?;
2,057✔
63

64
        let fr = self.frames_mut().last_mut().unwrap();
2,057✔
65
        crate::trace!("set_shape({src_shape:?})");
66

67
        // Check if target is a DynamicValue - if so, convert the source value
68
        if let Def::DynamicValue(dyn_def) = &fr.shape.def {
2,057✔
69
            return unsafe { self.set_into_dynamic_value(src_value, src_shape, dyn_def) };
24✔
70
        }
2,033✔
71

72
        if !fr.shape.is_shape(src_shape) {
2,033✔
73
            return Err(ReflectError::WrongShape {
4✔
74
                expected: fr.shape,
4✔
75
                actual: src_shape,
4✔
76
            });
4✔
77
        }
2,029✔
78

79
        fr.deinit();
2,029✔
80

81
        // SAFETY: `fr.shape` and `src_shape` are the same, so they have the same size,
82
        // and the preconditions for this function are that `src_value` is fully intialized.
83
        unsafe {
2,029✔
84
            // unwrap safety: the only failure condition for copy_from is that shape is unsized,
2,029✔
85
            // which is not possible for `Partial`
2,029✔
86
            fr.data.copy_from(src_value, fr.shape).unwrap();
2,029✔
87
        }
2,029✔
88

89
        // SAFETY: if we reached this point, `fr.data` is correctly initialized
90
        unsafe {
2,029✔
91
            fr.mark_as_init();
2,029✔
92
        }
2,029✔
93

94
        Ok(self)
2,029✔
95
    }
2,057✔
96

97
    /// Sets a value into a DynamicValue target by converting the source value.
98
    ///
99
    /// # Safety
100
    ///
101
    /// Same safety requirements as `set_shape`.
102
    unsafe fn set_into_dynamic_value(
24✔
103
        &mut self,
24✔
104
        src_value: PtrConst<'_>,
24✔
105
        src_shape: &'static Shape,
24✔
106
        dyn_def: &facet_core::DynamicValueDef,
24✔
107
    ) -> Result<&mut Self, ReflectError> {
24✔
108
        let fr = self.frames_mut().last_mut().unwrap();
24✔
109
        let vtable = dyn_def.vtable;
24✔
110

111
        fr.deinit();
24✔
112

113
        // If source shape is also the same DynamicValue shape, just copy it
114
        if fr.shape.is_shape(src_shape) {
24✔
NEW
115
            unsafe {
×
NEW
116
                fr.data.copy_from(src_value, fr.shape).unwrap();
×
NEW
117
                fr.mark_as_init();
×
NEW
118
            }
×
NEW
119
            return Ok(self);
×
120
        }
24✔
121

122
        // Get the size in bits for numeric conversions
123
        let size_bits = src_shape
24✔
124
            .layout
24✔
125
            .sized_layout()
24✔
126
            .map(|l| l.size() * 8)
24✔
127
            .unwrap_or(0);
24✔
128

129
        // Convert based on source shape's type
130
        match &src_shape.ty {
12✔
131
            Type::Primitive(PrimitiveType::Boolean) => {
3✔
132
                let val = unsafe { *(src_value.as_byte_ptr() as *const bool) };
3✔
133
                unsafe { (vtable.set_bool)(fr.data, val) };
3✔
134
            }
3✔
135
            Type::Primitive(PrimitiveType::Numeric(NumericType::Float)) => {
136
                if size_bits == 64 {
1✔
137
                    let val = unsafe { *(src_value.as_byte_ptr() as *const f64) };
1✔
138
                    let success = unsafe { (vtable.set_f64)(fr.data, val) };
1✔
139
                    if !success {
1✔
NEW
140
                        return Err(ReflectError::OperationFailed {
×
NEW
141
                            shape: src_shape,
×
NEW
142
                            operation: "f64 value (NaN/Infinity) not representable in dynamic value",
×
NEW
143
                        });
×
144
                    }
1✔
NEW
145
                } else if size_bits == 32 {
×
NEW
146
                    let val = unsafe { *(src_value.as_byte_ptr() as *const f32) } as f64;
×
NEW
147
                    let success = unsafe { (vtable.set_f64)(fr.data, val) };
×
NEW
148
                    if !success {
×
NEW
149
                        return Err(ReflectError::OperationFailed {
×
NEW
150
                            shape: src_shape,
×
NEW
151
                            operation: "f32 value (NaN/Infinity) not representable in dynamic value",
×
NEW
152
                        });
×
NEW
153
                    }
×
154
                } else {
NEW
155
                    return Err(ReflectError::OperationFailed {
×
NEW
156
                        shape: src_shape,
×
NEW
157
                        operation: "unsupported float size for dynamic value",
×
NEW
158
                    });
×
159
                }
160
            }
161
            Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: true })) => {
162
                let val: i64 = match size_bits {
11✔
NEW
163
                    8 => (unsafe { *(src_value.as_byte_ptr() as *const i8) }) as i64,
×
NEW
164
                    16 => (unsafe { *(src_value.as_byte_ptr() as *const i16) }) as i64,
×
165
                    32 => (unsafe { *(src_value.as_byte_ptr() as *const i32) }) as i64,
1✔
166
                    64 => unsafe { *(src_value.as_byte_ptr() as *const i64) },
10✔
167
                    _ => {
NEW
168
                        return Err(ReflectError::OperationFailed {
×
NEW
169
                            shape: src_shape,
×
NEW
170
                            operation: "unsupported signed integer size for dynamic value",
×
NEW
171
                        });
×
172
                    }
173
                };
174
                unsafe { (vtable.set_i64)(fr.data, val) };
11✔
175
            }
176
            Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: false })) => {
NEW
177
                let val: u64 = match size_bits {
×
NEW
178
                    8 => (unsafe { *src_value.as_byte_ptr() }) as u64,
×
NEW
179
                    16 => (unsafe { *(src_value.as_byte_ptr() as *const u16) }) as u64,
×
NEW
180
                    32 => (unsafe { *(src_value.as_byte_ptr() as *const u32) }) as u64,
×
NEW
181
                    64 => unsafe { *(src_value.as_byte_ptr() as *const u64) },
×
182
                    _ => {
NEW
183
                        return Err(ReflectError::OperationFailed {
×
NEW
184
                            shape: src_shape,
×
NEW
185
                            operation: "unsupported unsigned integer size for dynamic value",
×
NEW
186
                        });
×
187
                    }
188
                };
NEW
189
                unsafe { (vtable.set_u64)(fr.data, val) };
×
190
            }
191
            Type::Primitive(PrimitiveType::Textual(_)) => {
192
                // char or str - for char, convert to string
NEW
193
                if src_shape.type_identifier == "char" {
×
NEW
194
                    let c = unsafe { *(src_value.as_byte_ptr() as *const char) };
×
NEW
195
                    let mut buf = [0u8; 4];
×
NEW
196
                    let s = c.encode_utf8(&mut buf);
×
NEW
197
                    unsafe { (vtable.set_str)(fr.data, s) };
×
NEW
198
                } else {
×
NEW
199
                    // &str
×
NEW
200
                    let s: &str = unsafe { *(src_value.as_byte_ptr() as *const &str) };
×
NEW
201
                    unsafe { (vtable.set_str)(fr.data, s) };
×
NEW
202
                }
×
203
            }
204
            _ => {
205
                // Handle String type (not a primitive but common)
206
                if src_shape.type_identifier == "String" {
9✔
207
                    let s: &::alloc::string::String =
9✔
208
                        unsafe { &*(src_value.as_byte_ptr() as *const ::alloc::string::String) };
9✔
209
                    unsafe { (vtable.set_str)(fr.data, s.as_str()) };
9✔
210
                    // Drop the source String since we cloned its content
211
                    if let Some(drop_fn) = src_shape.vtable.drop_in_place {
9✔
212
                        unsafe {
9✔
213
                            drop_fn(PtrMut::new(NonNull::new_unchecked(
9✔
214
                                src_value.as_byte_ptr() as *mut u8
9✔
215
                            )));
9✔
216
                        }
9✔
NEW
217
                    }
×
218
                } else {
NEW
219
                    return Err(ReflectError::OperationFailed {
×
NEW
220
                        shape: src_shape,
×
NEW
221
                        operation: "cannot convert this type to dynamic value",
×
NEW
222
                    });
×
223
                }
224
            }
225
        }
226

227
        fr.tracker = Tracker::DynamicValue {
24✔
228
            state: DynamicValueState::Scalar,
24✔
229
        };
24✔
230
        unsafe { fr.mark_as_init() };
24✔
231
        Ok(self)
24✔
232
    }
24✔
233

234
    /// Sets the current frame using a function that initializes the value
235
    ///
236
    /// # Safety
237
    ///
238
    /// If `f` returns Ok(), it is assumed that it initialized the passed pointer fully and with a
239
    /// value of the right type.
240
    ///
241
    /// If `f` returns Err(), it is assumed that it did NOT initialize the passed pointer and that
242
    /// there is no need to drop it in place.
243
    pub unsafe fn set_from_function<F>(&mut self, f: F) -> Result<&mut Self, ReflectError>
62✔
244
    where
62✔
245
        F: FnOnce(PtrUninit<'_>) -> Result<(), ReflectError>,
62✔
246
    {
247
        self.require_active()?;
62✔
248
        let frame = self.frames_mut().last_mut().unwrap();
62✔
249

250
        frame.deinit();
62✔
251
        f(frame.data)?;
62✔
252

253
        // safety: `f()` returned Ok, so `frame.data` must be initialized
254
        unsafe {
62✔
255
            frame.mark_as_init();
62✔
256
        }
62✔
257

258
        Ok(self)
62✔
259
    }
62✔
260

261
    /// Sets the current frame to its default value using `default_in_place` from the
262
    /// vtable.
263
    ///
264
    /// Note: if you have `struct S { field: F }`, and `F` does not implement `Default`
265
    /// but `S` does, this doesn't magically uses S's `Default` implementation to get a value
266
    /// for `field`.
267
    ///
268
    /// If the current frame's shape does not implement `Default`, then this returns an error.
269
    #[inline]
270
    pub fn set_default(&mut self) -> Result<&mut Self, ReflectError> {
53✔
271
        self.require_active()?;
53✔
272
        let frame = self.frames().last().unwrap();
53✔
273

274
        let Some(default_fn) = frame.shape.vtable.default_in_place else {
53✔
275
            return Err(ReflectError::OperationFailed {
1✔
276
                shape: frame.shape,
1✔
277
                operation: "type does not implement Default",
1✔
278
            });
1✔
279
        };
280

281
        // SAFETY: `default_fn` fully initializes the passed pointer. we took it
282
        // from the vtable of `frame.shape`.
283
        unsafe {
284
            self.set_from_function(move |ptr| {
52✔
285
                default_fn(ptr);
52✔
286
                Ok(())
52✔
287
            })
52✔
288
        }
289
    }
53✔
290

291
    /// Copy a value from a Peek into the current frame.
292
    ///
293
    /// # Invariants
294
    ///
295
    /// `peek` must be a thin pointer, otherwise this panics.
296
    ///
297
    /// # Safety
298
    ///
299
    /// If this succeeds, the value `Peek` points to has been moved out of, and
300
    /// as such, should not be dropped (but should be deallocated).
301
    pub unsafe fn set_from_peek(&mut self, peek: &Peek<'_, '_>) -> Result<&mut Self, ReflectError> {
×
302
        self.require_active()?;
×
303

304
        // Get the source value's pointer and shape
305
        let src_ptr = peek.data();
×
306
        let src_shape = peek.shape();
×
307

308
        // SAFETY: `Peek` guarantees that src_ptr is initialized and of type src_shape
309
        unsafe { self.set_shape(src_ptr, src_shape) }
×
310
    }
×
311

312
    /// Parses a string value into the current frame using the type's ParseFn from the vtable.
313
    ///
314
    /// If the current frame was previously initialized, its contents are dropped in place.
315
    pub fn parse_from_str(&mut self, s: &str) -> Result<&mut Self, ReflectError> {
296✔
316
        self.require_active()?;
296✔
317

318
        let frame = self.frames_mut().last_mut().unwrap();
296✔
319

320
        // Check if the type has a parse function
321
        let Some(parse_fn) = frame.shape.vtable.parse else {
296✔
322
            return Err(ReflectError::OperationFailed {
2✔
323
                shape: frame.shape,
2✔
324
                operation: "Type does not support parsing from string",
2✔
325
            });
2✔
326
        };
327

328
        // Note: deinit leaves us in `Tracker::Uninit` state which is valid even if we error out.
329
        frame.deinit();
294✔
330

331
        // Parse the string value using the type's parse function
332
        let result = unsafe { parse_fn(s, frame.data) };
294✔
333
        if let Err(_pe) = result {
294✔
334
            // TODO: can we propagate the ParseError somehow?
335
            return Err(ReflectError::OperationFailed {
11✔
336
                shape: frame.shape,
11✔
337
                operation: "Failed to parse string value",
11✔
338
            });
11✔
339
        }
283✔
340

341
        // SAFETY: `parse_fn` returned `Ok`, so `frame.data` is fully initialized now.
342
        unsafe {
283✔
343
            frame.mark_as_init();
283✔
344
        }
283✔
345
        Ok(self)
283✔
346
    }
296✔
347
}
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