Skip to main content

facet_reflect/partial/partial_api/
set.rs

1use super::*;
2use facet_core::{Def, DynDateTimeKind, KnownPointer, NumericType, PrimitiveType, Type};
3
4////////////////////////////////////////////////////////////////////////////////////////////////////
5// `Set` and set helpers
6////////////////////////////////////////////////////////////////////////////////////////////////////
7impl<'facet, const BORROW: bool> Partial<'facet, BORROW> {
8    /// Set a shared slice reference (`&[T]`) to an empty slice without knowing `T` at compile time.
9    ///
10    /// This writes a valid wide reference with len=0 and a suitably aligned dangling data pointer.
11    pub fn set_empty_shared_slice(mut self) -> Result<Self, ReflectError> {
12        let shape = self.frames().last().unwrap().allocated.shape();
13        let align = match shape.def {
14            Def::Pointer(ptr_def)
15                if matches!(ptr_def.known, Some(KnownPointer::SharedReference)) =>
16            {
17                let Some(pointee) = ptr_def.pointee() else {
18                    return Err(self.err(ReflectErrorKind::OperationFailed {
19                        shape,
20                        operation: "shared reference pointer missing pointee shape",
21                    }));
22                };
23                let Def::Slice(slice_def) = pointee.def else {
24                    return Err(self.err(ReflectErrorKind::OperationFailed {
25                        shape,
26                        operation: "set_empty_shared_slice requires a slice pointee",
27                    }));
28                };
29                slice_def
30                    .t
31                    .layout
32                    .sized_layout()
33                    .map_or(1, |l| l.align().max(1))
34            }
35            _ => {
36                return Err(self.err(ReflectErrorKind::OperationFailed {
37                    shape,
38                    operation: "set_empty_shared_slice requires a shared slice reference",
39                }));
40            }
41        };
42
43        let fr = self.frames_mut().last_mut().unwrap();
44        fr.deinit_for_replace();
45
46        // For len=0, any non-null aligned pointer is valid.
47        let data_ptr = align as *const u8 as usize;
48        unsafe {
49            let dst = fr.data.as_mut_byte_ptr() as *mut [usize; 2];
50            core::ptr::write(dst, [data_ptr, 0]);
51            fr.mark_as_init();
52        }
53
54        Ok(self)
55    }
56
57    /// Sets a value wholesale into the current frame.
58    ///
59    /// If the current frame was already initialized, the previous value is
60    /// dropped. If it was partially initialized, the fields that were initialized
61    /// are dropped, etc.
62    pub fn set<U>(mut self, value: U) -> Result<Self, ReflectError>
63    where
64        U: Facet<'facet>,
65    {
66        struct DropVal<U> {
67            ptr: *mut U,
68        }
69        impl<U> Drop for DropVal<U> {
70            #[inline]
71            fn drop(&mut self) {
72                unsafe { core::ptr::drop_in_place(self.ptr) };
73            }
74        }
75
76        let mut value = ManuallyDrop::new(value);
77        let drop = DropVal {
78            ptr: (&mut value) as *mut ManuallyDrop<U> as *mut U,
79        };
80
81        let ptr_const = PtrConst::new(drop.ptr);
82        // Safety: We are calling set_shape with a valid shape and a valid pointer
83        self = unsafe { self.set_shape(ptr_const, U::SHAPE)? };
84        core::mem::forget(drop);
85
86        Ok(self)
87    }
88
89    /// Sets a value into the current frame by [PtrConst] / [Shape].
90    ///
91    /// # Safety
92    ///
93    /// The caller must ensure that `src_value` points to a valid instance of a value
94    /// whose memory layout and type matches `src_shape`, and that this value can be
95    /// safely copied (bitwise) into the destination specified by the Partial's current frame.
96    ///
97    /// After a successful call, the ownership of the value at `src_value` is effectively moved
98    /// into the Partial (i.e., the destination), and the original value should not be used
99    /// or dropped by the caller; you should use `core::mem::forget` on the passed value.
100    ///
101    /// If an error is returned, the destination remains unmodified and safe for future operations.
102    #[inline]
103    pub unsafe fn set_shape(
104        mut self,
105        src_value: PtrConst,
106        src_shape: &'static Shape,
107    ) -> Result<Self, ReflectError> {
108        // Get shape upfront to avoid borrow conflicts
109        let shape = self.frames().last().unwrap().allocated.shape();
110        let fr = self.frames_mut().last_mut().unwrap();
111        crate::trace!("set_shape({src_shape:?})");
112
113        // Check if target is a DynamicValue - if so, convert the source value
114        if let Def::DynamicValue(dyn_def) = &shape.def {
115            return unsafe { self.set_into_dynamic_value(src_value, src_shape, dyn_def) };
116        }
117
118        if !shape.is_shape(src_shape) {
119            return Err(self.err(ReflectErrorKind::WrongShape {
120                expected: shape,
121                actual: src_shape,
122            }));
123        }
124
125        fr.deinit_for_replace();
126
127        // SAFETY: `fr.allocated.shape()` and `src_shape` are the same, so they have the same size,
128        // and the preconditions for this function are that `src_value` is fully intialized.
129        unsafe {
130            // unwrap safety: the only failure condition for copy_from is that shape is unsized,
131            // which is not possible for `Partial`
132            fr.data.copy_from(src_value, fr.allocated.shape()).unwrap();
133        }
134
135        // SAFETY: if we reached this point, `fr.data` is correctly initialized
136        unsafe {
137            fr.mark_as_init();
138        }
139
140        Ok(self)
141    }
142
143    /// Sets a value into a DynamicValue target by converting the source value.
144    ///
145    /// # Safety
146    ///
147    /// Same safety requirements as `set_shape`.
148    unsafe fn set_into_dynamic_value(
149        mut self,
150        src_value: PtrConst,
151        src_shape: &'static Shape,
152        dyn_def: &facet_core::DynamicValueDef,
153    ) -> Result<Self, ReflectError> {
154        let fr = self.frames_mut().last_mut().unwrap();
155        let vtable = dyn_def.vtable;
156
157        // Use deinit_for_replace which handles BorrowedInPlace and Field frames correctly
158        fr.deinit_for_replace();
159
160        // If source shape is also the same DynamicValue shape, just copy it
161        if fr.allocated.shape().is_shape(src_shape) {
162            unsafe {
163                fr.data.copy_from(src_value, fr.allocated.shape()).unwrap();
164                fr.mark_as_init();
165            }
166            return Ok(self);
167        }
168
169        // Get the size in bits for numeric conversions
170        let size_bits = src_shape
171            .layout
172            .sized_layout()
173            .map(|l| l.size() * 8)
174            .unwrap_or(0);
175
176        // Convert based on source shape's type
177        match &src_shape.ty {
178            Type::Primitive(PrimitiveType::Boolean) => {
179                let val = unsafe { *(src_value.as_byte_ptr() as *const bool) };
180                unsafe { (vtable.set_bool)(fr.data, val) };
181            }
182            Type::Primitive(PrimitiveType::Numeric(NumericType::Float)) => {
183                if size_bits == 64 {
184                    let val = unsafe { *(src_value.as_byte_ptr() as *const f64) };
185                    let success = unsafe { (vtable.set_f64)(fr.data, val) };
186                    if !success {
187                        return Err(self.err(ReflectErrorKind::OperationFailed {
188                            shape: src_shape,
189                            operation: "f64 value (NaN/Infinity) not representable in dynamic value",
190                        }));
191                    }
192                } else if size_bits == 32 {
193                    let val = unsafe { *(src_value.as_byte_ptr() as *const f32) } as f64;
194                    let success = unsafe { (vtable.set_f64)(fr.data, val) };
195                    if !success {
196                        return Err(self.err(ReflectErrorKind::OperationFailed {
197                            shape: src_shape,
198                            operation: "f32 value (NaN/Infinity) not representable in dynamic value",
199                        }));
200                    }
201                } else {
202                    return Err(self.err(ReflectErrorKind::OperationFailed {
203                        shape: src_shape,
204                        operation: "unsupported float size for dynamic value",
205                    }));
206                }
207            }
208            Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: true })) => {
209                let val: i64 = match size_bits {
210                    8 => (unsafe { *(src_value.as_byte_ptr() as *const i8) }) as i64,
211                    16 => (unsafe { *(src_value.as_byte_ptr() as *const i16) }) as i64,
212                    32 => (unsafe { *(src_value.as_byte_ptr() as *const i32) }) as i64,
213                    64 => unsafe { *(src_value.as_byte_ptr() as *const i64) },
214                    _ => {
215                        return Err(self.err(ReflectErrorKind::OperationFailed {
216                            shape: src_shape,
217                            operation: "unsupported signed integer size for dynamic value",
218                        }));
219                    }
220                };
221                unsafe { (vtable.set_i64)(fr.data, val) };
222            }
223            Type::Primitive(PrimitiveType::Numeric(NumericType::Integer { signed: false })) => {
224                let val: u64 = match size_bits {
225                    8 => (unsafe { *src_value.as_byte_ptr() }) as u64,
226                    16 => (unsafe { *(src_value.as_byte_ptr() as *const u16) }) as u64,
227                    32 => (unsafe { *(src_value.as_byte_ptr() as *const u32) }) as u64,
228                    64 => unsafe { *(src_value.as_byte_ptr() as *const u64) },
229                    _ => {
230                        return Err(self.err(ReflectErrorKind::OperationFailed {
231                            shape: src_shape,
232                            operation: "unsupported unsigned integer size for dynamic value",
233                        }));
234                    }
235                };
236                unsafe { (vtable.set_u64)(fr.data, val) };
237            }
238            Type::Primitive(PrimitiveType::Textual(_)) => {
239                // char or str - for char, convert to string
240                if *src_shape == *char::SHAPE {
241                    let c = unsafe { *(src_value.as_byte_ptr() as *const char) };
242                    let mut buf = [0u8; 4];
243                    let s = c.encode_utf8(&mut buf);
244                    unsafe { (vtable.set_str)(fr.data, s) };
245                } else {
246                    // &str
247                    let s: &str = unsafe { *(src_value.as_byte_ptr() as *const &str) };
248                    unsafe { (vtable.set_str)(fr.data, s) };
249                }
250            }
251            _ => {
252                if let Some(set_bytes) = vtable.set_bytes
253                    && let Def::List(list_def) = &src_shape.def
254                    && list_def.t.is_type::<u8>()
255                {
256                    let bytes: &::alloc::vec::Vec<u8> =
257                        unsafe { &*(src_value.as_byte_ptr() as *const ::alloc::vec::Vec<u8>) };
258                    unsafe { (set_bytes)(fr.data, bytes.as_slice()) };
259                    // Drop the source Vec since we've copied the bytes into the dynamic value.
260                    unsafe {
261                        src_shape
262                            .call_drop_in_place(PtrMut::new(src_value.as_byte_ptr() as *mut u8));
263                    }
264                    let fr = self.frames_mut().last_mut().unwrap();
265                    fr.tracker = Tracker::DynamicValue {
266                        state: DynamicValueState::Scalar,
267                    };
268                    unsafe { fr.mark_as_init() };
269                    return Ok(self);
270                }
271
272                // Handle String type (not a primitive but common)
273                if *src_shape == *::alloc::string::String::SHAPE {
274                    let s: &::alloc::string::String =
275                        unsafe { &*(src_value.as_byte_ptr() as *const ::alloc::string::String) };
276                    unsafe { (vtable.set_str)(fr.data, s.as_str()) };
277                    // Drop the source String since we cloned its content
278                    unsafe {
279                        src_shape
280                            .call_drop_in_place(PtrMut::new(src_value.as_byte_ptr() as *mut u8));
281                    }
282                } else {
283                    return Err(self.err(ReflectErrorKind::OperationFailed {
284                        shape: src_shape,
285                        operation: "cannot convert this type to dynamic value",
286                    }));
287                }
288            }
289        }
290
291        let fr = self.frames_mut().last_mut().unwrap();
292        fr.tracker = Tracker::DynamicValue {
293            state: DynamicValueState::Scalar,
294        };
295        unsafe { fr.mark_as_init() };
296        Ok(self)
297    }
298
299    /// Sets a datetime value into a DynamicValue target.
300    ///
301    /// This is used for format-specific datetime types (like TOML datetime).
302    /// Returns an error if the target doesn't support datetime values.
303    #[allow(clippy::too_many_arguments)]
304    pub fn set_datetime(
305        mut self,
306        year: i32,
307        month: u8,
308        day: u8,
309        hour: u8,
310        minute: u8,
311        second: u8,
312        nanos: u32,
313        kind: DynDateTimeKind,
314    ) -> Result<Self, ReflectError> {
315        // Get shape upfront to avoid borrow conflicts
316        let shape = self.frames().last().unwrap().allocated.shape();
317        let fr = self.frames_mut().last_mut().unwrap();
318
319        // Must be a DynamicValue type
320        let dyn_def = match &shape.def {
321            Def::DynamicValue(dv) => dv,
322            _ => {
323                return Err(self.err(ReflectErrorKind::OperationFailed {
324                    shape,
325                    operation: "set_datetime requires a DynamicValue target",
326                }));
327            }
328        };
329
330        let vtable = dyn_def.vtable;
331
332        // Check if the vtable supports datetime
333        let Some(set_datetime_fn) = vtable.set_datetime else {
334            return Err(self.err(ReflectErrorKind::OperationFailed {
335                shape,
336                operation: "dynamic value type does not support datetime",
337            }));
338        };
339
340        fr.deinit_for_replace();
341
342        // Call the vtable's set_datetime function
343        unsafe {
344            set_datetime_fn(fr.data, year, month, day, hour, minute, second, nanos, kind);
345        }
346
347        let fr = self.frames_mut().last_mut().unwrap();
348        fr.tracker = Tracker::DynamicValue {
349            state: DynamicValueState::Scalar,
350        };
351        unsafe { fr.mark_as_init() };
352        Ok(self)
353    }
354
355    /// Sets the current frame using a function that initializes the value
356    ///
357    /// # Safety
358    ///
359    /// If `f` returns Ok(), it is assumed that it initialized the passed pointer fully and with a
360    /// value of the right type.
361    ///
362    /// If `f` returns Err(), it is assumed that it did NOT initialize the passed pointer and that
363    /// there is no need to drop it in place.
364    pub unsafe fn set_from_function<F>(mut self, f: F) -> Result<Self, ReflectError>
365    where
366        F: FnOnce(PtrUninit) -> Result<(), ReflectErrorKind>,
367    {
368        let frame = self.frames_mut().last_mut().unwrap();
369
370        frame.deinit_for_replace();
371        if let Err(kind) = f(frame.data) {
372            // Only compute path on error (path construction allocates)
373            return Err(self.err(kind));
374        }
375
376        // safety: `f()` returned Ok, so `frame.data` must be initialized
377        unsafe {
378            frame.mark_as_init();
379        }
380
381        Ok(self)
382    }
383
384    /// Sets the current frame to its default value using `default_in_place` from the
385    /// vtable.
386    ///
387    /// Note: if you have `struct S { field: F }`, and `F` does not implement `Default`
388    /// but `S` does, this doesn't magically uses S's `Default` implementation to get a value
389    /// for `field`.
390    ///
391    /// If the current frame's shape does not implement `Default`, then this returns an error.
392    #[inline]
393    pub fn set_default(self) -> Result<Self, ReflectError> {
394        let frame = self.frames().last().unwrap();
395        let shape = frame.allocated.shape();
396
397        // SAFETY: `call_default_in_place` fully initializes the passed pointer.
398        unsafe {
399            self.set_from_function(move |ptr| {
400                shape
401                    .call_default_in_place(ptr)
402                    .ok_or(ReflectErrorKind::OperationFailed {
403                        shape,
404                        operation: "type does not implement Default",
405                    })
406            })
407        }
408    }
409
410    /// Copy a value from a Peek into the current frame.
411    ///
412    /// # Invariants
413    ///
414    /// `peek` must be a thin pointer, otherwise this panics.
415    ///
416    /// # Safety
417    ///
418    /// If this succeeds, the value `Peek` points to has been moved out of, and
419    /// as such, should not be dropped (but should be deallocated).
420    pub unsafe fn set_from_peek(self, peek: &Peek<'_, '_>) -> Result<Self, ReflectError> {
421        // Get the source value's pointer and shape
422        let src_ptr = peek.data();
423        let src_shape = peek.shape();
424
425        // SAFETY: `Peek` guarantees that src_ptr is initialized and of type src_shape
426        unsafe { self.set_shape(src_ptr, src_shape) }
427    }
428
429    /// Parses a string value into the current frame using the type's ParseFn from the vtable.
430    ///
431    /// If the current frame was previously initialized, its contents are dropped in place.
432    pub fn parse_from_str(mut self, s: &str) -> Result<Self, ReflectError> {
433        let frame = self.frames_mut().last_mut().unwrap();
434        let shape = frame.allocated.shape();
435
436        frame.deinit_for_replace();
437
438        // Parse the string value using the type's parse function
439        let result = unsafe { shape.call_parse(s, frame.data) };
440
441        match result {
442            Some(Ok(())) => {
443                // SAFETY: `call_parse` returned `Ok`, so `frame.data` is fully initialized now.
444                unsafe {
445                    frame.mark_as_init();
446                }
447                Ok(self)
448            }
449            Some(Err(_pe)) => {
450                // Return a ParseFailed error with the input value for better diagnostics
451                Err(self.err(ReflectErrorKind::ParseFailed {
452                    shape,
453                    input: s.into(),
454                }))
455            }
456            None => Err(self.err(ReflectErrorKind::OperationFailed {
457                shape,
458                operation: "Type does not support parsing from string",
459            })),
460        }
461    }
462
463    /// Parses a byte slice into the current frame using the type's ParseBytesFn from the vtable.
464    ///
465    /// This is used for binary formats where types have efficient binary representations
466    /// (e.g., UUID as 16 raw bytes instead of a string).
467    ///
468    /// If the current frame was previously initialized, its contents are dropped in place.
469    pub fn parse_from_bytes(mut self, bytes: &[u8]) -> Result<Self, ReflectError> {
470        let frame = self.frames_mut().last_mut().unwrap();
471        let shape = frame.allocated.shape();
472
473        frame.deinit_for_replace();
474
475        // Parse the bytes using the type's parse_bytes function
476        let result = unsafe { shape.call_parse_bytes(bytes, frame.data) };
477
478        match result {
479            Some(Ok(())) => {
480                // SAFETY: `call_parse_bytes` returned `Ok`, so `frame.data` is fully initialized.
481                unsafe {
482                    frame.mark_as_init();
483                }
484                Ok(self)
485            }
486            Some(Err(_pe)) => {
487                // TODO: can we propagate the ParseError somehow?
488                Err(self.err(ReflectErrorKind::OperationFailed {
489                    shape,
490                    operation: "Failed to parse bytes value",
491                }))
492            }
493            None => Err(self.err(ReflectErrorKind::OperationFailed {
494                shape,
495                operation: "Type does not support parsing from bytes",
496            })),
497        }
498    }
499}