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 };
95 ptr.write(dt.into());
96 }
97}
98
99unsafe fn dyn_begin_array(dst: PtrUninit) {
104 unsafe {
105 let ptr = dst.as_mut_byte_ptr() as *mut Value;
106 ptr.write(VArray::new().into_value());
107 }
108}
109
110unsafe fn dyn_push_array_element(array: PtrMut, element: PtrMut) {
111 unsafe {
112 let array_ptr = array.as_mut_byte_ptr() as *mut Value;
113 let element_ptr = element.as_mut_byte_ptr() as *mut Value;
114
115 let element_value = element_ptr.read();
117
118 let array_value = &mut *array_ptr;
120 if let Some(arr) = array_value.as_array_mut() {
121 arr.push(element_value);
122 }
123 }
124}
125
126unsafe fn dyn_begin_object(dst: PtrUninit) {
131 unsafe {
132 let ptr = dst.as_mut_byte_ptr() as *mut Value;
133 ptr.write(VObject::new().into_value());
134 }
135}
136
137unsafe fn dyn_insert_object_entry(object: PtrMut, key: &str, value: PtrMut) {
138 unsafe {
139 let object_ptr = object.as_mut_byte_ptr() as *mut Value;
140 let value_ptr = value.as_mut_byte_ptr() as *mut Value;
141
142 let entry_value = value_ptr.read();
144
145 let object_value = &mut *object_ptr;
147 if let Some(obj) = object_value.as_object_mut() {
148 obj.insert(key, entry_value);
149 }
150 }
151}
152
153unsafe fn dyn_get_kind(value: PtrConst) -> DynValueKind {
158 unsafe {
159 let ptr = value.as_byte_ptr() as *const Value;
160 let v = &*ptr;
161 match v.value_type() {
162 crate::ValueType::Null => DynValueKind::Null,
163 crate::ValueType::Bool => DynValueKind::Bool,
164 crate::ValueType::Number => DynValueKind::Number,
165 crate::ValueType::String => DynValueKind::String,
166 crate::ValueType::Bytes => DynValueKind::Bytes,
167 crate::ValueType::Array => DynValueKind::Array,
168 crate::ValueType::Object => DynValueKind::Object,
169 crate::ValueType::DateTime => DynValueKind::DateTime,
170 crate::ValueType::QName => DynValueKind::QName,
171 crate::ValueType::Uuid => DynValueKind::Uuid,
172 }
173 }
174}
175
176unsafe fn dyn_get_bool(value: PtrConst) -> Option<bool> {
177 unsafe {
178 let ptr = value.as_byte_ptr() as *const Value;
179 (*ptr).as_bool()
180 }
181}
182
183unsafe fn dyn_get_i64(value: PtrConst) -> Option<i64> {
184 unsafe {
185 let ptr = value.as_byte_ptr() as *const Value;
186 (*ptr).as_number().and_then(|n| n.to_i64())
187 }
188}
189
190unsafe fn dyn_get_u64(value: PtrConst) -> Option<u64> {
191 unsafe {
192 let ptr = value.as_byte_ptr() as *const Value;
193 (*ptr).as_number().and_then(|n| n.to_u64())
194 }
195}
196
197unsafe fn dyn_get_f64(value: PtrConst) -> Option<f64> {
198 unsafe {
199 let ptr = value.as_byte_ptr() as *const Value;
200 (*ptr).as_number().map(|n| n.to_f64_lossy())
201 }
202}
203
204unsafe fn dyn_get_str<'a>(value: PtrConst) -> Option<&'a str> {
205 unsafe {
206 let ptr = value.as_byte_ptr() as *const Value;
207 (*ptr).as_string().map(|s| s.as_str())
208 }
209}
210
211unsafe fn dyn_get_bytes<'a>(value: PtrConst) -> Option<&'a [u8]> {
212 unsafe {
213 let ptr = value.as_byte_ptr() as *const Value;
214 (*ptr).as_bytes().map(|b| b.as_slice())
215 }
216}
217
218#[allow(clippy::type_complexity)]
219unsafe fn dyn_get_datetime(
220 value: PtrConst,
221) -> Option<(i32, u8, u8, u8, u8, u8, u32, DynDateTimeKind)> {
222 unsafe {
223 let ptr = value.as_byte_ptr() as *const Value;
224 (*ptr).as_datetime().map(|dt| {
225 let kind = match dt.kind() {
226 DateTimeKind::Offset { offset_minutes } => {
227 DynDateTimeKind::Offset { offset_minutes }
228 }
229 DateTimeKind::LocalDateTime => DynDateTimeKind::LocalDateTime,
230 DateTimeKind::LocalDate => DynDateTimeKind::LocalDate,
231 DateTimeKind::LocalTime => DynDateTimeKind::LocalTime,
232 };
233 (
234 dt.year(),
235 dt.month(),
236 dt.day(),
237 dt.hour(),
238 dt.minute(),
239 dt.second(),
240 dt.nanos(),
241 kind,
242 )
243 })
244 }
245}
246
247unsafe fn dyn_array_len(value: PtrConst) -> Option<usize> {
248 unsafe {
249 let ptr = value.as_byte_ptr() as *const Value;
250 (*ptr).as_array().map(|a| a.len())
251 }
252}
253
254unsafe fn dyn_array_get(value: PtrConst, index: usize) -> Option<PtrConst> {
255 unsafe {
256 let ptr = value.as_byte_ptr() as *const Value;
257 (*ptr)
258 .as_array()
259 .and_then(|a| a.get(index).map(|elem| PtrConst::new(elem as *const Value)))
260 }
261}
262
263unsafe fn dyn_object_len(value: PtrConst) -> Option<usize> {
264 unsafe {
265 let ptr = value.as_byte_ptr() as *const Value;
266 (*ptr).as_object().map(|o| o.len())
267 }
268}
269
270unsafe fn dyn_object_get_entry<'a>(value: PtrConst, index: usize) -> Option<(&'a str, PtrConst)> {
271 unsafe {
272 let ptr = value.as_byte_ptr() as *const Value;
273 (*ptr).as_object().and_then(|o| {
274 o.iter()
275 .nth(index)
276 .map(|(k, v)| (k.as_str(), PtrConst::new(v as *const Value)))
277 })
278 }
279}
280
281unsafe fn dyn_object_get(value: PtrConst, key: &str) -> Option<PtrConst> {
282 unsafe {
283 let ptr = value.as_byte_ptr() as *const Value;
284 (*ptr)
285 .as_object()
286 .and_then(|o| o.get(key).map(|v| PtrConst::new(v as *const Value)))
287 }
288}
289
290unsafe fn dyn_object_get_mut(value: PtrMut, key: &str) -> Option<PtrMut> {
291 unsafe {
292 let ptr = value.as_mut_byte_ptr() as *mut Value;
293 (*ptr)
294 .as_object_mut()
295 .and_then(|o| o.get_mut(key).map(|v| PtrMut::new(v as *mut Value)))
296 }
297}
298
299static DYNAMIC_VALUE_VTABLE: DynamicValueVTable = DynamicValueVTable {
304 set_null: dyn_set_null,
305 set_bool: dyn_set_bool,
306 set_i64: dyn_set_i64,
307 set_u64: dyn_set_u64,
308 set_f64: dyn_set_f64,
309 set_str: dyn_set_str,
310 set_bytes: Some(dyn_set_bytes),
311 set_datetime: Some(dyn_set_datetime),
312 begin_array: dyn_begin_array,
313 push_array_element: dyn_push_array_element,
314 end_array: None,
315 begin_object: dyn_begin_object,
316 insert_object_entry: dyn_insert_object_entry,
317 end_object: None,
318 get_kind: dyn_get_kind,
319 get_bool: dyn_get_bool,
320 get_i64: dyn_get_i64,
321 get_u64: dyn_get_u64,
322 get_f64: dyn_get_f64,
323 get_str: dyn_get_str,
324 get_bytes: Some(dyn_get_bytes),
325 get_datetime: Some(dyn_get_datetime),
326 array_len: dyn_array_len,
327 array_get: dyn_array_get,
328 object_len: dyn_object_len,
329 object_get_entry: dyn_object_get_entry,
330 object_get: dyn_object_get,
331 object_get_mut: Some(dyn_object_get_mut),
332};
333
334static DYNAMIC_VALUE_DEF: DynamicValueDef = DynamicValueDef::new(&DYNAMIC_VALUE_VTABLE);
335
336unsafe fn value_drop_in_place(ox: OxPtrMut) {
339 unsafe {
340 let ptr = ox.ptr().as_mut_byte_ptr() as *mut Value;
341 core::ptr::drop_in_place(ptr);
342 }
343}
344
345unsafe fn value_clone_into(src: OxPtrConst, dst: OxPtrMut) {
346 unsafe {
347 let src_ptr = src.ptr().as_byte_ptr() as *const Value;
348 let dst_ptr = dst.ptr().as_mut_byte_ptr() as *mut Value;
349 dst_ptr.write((*src_ptr).clone());
350 }
351}
352
353unsafe fn value_debug(
354 ox: OxPtrConst,
355 f: &mut core::fmt::Formatter<'_>,
356) -> Option<core::fmt::Result> {
357 unsafe {
358 let ptr = ox.ptr().as_byte_ptr() as *const Value;
359 Some(core::fmt::Debug::fmt(&*ptr, f))
360 }
361}
362
363unsafe fn value_default_in_place(ox: OxPtrUninit) -> bool {
364 unsafe { ox.put(Value::default()) };
365 true
366}
367
368unsafe fn value_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
369 unsafe {
370 let a_ptr = a.ptr().as_byte_ptr() as *const Value;
371 let b_ptr = b.ptr().as_byte_ptr() as *const Value;
372 Some(*a_ptr == *b_ptr)
373 }
374}
375
376unsafe fn value_hash(ox: OxPtrConst, hasher: &mut facet_core::HashProxy<'_>) -> Option<()> {
377 unsafe {
378 use core::hash::Hash;
379 let ptr = ox.ptr().as_byte_ptr() as *const Value;
380 (*ptr).hash(hasher);
381 Some(())
382 }
383}
384
385static VALUE_VTABLE_INDIRECT: facet_core::VTableIndirect = facet_core::VTableIndirect {
387 debug: Some(value_debug),
388 partial_eq: Some(value_partial_eq),
389 hash: Some(value_hash),
390 ..facet_core::VTableIndirect::EMPTY
391};
392
393static VALUE_TYPE_OPS_INDIRECT: facet_core::TypeOpsIndirect = facet_core::TypeOpsIndirect {
395 drop_in_place: value_drop_in_place,
396 default_in_place: Some(value_default_in_place),
397 clone_into: Some(value_clone_into),
398 is_truthy: None,
399};
400
401unsafe impl Facet<'_> for Value {
402 const SHAPE: &'static Shape = &const {
403 ShapeBuilder::for_sized::<Value>("Value")
404 .vtable(VTableErased::Indirect(&VALUE_VTABLE_INDIRECT))
405 .type_ops(facet_core::TypeOps::Indirect(&VALUE_TYPE_OPS_INDIRECT))
406 .def(Def::DynamicValue(DYNAMIC_VALUE_DEF))
407 .doc(&[" A dynamic value that can hold null, bool, number, string, bytes, array, or object."])
408 .build()
409 };
410}
411
412pub static VALUE_SHAPE: &Shape = <Value as Facet>::SHAPE;