Skip to main content

facet_reflect/poke/
dynamic_value.rs

1//! Support for poking (mutating) DynamicValue types like `facet_value::Value`
2
3use core::mem::ManuallyDrop;
4
5use facet_core::{DynValueKind, DynamicValueDef, Facet, PtrMut, PtrUninit};
6
7use crate::{HeapValue, ReflectError, ReflectErrorKind};
8
9use super::Poke;
10
11/// Lets you mutate a dynamic value (implements mutable operations for DynamicValue types).
12///
13/// This is used for types like `facet_value::Value` that can hold any of:
14/// null, bool, number, string, bytes, array, or object - determined at runtime.
15///
16/// The setter methods (`set_null`, `set_bool`, etc.) drop the previous value and
17/// re-initialize the storage with the new kind.
18pub struct PokeDynamicValue<'mem, 'facet> {
19    pub(crate) value: Poke<'mem, 'facet>,
20    pub(crate) def: DynamicValueDef,
21}
22
23impl<'mem, 'facet> core::fmt::Debug for PokeDynamicValue<'mem, 'facet> {
24    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
25        f.debug_struct("PokeDynamicValue")
26            .field("kind", &self.kind())
27            .finish_non_exhaustive()
28    }
29}
30
31impl<'mem, 'facet> PokeDynamicValue<'mem, 'facet> {
32    /// Creates a new poke dynamic value.
33    ///
34    /// # Safety
35    ///
36    /// The caller must ensure that `def` contains valid vtable function pointers that
37    /// correctly implement the dynamic-value operations for the actual type.
38    #[inline]
39    pub const unsafe fn new(value: Poke<'mem, 'facet>, def: DynamicValueDef) -> Self {
40        Self { value, def }
41    }
42
43    /// Returns the dynamic value definition.
44    #[inline(always)]
45    pub const fn def(&self) -> DynamicValueDef {
46        self.def
47    }
48
49    /// Returns the underlying `Poke` as a read-only `Peek`.
50    #[inline]
51    pub fn as_peek(&self) -> crate::Peek<'_, 'facet> {
52        self.value.as_peek()
53    }
54
55    /// Returns the kind of value stored.
56    #[inline]
57    pub fn kind(&self) -> DynValueKind {
58        unsafe { (self.def.vtable.get_kind)(self.value.data()) }
59    }
60
61    /// Returns true if the value is null.
62    #[inline]
63    pub fn is_null(&self) -> bool {
64        self.kind() == DynValueKind::Null
65    }
66
67    /// Returns the boolean value if this is a bool, `None` otherwise.
68    #[inline]
69    pub fn as_bool(&self) -> Option<bool> {
70        unsafe { (self.def.vtable.get_bool)(self.value.data()) }
71    }
72
73    /// Returns the i64 value if representable, `None` otherwise.
74    #[inline]
75    pub fn as_i64(&self) -> Option<i64> {
76        unsafe { (self.def.vtable.get_i64)(self.value.data()) }
77    }
78
79    /// Returns the u64 value if representable, `None` otherwise.
80    #[inline]
81    pub fn as_u64(&self) -> Option<u64> {
82        unsafe { (self.def.vtable.get_u64)(self.value.data()) }
83    }
84
85    /// Returns the f64 value if this is a number, `None` otherwise.
86    #[inline]
87    pub fn as_f64(&self) -> Option<f64> {
88        unsafe { (self.def.vtable.get_f64)(self.value.data()) }
89    }
90
91    /// Returns the string value if this is a string, `None` otherwise.
92    #[inline]
93    pub fn as_str(&self) -> Option<&str> {
94        unsafe { (self.def.vtable.get_str)(self.value.data()) }
95    }
96
97    /// Returns the bytes value if this is bytes, `None` otherwise.
98    #[inline]
99    pub fn as_bytes(&self) -> Option<&[u8]> {
100        self.def
101            .vtable
102            .get_bytes
103            .and_then(|f| unsafe { f(self.value.data()) })
104    }
105
106    /// Returns the length of the array if this is an array, `None` otherwise.
107    #[inline]
108    pub fn array_len(&self) -> Option<usize> {
109        unsafe { (self.def.vtable.array_len)(self.value.data()) }
110    }
111
112    /// Returns the length of the object if this is an object, `None` otherwise.
113    #[inline]
114    pub fn object_len(&self) -> Option<usize> {
115        unsafe { (self.def.vtable.object_len)(self.value.data()) }
116    }
117
118    /// Helper: drop the existing value and return a `PtrUninit` to the same location.
119    #[inline]
120    unsafe fn drop_and_as_uninit(&mut self) -> PtrUninit {
121        unsafe { self.value.shape.call_drop_in_place(self.value.data_mut()) };
122        PtrUninit::new(self.value.data_mut().as_mut_byte_ptr())
123    }
124
125    /// Replace the value with `null`, dropping the previous contents.
126    pub fn set_null(&mut self) {
127        unsafe {
128            let uninit = self.drop_and_as_uninit();
129            (self.def.vtable.set_null)(uninit);
130        }
131    }
132
133    /// Replace the value with a boolean, dropping the previous contents.
134    pub fn set_bool(&mut self, v: bool) {
135        unsafe {
136            let uninit = self.drop_and_as_uninit();
137            (self.def.vtable.set_bool)(uninit, v);
138        }
139    }
140
141    /// Replace the value with an i64, dropping the previous contents.
142    pub fn set_i64(&mut self, v: i64) {
143        unsafe {
144            let uninit = self.drop_and_as_uninit();
145            (self.def.vtable.set_i64)(uninit, v);
146        }
147    }
148
149    /// Replace the value with a u64, dropping the previous contents.
150    pub fn set_u64(&mut self, v: u64) {
151        unsafe {
152            let uninit = self.drop_and_as_uninit();
153            (self.def.vtable.set_u64)(uninit, v);
154        }
155    }
156
157    /// Replace the value with an f64, dropping the previous contents.
158    ///
159    /// Returns `false` if the value is not representable by the underlying type.
160    pub fn set_f64(&mut self, v: f64) -> bool {
161        unsafe {
162            let uninit = self.drop_and_as_uninit();
163            (self.def.vtable.set_f64)(uninit, v)
164        }
165    }
166
167    /// Replace the value with a string, dropping the previous contents.
168    pub fn set_str(&mut self, v: &str) {
169        unsafe {
170            let uninit = self.drop_and_as_uninit();
171            (self.def.vtable.set_str)(uninit, v);
172        }
173    }
174
175    /// Replace the value with a byte slice, dropping the previous contents.
176    ///
177    /// Returns `false` if the underlying dynamic value type doesn't support bytes.
178    pub fn set_bytes(&mut self, v: &[u8]) -> bool {
179        let Some(set_bytes) = self.def.vtable.set_bytes else {
180            return false;
181        };
182        unsafe {
183            let uninit = self.drop_and_as_uninit();
184            set_bytes(uninit, v);
185        }
186        true
187    }
188
189    /// Replace the value with an empty array, dropping the previous contents.
190    pub fn set_array(&mut self) {
191        unsafe {
192            let uninit = self.drop_and_as_uninit();
193            (self.def.vtable.begin_array)(uninit);
194        }
195    }
196
197    /// Replace the value with an empty object, dropping the previous contents.
198    pub fn set_object(&mut self) {
199        unsafe {
200            let uninit = self.drop_and_as_uninit();
201            (self.def.vtable.begin_object)(uninit);
202        }
203    }
204
205    /// Push an element onto the array value.
206    ///
207    /// The value must already be an array (use [`set_array`](Self::set_array) first if needed).
208    /// The element's shape must match this dynamic value's shape — a nested element is itself
209    /// a full dynamic value of the same kind (e.g. another `facet_value::Value`).
210    ///
211    /// The element is moved into the array (the vtable does the `ptr::read`); the caller's
212    /// original ownership of `element` is consumed by this call.
213    pub fn push_array_element<T: Facet<'facet>>(&mut self, element: T) -> Result<(), ReflectError> {
214        if self.value.shape != T::SHAPE {
215            return Err(self.value.err(ReflectErrorKind::WrongShape {
216                expected: self.value.shape,
217                actual: T::SHAPE,
218            }));
219        }
220        let mut element = ManuallyDrop::new(element);
221        unsafe {
222            let elem_ptr = PtrMut::new(&mut element as *mut ManuallyDrop<T> as *mut u8);
223            (self.def.vtable.push_array_element)(self.value.data_mut(), elem_ptr);
224        }
225        Ok(())
226    }
227
228    /// Type-erased [`push_array_element`](Self::push_array_element).
229    ///
230    /// Accepts a [`HeapValue`] whose shape must match this dynamic value's shape.
231    pub fn push_array_element_from_heap<const BORROW: bool>(
232        &mut self,
233        element: HeapValue<'facet, BORROW>,
234    ) -> Result<(), ReflectError> {
235        if self.value.shape != element.shape() {
236            return Err(self.value.err(ReflectErrorKind::WrongShape {
237                expected: self.value.shape,
238                actual: element.shape(),
239            }));
240        }
241        let mut element = element;
242        let guard = element
243            .guard
244            .take()
245            .expect("HeapValue guard was already taken");
246        unsafe {
247            let elem_ptr = PtrMut::new(guard.ptr.as_ptr());
248            (self.def.vtable.push_array_element)(self.value.data_mut(), elem_ptr);
249        }
250        drop(guard);
251        Ok(())
252    }
253
254    /// Finalize an array value. No-op if the underlying dynamic-value type doesn't need it.
255    pub fn end_array(&mut self) {
256        if let Some(end_array) = self.def.vtable.end_array {
257            unsafe { end_array(self.value.data_mut()) };
258        }
259    }
260
261    /// Insert a key-value pair into the object value.
262    ///
263    /// The value must already be an object (use [`set_object`](Self::set_object) first if needed).
264    /// The value's shape must match this dynamic value's shape — a nested value is itself a full
265    /// dynamic value of the same kind.
266    ///
267    /// `value` is moved into the object (the vtable does the `ptr::read`).
268    pub fn insert_object_entry<T: Facet<'facet>>(
269        &mut self,
270        key: &str,
271        value: T,
272    ) -> Result<(), ReflectError> {
273        if self.value.shape != T::SHAPE {
274            return Err(self.value.err(ReflectErrorKind::WrongShape {
275                expected: self.value.shape,
276                actual: T::SHAPE,
277            }));
278        }
279        let mut value = ManuallyDrop::new(value);
280        unsafe {
281            let value_ptr = PtrMut::new(&mut value as *mut ManuallyDrop<T> as *mut u8);
282            (self.def.vtable.insert_object_entry)(self.value.data_mut(), key, value_ptr);
283        }
284        Ok(())
285    }
286
287    /// Type-erased [`insert_object_entry`](Self::insert_object_entry).
288    ///
289    /// Accepts a [`HeapValue`] whose shape must match this dynamic value's shape.
290    pub fn insert_object_entry_from_heap<const BORROW: bool>(
291        &mut self,
292        key: &str,
293        value: HeapValue<'facet, BORROW>,
294    ) -> Result<(), ReflectError> {
295        if self.value.shape != value.shape() {
296            return Err(self.value.err(ReflectErrorKind::WrongShape {
297                expected: self.value.shape,
298                actual: value.shape(),
299            }));
300        }
301        let mut value = value;
302        let guard = value
303            .guard
304            .take()
305            .expect("HeapValue guard was already taken");
306        unsafe {
307            let value_ptr = PtrMut::new(guard.ptr.as_ptr());
308            (self.def.vtable.insert_object_entry)(self.value.data_mut(), key, value_ptr);
309        }
310        drop(guard);
311        Ok(())
312    }
313
314    /// Finalize an object value. No-op if the underlying dynamic-value type doesn't need it.
315    pub fn end_object(&mut self) {
316        if let Some(end_object) = self.def.vtable.end_object {
317            unsafe { end_object(self.value.data_mut()) };
318        }
319    }
320
321    /// Get a mutable `Poke` for the value at the given object key.
322    ///
323    /// Returns `None` if the dynamic value is not an object, the key is missing, or
324    /// `object_get_mut` is not implemented for this type.
325    #[inline]
326    pub fn object_get_mut(&mut self, key: &str) -> Option<Poke<'_, 'facet>> {
327        let object_get_mut = self.def.vtable.object_get_mut?;
328        let inner_ptr = unsafe { object_get_mut(self.value.data_mut(), key)? };
329        // Nested dynamic values share the outer shape.
330        Some(unsafe { Poke::from_raw_parts(inner_ptr, self.value.shape) })
331    }
332
333    /// Converts this `PokeDynamicValue` back into a `Poke`.
334    #[inline]
335    pub const fn into_inner(self) -> Poke<'mem, 'facet> {
336        self.value
337    }
338
339    /// Returns a read-only `PeekDynamicValue` view.
340    #[inline]
341    pub fn as_peek_dynamic_value(&self) -> crate::PeekDynamicValue<'_, 'facet> {
342        crate::PeekDynamicValue {
343            value: self.value.as_peek(),
344            def: self.def,
345        }
346    }
347}