Skip to main content

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