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

facet-rs / facet / 19803020611

30 Nov 2025 06:23PM UTC coverage: 57.923% (-3.0%) from 60.927%
19803020611

push

github

fasterthanlime
Convert facet-kdl to use define_attr_grammar!

- Replace ~140 lines of hand-written macros with concise grammar DSL
- Enhance make_parse_attr.rs grammar compiler:
  - Add `ns "kdl";` syntax for namespace declaration
  - Add to_snake_case() helper (NodeName → node_name)
  - Generate __attr! macro with proper ExtensionAttr return
  - Use () data for unit variants, full dispatch for complex ones
  - Add #[repr(u8)] to generated enums for Facet derive
  - Use HashMap for O(1) struct lookup
- Update design diagrams with namespace fixes

50 of 53 new or added lines in 1 file covered. (94.34%)

3583 existing lines in 40 files now uncovered.

18788 of 32436 relevant lines covered (57.92%)

179.8 hits per line

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

60.27
/facet-reflect/src/partial/partial_api/set.rs
1
use super::*;
2
use facet_core::{Def, DynDateTimeKind, 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<Self, ReflectError>
2,139✔
14
    where
2,139✔
15
        U: Facet<'facet>,
2,139✔
16
    {
17
        struct DropVal<U> {
18
            ptr: *mut U,
19
        }
20
        impl<U> Drop for DropVal<U> {
21
            #[inline]
22
            fn drop(&mut self) {
1✔
23
                unsafe { core::ptr::drop_in_place(self.ptr) };
1✔
24
            }
1✔
25
        }
26

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

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

37
        Ok(self)
2,138✔
38
    }
2,139✔
39

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

62
        // Check if target is a DynamicValue - if so, convert the source value
63
        if let Def::DynamicValue(dyn_def) = &fr.shape.def {
2,139✔
64
            return unsafe { self.set_into_dynamic_value(src_value, src_shape, dyn_def) };
39✔
65
        }
2,100✔
66

67
        if !fr.shape.is_shape(src_shape) {
2,100✔
68
            return Err(ReflectError::WrongShape {
1✔
69
                expected: fr.shape,
1✔
70
                actual: src_shape,
1✔
71
            });
1✔
72
        }
2,099✔
73

74
        fr.deinit();
2,099✔
75

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

84
        // SAFETY: if we reached this point, `fr.data` is correctly initialized
85
        unsafe {
2,099✔
86
            fr.mark_as_init();
2,099✔
87
        }
2,099✔
88

89
        Ok(self)
2,099✔
90
    }
2,139✔
91

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

106
        fr.deinit();
39✔
107

108
        // If source shape is also the same DynamicValue shape, just copy it
109
        if fr.shape.is_shape(src_shape) {
39✔
110
            unsafe {
1✔
111
                fr.data.copy_from(src_value, fr.shape).unwrap();
1✔
112
                fr.mark_as_init();
1✔
113
            }
1✔
114
            return Ok(self);
1✔
115
        }
38✔
116

117
        // Get the size in bits for numeric conversions
118
        let size_bits = src_shape
38✔
119
            .layout
38✔
120
            .sized_layout()
38✔
121
            .map(|l| l.size() * 8)
38✔
122
            .unwrap_or(0);
38✔
123

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

222
        let fr = self.frames_mut().last_mut().unwrap();
38✔
223
        fr.tracker = Tracker::DynamicValue {
38✔
224
            state: DynamicValueState::Scalar,
38✔
225
        };
38✔
226
        unsafe { fr.mark_as_init() };
38✔
227
        Ok(self)
38✔
228
    }
39✔
229

230
    /// Sets a datetime value into a DynamicValue target.
231
    ///
232
    /// This is used for format-specific datetime types (like TOML datetime).
233
    /// Returns an error if the target doesn't support datetime values.
234
    #[allow(clippy::too_many_arguments)]
UNCOV
235
    pub fn set_datetime(
×
UNCOV
236
        mut self,
×
UNCOV
237
        year: i32,
×
UNCOV
238
        month: u8,
×
UNCOV
239
        day: u8,
×
UNCOV
240
        hour: u8,
×
UNCOV
241
        minute: u8,
×
UNCOV
242
        second: u8,
×
UNCOV
243
        nanos: u32,
×
UNCOV
244
        kind: DynDateTimeKind,
×
UNCOV
245
    ) -> Result<Self, ReflectError> {
×
UNCOV
246
        let fr = self.frames_mut().last_mut().unwrap();
×
247

248
        // Must be a DynamicValue type
UNCOV
249
        let dyn_def = match &fr.shape.def {
×
UNCOV
250
            Def::DynamicValue(dv) => dv,
×
251
            _ => {
UNCOV
252
                return Err(ReflectError::OperationFailed {
×
UNCOV
253
                    shape: fr.shape,
×
UNCOV
254
                    operation: "set_datetime requires a DynamicValue target",
×
UNCOV
255
                });
×
256
            }
257
        };
258

UNCOV
259
        let vtable = dyn_def.vtable;
×
260

261
        // Check if the vtable supports datetime
UNCOV
262
        let Some(set_datetime_fn) = vtable.set_datetime else {
×
UNCOV
263
            return Err(ReflectError::OperationFailed {
×
UNCOV
264
                shape: fr.shape,
×
UNCOV
265
                operation: "dynamic value type does not support datetime",
×
UNCOV
266
            });
×
267
        };
268

UNCOV
269
        fr.deinit();
×
270

271
        // Call the vtable's set_datetime function
UNCOV
272
        unsafe {
×
UNCOV
273
            set_datetime_fn(fr.data, year, month, day, hour, minute, second, nanos, kind);
×
UNCOV
274
        }
×
275

UNCOV
276
        let fr = self.frames_mut().last_mut().unwrap();
×
UNCOV
277
        fr.tracker = Tracker::DynamicValue {
×
UNCOV
278
            state: DynamicValueState::Scalar,
×
UNCOV
279
        };
×
UNCOV
280
        unsafe { fr.mark_as_init() };
×
UNCOV
281
        Ok(self)
×
UNCOV
282
    }
