1use 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
10unsafe 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 _ => VDateTime::new_local_datetime(year, month, day, hour, minute, second, nanos),
97 };
98 ptr.write(dt.into());
99 }
100}
101
102unsafe 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 let element_value = element_ptr.read();
120
121 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
129unsafe 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 let entry_value = value_ptr.read();
147
148 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
156unsafe 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 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 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
313static 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
350unsafe 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
399static 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
407static 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
426pub static VALUE_SHAPE: &Shape = <Value as Facet>::SHAPE;