• 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

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

3
////////////////////////////////////////////////////////////////////////////////////////////////////
4
// Option / inner
5
////////////////////////////////////////////////////////////////////////////////////////////////////
6
impl Partial<'_> {
7
    /// Begin building the Some variant of an Option
8
    pub fn begin_some(&mut self) -> Result<&mut Self, ReflectError> {
133✔
9
        self.require_active()?;
133✔
10

11
        // Verify we're working with an Option and get the def
12
        let option_def = {
131✔
13
            let frame = self.frames().last().unwrap();
133✔
14
            match frame.shape.def {
133✔
15
                Def::Option(def) => def,
131✔
16
                _ => {
17
                    return Err(ReflectError::WasNotA {
2✔
18
                        expected: "Option",
2✔
19
                        actual: frame.shape,
2✔
20
                    });
2✔
21
                }
22
            }
23
        };
24

25
        // Check if we need to handle re-initialization.
26
        // For Options, also check if tracker is Option{building_inner:false} which means
27
        // a previous begin_some/end cycle completed.
28
        let needs_reinit = {
131✔
29
            let frame = self.frames().last().unwrap();
131✔
30
            frame.is_init
131✔
31
                || matches!(
131✔
32
                    frame.tracker,
131✔
33
                    Tracker::Option {
34
                        building_inner: false
35
                    }
36
                )
37
        };
38

39
        if needs_reinit {
131✔
NEW
40
            self.prepare_for_reinitialization();
×
41
        }
131✔
42

43
        // Set tracker to indicate we're building the inner value
44
        let frame = self.frames_mut().last_mut().unwrap();
131✔
45
        frame.tracker = Tracker::Option {
131✔
46
            building_inner: true,
131✔
47
        };
131✔
48

49
        // Get the inner type shape
50
        let inner_shape = option_def.t;
131✔
51

52
        // Allocate memory for the inner value
53
        let inner_layout =
131✔
54
            inner_shape
131✔
55
                .layout
131✔
56
                .sized_layout()
131✔
57
                .map_err(|_| ReflectError::Unsized {
131✔
58
                    shape: inner_shape,
×
59
                    operation: "begin_some, allocating Option inner value",
60
                })?;
×
61

62
        let inner_data = if inner_layout.size() == 0 {
131✔
63
            // For ZST, use a non-null but unallocated pointer
64
            PtrUninit::new(NonNull::<u8>::dangling())
×
65
        } else {
66
            // Allocate memory for the inner value
67
            let ptr = unsafe { ::alloc::alloc::alloc(inner_layout) };
131✔
68
            let Some(ptr) = NonNull::new(ptr) else {
131✔
69
                ::alloc::alloc::handle_alloc_error(inner_layout);
×
70
            };
71
            PtrUninit::new(ptr)
131✔
72
        };
73

74
        // Create a new frame for the inner value
75
        let inner_frame = Frame::new(inner_data, inner_shape, FrameOwnership::Owned);
131✔
76
        self.frames_mut().push(inner_frame);
131✔
77

78
        Ok(self)
131✔
79
    }
133✔
80

81
    /// Begin building the inner value of a wrapper type