×
283

284
    /// Sets the current frame using a function that initializes the value
285
    ///
286
    /// # Safety
287
    ///
288
    /// If `f` returns Ok(), it is assumed that it initialized the passed pointer fully and with a
289
    /// value of the right type.
290
    ///
291
    /// If `f` returns Err(), it is assumed that it did NOT initialize the passed pointer and that
292
    /// there is no need to drop it in place.
293
    pub unsafe fn set_from_function<F>(mut self, f: F) -> Result<Self, ReflectError>
64✔
294
    where
64✔
295
        F: FnOnce(PtrUninit<'_>) -> Result<(), ReflectError>,
64✔
296
    {
297
        let frame = self.frames_mut().last_mut().unwrap();
64✔
298

299
        frame.deinit();
64✔
300
        f(frame.data)?;
64✔
301

302
        // safety: `f()` returned Ok, so `frame.data` must be initialized
303
        unsafe {
64✔
304
            frame.mark_as_init();
64✔
305
        }
64✔
306

307
        Ok(self)
64✔
308
    }
64✔
309

310
    /// Sets the current frame to its default value using `default_in_place` from the
311
    /// vtable.
312
    ///
313
    /// Note: if you have `struct S { field: F }`, and `F` does not implement `Default`
314
    /// but `S` does, this doesn't magically uses S's `Default` implementation to get a value
315
    /// for `field`.
316
    ///
317
    /// If the current frame's shape does not implement `Default`, then this returns an error.
318
    #[inline]
319
    pub fn set_default(self) -> Result<Self, ReflectError> {
55✔
320
        let frame = self.frames().last().unwrap();
55✔
321

322
        let Some(default_fn) = frame.shape.vtable.default_in_place else {
55✔
323
            return Err(ReflectError::OperationFailed {
1✔
324
                shape: frame.shape,
1✔
325
                operation: "type does not implement Default",
1✔
326
            });
1✔
327
        };
328

329
        // SAFETY: `default_fn` fully initializes the passed pointer. we took it
330
        // from the vtable of `frame.shape`.
331
        unsafe {
332
            self.set_from_function(move |ptr| {
54✔
333
                default_fn(ptr);
54✔
334
                Ok(())
54✔
335
            })
54✔
336
        }
337
    }
55✔
338

339
    /// Copy a value from a Peek into the current frame.
340
    ///
341
    /// # Invariants
342
    ///
343
    /// `peek` must be a thin pointer, otherwise this panics.
344
    ///
345
    /// # Safety
346
    ///
347
    /// If this succeeds, the value `Peek` points to has been moved out of, and
348
    /// as such, should not be dropped (but should be deallocated).
UNCOV
349
    pub unsafe fn set_from_peek(self, peek: &Peek<'_, '_>) -> Result<Self, ReflectError> {
×
350
        // Get the source value's pointer and shape
UNCOV
351
        let src_ptr = peek.data();
×
UNCOV
352
        let src_shape = peek.shape();
×
353

354
        // SAFETY: `Peek` guarantees that src_ptr is initialized and of type src_shape
UNCOV
355
        unsafe { self.set_shape(src_ptr, src_shape) }
×
UNCOV
356
    }
×
357

358
    /// Parses a string value into the current frame using the type's ParseFn from the vtable.
359
    ///
360
    /// If the current frame was previously initialized, its contents are dropped in place.
361
    pub fn parse_from_str(mut self, s: &str) -> Result<Self, ReflectError> {
308✔
362
        let frame = self.frames_mut().last_mut().unwrap();
308✔
363

364
        // Check if the type has a parse function
365
        let Some(parse_fn) = frame.shape.vtable.parse else {
308✔
366
            return Err(ReflectError::OperationFailed {
2✔
367
                shape: frame.shape,
2✔
368
                operation: "Type does not support parsing from string",
2✔
369
            });
2✔
370
        };
371

372
        // Note: deinit leaves us in `Tracker::Uninit` state which is valid even if we error out.
373
        frame.deinit();
306✔
374

375
        // Parse the string value using the type's parse function
376
        let result = unsafe { parse_fn(s, frame.data) };
306✔
377
        if let Err(_pe) = result {
306✔
378
            // TODO: can we propagate the ParseError somehow?
379
            return Err(ReflectError::OperationFailed {
11✔
380
                shape: frame.shape,
11✔
381
                operation: "Failed to parse string value",
11✔
382
            });
11✔
383
        }
295✔
384

385
        // SAFETY: `parse_fn` returned `Ok`, so `frame.data` is fully initialized now.
386
        unsafe {
295✔
387
            frame.mark_as_init();
295✔
388
        }
295✔
389
        Ok(self)
295✔
390
    }
308✔
391
}
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