facet_value/
facet_impl.rs

1//! Facet implementation for Value, enabling deserialization from any format.
2
3use facet_core::{
4    Def, DynDateTimeKind, DynValueKind, DynamicValueDef, DynamicValueVTable, Facet, OxPtrConst,
5    OxPtrMut, PtrConst, PtrMut, PtrUninit, Shape, ShapeBuilder, VTableErased,
6};
7
8use crate::{DateTimeKind, VArray, VBytes, VDateTime, VNumber, VObject, VString, Value};
9
10// ============================================================================
11// Scalar setters
12// ============================================================================
13
14unsafe fn dyn_set_null(dst: PtrUninit) {
15    unsafe {
16        let ptr = dst.as_mut_byte_ptr() as *mut Value;
17        ptr.write(Value::NULL);
18    }
19}
20
21unsafe fn dyn_set_bool(dst: PtrUninit, value: bool) {
22    unsafe {
23        let ptr = dst.as_mut_byte_ptr() as *mut Value;
24        ptr.write(Value::from(value));
25    }
26}
27
28unsafe fn dyn_set_i64(dst: PtrUninit, value: i64) {
29    unsafe {
30        let ptr = dst.as_mut_byte_ptr() as *mut Value;
31        ptr.write(VNumber::from_i64(value).into_value());
32    }
33}
34
35unsafe fn dyn_set_u64(dst: PtrUninit, value: u64) {
36    unsafe {
37        let ptr = dst.as_mut_byte_ptr() as *mut Value;
38        ptr.write(VNumber::from_u64(value).into_value());
39    }
40}
41
42unsafe fn dyn_set_f64(dst: PtrUninit, value: f64) -> bool {
43    unsafe {
44        let ptr = dst.as_mut_byte_ptr() as *mut Value;
45        match VNumber::from_f64(value) {
46            Some(num) => {
47                ptr.write(num.into_value());
48                true
49            }
50            None => {
51                // NaN or infinity - write null as fallback and return false
52                ptr.write(Value::NULL);
53                false
54            }
55        }
56    }
57}
58
59unsafe fn dyn_set_str(dst: PtrUninit, value: &str) {
60    unsafe {
61        let ptr = dst.as_mut_byte_ptr() as *mut Value;
62        ptr.write(VString::new(value).into_value());
63    }
64}
65
66unsafe fn dyn_set_bytes(dst: PtrUninit, value: &[u8]) {
67    unsafe {
68        let ptr = dst.as_mut_byte_ptr() as *mut Value;
69        ptr.write(VBytes::new(value).into_value());
70    }
71}
72
73#[allow(clippy::too_many_arguments)]
74unsafe fn dyn_set_datetime(
75    dst: PtrUninit,
76    year: i32,
77    month: u8,
78    day: u8,
79    hour: u8,
80    minute: u8,
81    second: u8,
82    nanos: u32,
83    kind: DynDateTimeKind,
84) {
85    unsafe {
86        let ptr = dst.as_mut_byte_ptr() as *mut Value;
87        let dt = match kind {
88            DynDateTimeKind::Offset { offset_minutes } => VDateTime::new_offset(
89                year,
90                month,
91                day,
92                hour,
93                minute,
94                second,
95                nanos,
96                offset_minutes,
97            ),
98            DynDateTimeKind::LocalDateTime => {
99                VDateTime::new_local_datetime(year, month, day, hour, minute, second, nanos)
100            }
101            DynDateTimeKind::LocalDate => VDateTime::new_local_date(year, month, day),
102            DynDateTimeKind::LocalTime => VDateTime::new_local_time(hour, minute, second, nanos),
103        };
104        ptr.write(dt.into());
105    }
106}
107
108// ============================================================================
109// Array operations
110// ============================================================================
111
112unsafe fn dyn_begin_array(dst: PtrUninit) {
113    unsafe {
114        let ptr = dst.as_mut_byte_ptr() as *mut Value;
115        ptr.write(VArray::new().into_value());
116    }
117}
118
119unsafe fn dyn_push_array_element(array: PtrMut, element: PtrMut) {
120    unsafe {
121        let array_ptr = array.as_mut_byte_ptr() as *mut Value;
122        let element_ptr = element.as_mut_byte_ptr() as *mut Value;
123
124        // Read the element (moving it out)
125        let element_value = element_ptr.read();
126
127        // Get the array and push
128        let array_value = &mut *array_ptr;
129        if let Some(arr) = array_value.as_array_mut() {
130            arr.push(element_value);
131        }
132    }
133}
134
135// ============================================================================
136// Object operations
137// ============================================================================
138
139unsafe fn dyn_begin_object(dst: PtrUninit) {
140    unsafe {
141        let ptr = dst.as_mut_byte_ptr() as *mut Value;
142        ptr.write(VObject::new().into_value());
143    }
144}
145
146unsafe fn dyn_insert_object_entry(object: PtrMut, key: &str, value: PtrMut) {
147    unsafe {
148        let object_ptr = object.as_mut_byte_ptr() as *mut Value;
149        let value_ptr = value.as_mut_byte_ptr() as *mut Value;
150
151        // Read the value (moving it out)
152        let entry_value = value_ptr.read();
153
154        // Get the object and insert
155        let object_value = &mut *object_ptr;
156        if let Some(obj) = object_value.as_object_mut() {
157            obj.insert(key, entry_value);
158        }
159    }
160}
161
162// ============================================================================
163// Read operations
164// ============================================================================
165
166unsafe fn dyn_get_kind(value: PtrConst) -> DynValueKind {
167    unsafe {
168        let ptr = value.as_byte_ptr() as *const Value;
169        let v = &*ptr;
170        match v.value_type() {
171            crate::ValueType::Null => DynValueKind::Null,
172            crate::ValueType::Bool => DynValueKind::Bool,
173            crate::ValueType::Number => DynValueKind::Number,
174            crate::ValueType::String => DynValueKind::String,
175            crate::ValueType::Bytes => DynValueKind::Bytes,
176            crate::ValueType::Array => DynValueKind::Array,
177            crate::ValueType::Object => DynValueKind::Object,
178            crate::ValueType::DateTime => DynValueKind::DateTime,
179            crate::ValueType::QName => DynValueKind::QName,
180            crate::ValueType::Uuid => DynValueKind::Uuid,
181        }
182    }
183}
184
185unsafe fn dyn_get_bool(value: PtrConst) -> Option<bool> {
186    unsafe {
187        let ptr = value.as_byte_ptr() as *const Value;
188        (*ptr).as_bool()
189    }
190}
191
192unsafe fn dyn_get_i64(value: PtrConst) -> Option<i64> {
193    unsafe {
194        let ptr = value.as_byte_ptr() as *const Value;
195        (*ptr).as_number().and_then(|n| n.to_i64())
196    }
197}
198
199unsafe fn dyn_get_u64(value: PtrConst) -> Option<u64> {
200    unsafe {
201        let ptr = value.as_byte_ptr() as *const Value;
202        (*ptr).as_number().and_then(|n| n.to_u64())
203    }
204}
205
206unsafe fn dyn_get_f64(value: PtrConst) -> Option<f64> {
207    unsafe {
208        let ptr = value.as_byte_ptr() as *const Value;
209        (*ptr).as_number().map(|n| n.to_f64_lossy())
210    }
211}
212
213unsafe fn dyn_get_str<'a>(value: PtrConst) -> Option<&'a str> {
214    unsafe {
215        let ptr = value.as_byte_ptr() as *const Value;
216        (*ptr).as_string().map(|s| s.as_str())
217    }
218}
219
220unsafe fn dyn_get_bytes<'a>(value: PtrConst) -> Option<&'a [u8]> {
221    unsafe {
222        let ptr = value.as_byte_ptr() as *const Value;
223        (*ptr).as_bytes().map(|b| b.as_slice())
224    }
225}
226
227#[allow(clippy::type_complexity)]
228unsafe fn dyn_get_datetime(
229    value: PtrConst,
230) -> Option<(i32, u8, u8, u8, u8, u8, u32, DynDateTimeKind)> {
231    unsafe {
232        let ptr = value.as_byte_ptr() as *const Value;
233        (*ptr).as_datetime().map(|dt| {
234            let kind = match dt.kind() {
235                DateTimeKind::Offset { offset_minutes } => {
236                    DynDateTimeKind::Offset { offset_minutes }
237                }
238                DateTimeKind::LocalDateTime => DynDateTimeKind::LocalDateTime,
239                DateTimeKind::LocalDate => DynDateTimeKind::LocalDate,
240                DateTimeKind::LocalTime => DynDateTimeKind::LocalTime,
241            };
242            (
243                dt.year(),
244                dt.month(),
245                dt.day(),
246                dt.hour(),
247                dt.minute(),
248                dt.second(),
249                dt.nanos(),
250                kind,
251            )
252        })
253    }
254}
255
256unsafe fn dyn_array_len(value: PtrConst) -> Option<usize> {
257    unsafe {
258        let ptr = value.as_byte_ptr() as *const Value;
259        (*ptr).as_array().map(|a| a.len())
260    }
261}
262
263unsafe fn dyn_array_get(value: PtrConst, index: usize) -> Option<PtrConst> {
264    unsafe {
265        let ptr = value.as_byte_ptr() as *const Value;
266        (*ptr)
267            .as_array()
268            .and_then(|a| a.get(index).map(|elem| PtrConst::new(elem as *const Value)))
269    }
270}
271
272unsafe fn dyn_object_len(value: PtrConst) -> Option<usize> {
273    unsafe {
274        let ptr = value.as_byte_ptr() as *const Value;
275        (*ptr).as_object().map(|o| o.len())
276    }
277}
278
279unsafe fn dyn_object_get_entry<'a>(value: PtrConst, index: usize) -> Option<(&'a str, PtrConst)> {
280    unsafe {
281        let ptr = value.as_byte_ptr() as *const Value;
282        (*ptr).as_object().and_then(|o| {
283            o.iter()
284                .nth(index)
285                .map(|(k, v)| (k.as_str(), PtrConst::new(v as *const Value)))
286        })
287    }
288}
289
290unsafe fn dyn_object_get(value: PtrConst, key: &str) -> Option<PtrConst> {
291    unsafe {
292        let ptr = value.as_byte_ptr() as *const Value;
293        (*ptr)
294            .as_object()
295            .and_then(|o| o.get(key).map(|v| PtrConst::new(v as *const Value)))
296    }
297}
298
299unsafe fn dyn_object_get_mut(value: PtrMut, key: &str) -> Option<PtrMut> {
300    unsafe {
301        let ptr = value.as_mut_byte_ptr() as *mut Value;
302        (*ptr)
303            .as_object_mut()
304            .and_then(|o| o.get_mut(key).map(|v| PtrMut::new(v as *mut Value)))
305    }
306}
307
308// ============================================================================
309// VTable and Shape
310// ============================================================================
311
312static DYNAMIC_VALUE_VTABLE: DynamicValueVTable = DynamicValueVTable {
313    set_null: dyn_set_null,
314    set_bool: dyn_set_bool,
315    set_i64: dyn_set_i64,
316    set_u64: dyn_set_u64,
317    set_f64: dyn_set_f64,
318    set_str: dyn_set_str,
319    set_bytes: Some(dyn_set_bytes),
320    set_datetime: Some(dyn_set_datetime),
321    begin_array: dyn_begin_array,
322    push_array_element: dyn_push_array_element,
323    end_array: None,
324    begin_object: dyn_begin_object,
325    insert_object_entry: dyn_insert_object_entry,
326    end_object: None,
327    get_kind: dyn_get_kind,
328    get_bool: dyn_get_bool,
329    get_i64: dyn_get_i64,
330    get_u64: dyn_get_u64,
331    get_f64: dyn_get_f64,
332    get_str: dyn_get_str,
333    get_bytes: Some(dyn_get_bytes),
334    get_datetime: Some(dyn_get_datetime),
335    array_len: dyn_array_len,
336    array_get: dyn_array_get,
337    object_len: dyn_object_len,
338    object_get_entry: dyn_object_get_entry,
339    object_get: dyn_object_get,
340    object_get_mut: Some(dyn_object_get_mut),
341};
342
343static DYNAMIC_VALUE_DEF: DynamicValueDef = DynamicValueDef::new(&DYNAMIC_VALUE_VTABLE);
344
345// Value vtable functions for the standard Facet machinery
346
347unsafe fn value_drop_in_place(ox: OxPtrMut) {
348    unsafe {
349        let ptr = ox.ptr().as_mut_byte_ptr() as *mut Value;
350        core::ptr::drop_in_place(ptr);
351    }
352}
353
354unsafe fn value_clone_into(src: OxPtrConst, dst: OxPtrMut) {
355    unsafe {
356        let src_ptr = src.ptr().as_byte_ptr() as *const Value;
357        let dst_ptr = dst.ptr().as_mut_byte_ptr() as *mut Value;
358        dst_ptr.write((*src_ptr).clone());
359    }
360}
361
362unsafe fn value_debug(
363    ox: OxPtrConst,
364    f: &mut core::fmt::Formatter<'_>,
365) -> Option<core::fmt::Result> {
366    unsafe {
367        let ptr = ox.ptr().as_byte_ptr() as *const Value;
368        Some(core::fmt::Debug::fmt(&*ptr, f))
369    }
370}
371
372unsafe fn value_default_in_place(ox: OxPtrMut) {
373    unsafe {
374        let ptr = ox.ptr().as_mut_byte_ptr() as *mut Value;
375        ptr.write(Value::default());
376    }
377}
378
379unsafe fn value_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
380    unsafe {
381        let a_ptr = a.ptr().as_byte_ptr() as *const Value;
382        let b_ptr = b.ptr().as_byte_ptr() as *const Value;
383        Some(*a_ptr == *b_ptr)
384    }
385}
386
387unsafe fn value_hash(ox: OxPtrConst, hasher: &mut facet_core::HashProxy<'_>) -> Option<()> {
388    unsafe {
389        use core::hash::Hash;
390        let ptr = ox.ptr().as_byte_ptr() as *const Value;
391        (*ptr).hash(hasher);
392        Some(())
393    }
394}
395
396// Use VTableIndirect for Value (trait operations)
397static VALUE_VTABLE_INDIRECT: facet_core::VTableIndirect = facet_core::VTableIndirect {
398    debug: Some(value_debug),
399    partial_eq: Some(value_partial_eq),
400    hash: Some(value_hash),
401    ..facet_core::VTableIndirect::EMPTY
402};
403
404// Use TypeOpsIndirect for Value (type operations)
405static VALUE_TYPE_OPS_INDIRECT: facet_core::TypeOpsIndirect = facet_core::TypeOpsIndirect {
406    drop_in_place: value_drop_in_place,
407    default_in_place: Some(value_default_in_place),
408    clone_into: Some(value_clone_into),
409    is_truthy: None,
410};
411
412unsafe impl Facet<'_> for Value {
413    const SHAPE: &'static Shape = &const {
414        ShapeBuilder::for_sized::<Value>("Value")
415            .vtable(VTableErased::Indirect(&VALUE_VTABLE_INDIRECT))
416            .type_ops(facet_core::TypeOps::Indirect(&VALUE_TYPE_OPS_INDIRECT))
417            .def(Def::DynamicValue(DYNAMIC_VALUE_DEF))
418            .doc(&[" A dynamic value that can hold null, bool, number, string, bytes, array, or object."])
419            .build()
420    };
421}
422
423/// The static shape for `Value`.
424pub static VALUE_SHAPE: &Shape = <Value as Facet>::SHAPE;