82
    pub fn begin_inner(&mut self) -> Result<&mut Self, ReflectError> {
39✔
83
        self.require_active()?;
39✔
84

85
        // Get the inner shape and check for try_from
86
        let (inner_shape, has_try_from, parent_shape, is_option) = {
39✔
87
            let frame = self.frames().last().unwrap();
39✔
88
            if let Some(inner_shape) = frame.shape.inner {
39✔
89
                let has_try_from = frame.shape.vtable.try_from.is_some();
36✔
90
                let is_option = matches!(frame.shape.def, Def::Option(_));
36✔
91
                (Some(inner_shape), has_try_from, frame.shape, is_option)
36✔
92
            } else {
93
                (None, false, frame.shape, false)
3✔
94
            }
95
        };
96

97
        // Handle re-initialization if needed
98
        self.prepare_for_reinitialization();
39✔
99

100
        if let Some(inner_shape) = inner_shape {
39✔
101
            if has_try_from {
36✔
102
                // For Option types, use begin_some behavior to properly track building_inner
103
                // This ensures end() knows how to handle the popped frame
104
                if is_option {
35✔
105
                    return self.begin_some();
×
106
                }
35✔
107

108
                // Create a conversion frame with the inner shape
109
                // For non-Option types with try_from, we leave the parent tracker unchanged
110
                // and the conversion will happen in end()
111

112
                // Allocate memory for the inner value (conversion source)
113
                let inner_layout =
35✔
114
                    inner_shape
35✔
115
                        .layout
35✔
116
                        .sized_layout()
35✔
117
                        .map_err(|_| ReflectError::Unsized {
35✔
118
                            shape: inner_shape,
×
119
                            operation: "begin_inner, getting inner layout",
120
                        })?;
×
121

122
                let inner_data = if inner_layout.size() == 0 {
35✔
123
                    // For ZST, use a non-null but unallocated pointer
124
                    PtrUninit::new(NonNull::<u8>::dangling())
×
125
                } else {
126
                    // Allocate memory for the inner value
127
                    let ptr = unsafe { ::alloc::alloc::alloc(inner_layout) };
35✔
128
                    let Some(ptr) = NonNull::new(ptr) else {
35✔
129
                        ::alloc::alloc::handle_alloc_error(inner_layout);
×
130
                    };
131
                    PtrUninit::new(ptr)
35✔
132
                };
133

134
                // For conversion frames, we create a frame directly with the inner shape
135
                // This allows setting values of the inner type which will be converted
136
                // The automatic conversion detection in end() will handle the conversion
137
                trace!(
138
                    "begin_inner: Creating frame for inner type {inner_shape} (parent is {parent_shape})"
139
                );
140
                self.frames_mut()
35✔
141
                    .push(Frame::new(inner_data, inner_shape, FrameOwnership::Owned));
35✔
142

143
                Ok(self)
35✔
144
            } else {
145
                // For wrapper types without try_from, navigate to the first field
146
                // This is a common pattern for newtype wrappers
147
                trace!("begin_inner: No try_from for {parent_shape}, using field navigation");
148
                self.begin_nth_field(0)
1✔
149
            }
150
        } else {
151
            Err(ReflectError::OperationFailed {
3✔
152
                shape: parent_shape,
3✔
153
                operation: "type does not have an inner value",
3✔
154
            })
3✔
155
        }
156
    }
39✔
157

158
    /// Begin bulding the source shape for custom deserialization, calling end() for this frame will
159
    /// call the deserialize_with function provided by the field and set the field using the result.
160
    pub fn begin_custom_deserialization(&mut self) -> Result<&mut Self, ReflectError> {
19✔
161
        self.require_active()?;
19✔
162

163
        let current_frame = self.frames().last().unwrap();
19✔
164
        let target_shape = current_frame.shape;
19✔
165
        if let Some(field) = self.parent_field() {
19✔
166
            if field.vtable.deserialize_with.is_some() {
19✔
167
                // TODO: can we assume that this is set if the vtable element is set?
168
                // TODO: can we get the shape some other way?
169
                let Some(FieldAttribute::DeserializeFrom(source_shape)) = field
19✔
170
                    .attributes
19✔
171
                    .iter()
19✔
172
                    .find(|&p| matches!(p, FieldAttribute::DeserializeFrom(_)))
22✔
173
                else {
174
                    panic!("expected field attribute to be present with deserialize_with");
×
175
                };
176
                let source_data = source_shape.allocate().map_err(|_| ReflectError::Unsized {
19✔
177
                    shape: target_shape,
×
178
                    operation: "Not a Sized type",
179
                })?;
×
180

181
                trace!(
182
                    "begin_custom_deserialization: Creating frame for deserialization type {source_shape}"
183
                );
184
                let mut new_frame = Frame::new(source_data, source_shape, FrameOwnership::Owned);
19✔
185
                new_frame.using_custom_deserialization = true;
19✔
186
                self.frames_mut().push(new_frame);
19✔
187

188
                Ok(self)
19✔
189
            } else {
190
                Err(ReflectError::OperationFailed {
×
191
                    shape: target_shape,
×
192
                    operation: "field does not have a deserialize_with function",
×
193
                })
×
194
            }
195
        } else {
196
            Err(ReflectError::OperationFailed {
×
197
                shape: target_shape,
×
198
                operation: "not currently processing a field",
×
199
            })
×
200
        }
201
    }
19✔
202
}
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