1#![allow(clippy::manual_map)]
2#[cfg(test)]
3#[path = "./value_tests.rs"]
4mod tests;
5
6pub(crate) mod array;
7pub(crate) mod table;
8#[cfg(feature = "to-toml")]
9mod to_toml;
10use crate::arena::Arena;
11use crate::error::{Error, ErrorKind};
12use crate::item::table::TableIndex;
13use crate::{DateTime, Span, Table};
14use std::fmt;
15use std::mem::ManuallyDrop;
16
17pub use array::Array;
18pub(crate) use array::InternalArray;
19use table::InnerTable;
20
21pub(crate) const TAG_MASK: u32 = 0x7;
22pub(crate) const TAG_SHIFT: u32 = 3;
23
24pub(crate) const TAG_STRING: u32 = 0;
25pub(crate) const TAG_INTEGER: u32 = 1;
26pub(crate) const TAG_FLOAT: u32 = 2;
27pub(crate) const TAG_BOOLEAN: u32 = 3;
28pub(crate) const TAG_DATETIME: u32 = 4;
29pub(crate) const TAG_TABLE: u32 = 5;
30pub(crate) const TAG_ARRAY: u32 = 6;
31
32pub(crate) const TAG_NONE: u32 = 7;
34
35pub(crate) const FLAG_MASK: u32 = 0x7;
39pub(crate) const FLAG_SHIFT: u32 = 3;
40
41pub(crate) const FLAG_NONE: u32 = 0;
42pub(crate) const FLAG_ARRAY: u32 = 2;
43pub(crate) const FLAG_AOT: u32 = 3;
44pub(crate) const FLAG_TABLE: u32 = 4;
45pub(crate) const FLAG_DOTTED: u32 = 5;
46pub(crate) const FLAG_HEADER: u32 = 6;
47pub(crate) const FLAG_FROZEN: u32 = 7;
48
49pub(crate) const HINTS_BIT: u32 = 1 << 31;
52pub(crate) const AUTO_STYLE_BIT: u32 = 1 << 26;
55const NOT_PROJECTED: u32 = !(TAG_MASK); #[derive(Copy, Clone)]
70#[repr(C)]
71pub struct ItemMetadata {
72 pub(crate) start_and_tag: u32,
73 pub(crate) end_and_flag: u32,
74}
75
76impl ItemMetadata {
77 #[inline]
79 pub(crate) fn spanned(tag: u32, flag: u32, start: u32, end: u32) -> Self {
80 Self {
81 start_and_tag: (start << TAG_SHIFT) | tag,
82 end_and_flag: (end << FLAG_SHIFT) | flag,
83 }
84 }
85
86 #[inline]
88 pub(crate) fn hints(tag: u32, flag: u32) -> Self {
89 Self {
90 start_and_tag: NOT_PROJECTED | tag,
91 end_and_flag: HINTS_BIT | flag,
92 }
93 }
94
95 #[inline]
96 pub(crate) fn tag(&self) -> u32 {
97 self.start_and_tag & TAG_MASK
98 }
99
100 #[inline]
101 pub(crate) fn flag(&self) -> u32 {
102 self.end_and_flag & FLAG_MASK
103 }
104
105 #[inline]
106 pub(crate) fn set_flag(&mut self, flag: u32) {
107 self.end_and_flag = (self.end_and_flag & !FLAG_MASK) | flag;
108 }
109
110 #[inline]
111 pub(crate) fn set_auto_style(&mut self) {
112 self.end_and_flag |= AUTO_STYLE_BIT;
113 }
114
115 #[inline]
116 #[allow(dead_code)]
117 pub(crate) fn is_auto_style(&self) -> bool {
118 self.end_and_flag & (HINTS_BIT | AUTO_STYLE_BIT) == (HINTS_BIT | AUTO_STYLE_BIT)
119 }
120
121 #[inline]
122 pub(crate) fn clear_auto_style(&mut self) {
123 self.end_and_flag &= !AUTO_STYLE_BIT;
124 }
125
126 #[inline]
128 pub(crate) fn is_span_mode(&self) -> bool {
129 (self.end_and_flag as i32) >= 0
130 }
131
132 #[inline]
134 pub fn span(&self) -> Span {
135 if (self.end_and_flag as i32) >= 0 {
136 self.span_unchecked()
137 } else {
138 Span { start: 0, end: 0 }
139 }
140 }
141
142 #[inline]
146 pub(crate) fn span_unchecked(&self) -> Span {
147 debug_assert!(self.is_span_mode());
148 Span::new(
149 self.start_and_tag >> TAG_SHIFT,
150 self.end_and_flag >> FLAG_SHIFT,
151 )
152 }
153
154 #[inline]
155 pub(crate) fn span_start(&self) -> u32 {
156 debug_assert!(self.is_span_mode());
157 self.start_and_tag >> TAG_SHIFT
158 }
159
160 #[inline]
161 pub(crate) fn set_span_start(&mut self, v: u32) {
162 debug_assert!(self.is_span_mode());
163 self.start_and_tag = (v << TAG_SHIFT) | (self.start_and_tag & TAG_MASK);
164 }
165
166 #[inline]
167 pub(crate) fn set_span_end(&mut self, v: u32) {
168 debug_assert!(self.is_span_mode());
169 self.end_and_flag = (v << FLAG_SHIFT) | (self.end_and_flag & FLAG_MASK);
170 }
171
172 #[inline]
173 pub(crate) fn extend_span_end(&mut self, new_end: u32) {
174 debug_assert!(self.is_span_mode());
175 let old = self.end_and_flag;
176 let current = old >> FLAG_SHIFT;
177 self.end_and_flag = (current.max(new_end) << FLAG_SHIFT) | (old & FLAG_MASK);
178 }
179}
180
181#[derive(Clone, Copy, Debug, PartialEq, Eq)]
183pub enum TableStyle {
184 Implicit,
186 Dotted,
188 Header,
190 Inline,
192}
193
194#[derive(Clone, Copy, Debug, PartialEq, Eq)]
196pub enum ArrayStyle {
197 Inline,
199 Header,
201}
202
203#[repr(C, packed)]
204#[derive(Clone, Copy)]
205struct PackedI128 {
206 value: i128,
207}
208
209#[repr(align(8))]
216#[derive(Clone, Copy)]
217pub struct Integer {
218 value: PackedI128,
219}
220
221impl Integer {
222 #[inline]
224 pub fn as_i128(&self) -> i128 {
225 let copy = *self;
226 copy.value.value
227 }
228
229 #[inline]
231 pub fn as_f64(&self) -> f64 {
232 let copy = *self;
233 copy.value.value as f64
234 }
235
236 #[inline]
238 pub fn as_i64(&self) -> Option<i64> {
239 i64::try_from(self.as_i128()).ok()
240 }
241
242 #[inline]
244 pub fn as_u64(&self) -> Option<u64> {
245 u64::try_from(self.as_i128()).ok()
246 }
247}
248
249impl From<i128> for Integer {
250 #[inline]
251 fn from(v: i128) -> Self {
252 Self {
253 value: PackedI128 { value: v },
254 }
255 }
256}
257
258impl From<i64> for Integer {
259 #[inline]
260 fn from(v: i64) -> Self {
261 Self::from(v as i128)
262 }
263}
264
265impl From<u64> for Integer {
266 #[inline]
267 fn from(v: u64) -> Self {
268 Self::from(v as i128)
269 }
270}
271
272impl From<i32> for Integer {
273 #[inline]
274 fn from(v: i32) -> Self {
275 Self::from(v as i128)
276 }
277}
278
279impl From<u32> for Integer {
280 #[inline]
281 fn from(v: u32) -> Self {
282 Self::from(v as i128)
283 }
284}
285
286impl PartialEq for Integer {
287 #[inline]
288 fn eq(&self, other: &Self) -> bool {
289 self.as_i128() == other.as_i128()
290 }
291}
292
293impl Eq for Integer {}
294
295impl fmt::Debug for Integer {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 self.as_i128().fmt(f)
298 }
299}
300
301impl fmt::Display for Integer {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 self.as_i128().fmt(f)
304 }
305}
306
307#[repr(C, align(8))]
308union Payload<'de> {
309 string: &'de str,
310 integer: Integer,
311 float: f64,
312 boolean: bool,
313 array: ManuallyDrop<InternalArray<'de>>,
314 table: ManuallyDrop<InnerTable<'de>>,
315 datetime: DateTime,
316}
317
318#[repr(C)]
348pub struct Item<'de> {
349 payload: Payload<'de>,
350 pub(crate) meta: ItemMetadata,
351}
352
353const _: () = assert!(std::mem::size_of::<Item<'_>>() == 24);
354const _: () = assert!(std::mem::align_of::<Item<'_>>() == 8);
355
356impl<'de> From<i64> for Item<'de> {
357 fn from(value: i64) -> Self {
358 Self::raw_hints(
359 TAG_INTEGER,
360 FLAG_NONE,
361 Payload {
362 integer: Integer::from(value),
363 },
364 )
365 }
366}
367impl<'de> From<i128> for Item<'de> {
368 fn from(value: i128) -> Self {
369 Self::raw_hints(
370 TAG_INTEGER,
371 FLAG_NONE,
372 Payload {
373 integer: Integer::from(value),
374 },
375 )
376 }
377}
378impl<'de> From<i32> for Item<'de> {
379 fn from(value: i32) -> Self {
380 Self::from(value as i64)
381 }
382}
383impl<'de> From<&'de str> for Item<'de> {
384 fn from(value: &'de str) -> Self {
385 Self::raw_hints(TAG_STRING, FLAG_NONE, Payload { string: value })
386 }
387}
388
389impl<'de> From<f64> for Item<'de> {
390 fn from(value: f64) -> Self {
391 Self::raw_hints(TAG_FLOAT, FLAG_NONE, Payload { float: value })
392 }
393}
394
395impl<'de> From<bool> for Item<'de> {
396 fn from(value: bool) -> Self {
397 Self::raw_hints(TAG_BOOLEAN, FLAG_NONE, Payload { boolean: value })
398 }
399}
400
401impl<'de> From<DateTime> for Item<'de> {
402 fn from(value: DateTime) -> Self {
403 Self::raw_hints(TAG_DATETIME, FLAG_NONE, Payload { datetime: value })
404 }
405}
406
407impl<'de> Item<'de> {
408 #[inline]
409 fn raw(tag: u32, flag: u32, start: u32, end: u32, payload: Payload<'de>) -> Self {
410 Self {
411 meta: ItemMetadata::spanned(tag, flag, start, end),
412 payload,
413 }
414 }
415
416 #[inline]
417 fn raw_hints(tag: u32, flag: u32, payload: Payload<'de>) -> Self {
418 Self {
419 meta: ItemMetadata::hints(tag, flag),
420 payload,
421 }
422 }
423
424 #[inline]
426 pub fn string(s: &'de str) -> Self {
427 Self::raw_hints(TAG_STRING, FLAG_NONE, Payload { string: s })
428 }
429
430 #[inline]
431 pub(crate) fn string_spanned(s: &'de str, span: Span) -> Self {
432 Self::raw(
433 TAG_STRING,
434 FLAG_NONE,
435 span.start,
436 span.end,
437 Payload { string: s },
438 )
439 }
440
441 #[inline]
442 pub(crate) fn integer_spanned(i: i128, span: Span) -> Self {
443 Self::raw(
444 TAG_INTEGER,
445 FLAG_NONE,
446 span.start,
447 span.end,
448 Payload {
449 integer: Integer::from(i),
450 },
451 )
452 }
453
454 #[inline]
455 pub(crate) fn float_spanned(f: f64, span: Span) -> Self {
456 Self::raw(
457 TAG_FLOAT,
458 FLAG_NONE,
459 span.start,
460 span.end,
461 Payload { float: f },
462 )
463 }
464
465 #[inline]
466 pub(crate) fn boolean(b: bool, span: Span) -> Self {
467 Self::raw(
468 TAG_BOOLEAN,
469 FLAG_NONE,
470 span.start,
471 span.end,
472 Payload { boolean: b },
473 )
474 }
475
476 #[inline]
477 pub(crate) fn array(a: InternalArray<'de>, span: Span) -> Self {
478 Self::raw(
479 TAG_ARRAY,
480 FLAG_ARRAY,
481 span.start,
482 span.end,
483 Payload {
484 array: ManuallyDrop::new(a),
485 },
486 )
487 }
488
489 #[inline]
490 pub(crate) fn table(t: InnerTable<'de>, span: Span) -> Self {
491 Self::raw(
492 TAG_TABLE,
493 FLAG_TABLE,
494 span.start,
495 span.end,
496 Payload {
497 table: ManuallyDrop::new(t),
498 },
499 )
500 }
501
502 #[inline]
504 pub(crate) fn array_aot(a: InternalArray<'de>, span: Span) -> Self {
505 Self::raw(
506 TAG_ARRAY,
507 FLAG_AOT,
508 span.start,
509 span.end,
510 Payload {
511 array: ManuallyDrop::new(a),
512 },
513 )
514 }
515
516 #[inline]
518 pub(crate) fn table_frozen(t: InnerTable<'de>, span: Span) -> Self {
519 Self::raw(
520 TAG_TABLE,
521 FLAG_FROZEN,
522 span.start,
523 span.end,
524 Payload {
525 table: ManuallyDrop::new(t),
526 },
527 )
528 }
529
530 #[inline]
532 pub(crate) fn table_header(t: InnerTable<'de>, span: Span) -> Self {
533 Self::raw(
534 TAG_TABLE,
535 FLAG_HEADER,
536 span.start,
537 span.end,
538 Payload {
539 table: ManuallyDrop::new(t),
540 },
541 )
542 }
543
544 #[inline]
546 pub(crate) fn table_dotted(t: InnerTable<'de>, span: Span) -> Self {
547 Self::raw(
548 TAG_TABLE,
549 FLAG_DOTTED,
550 span.start,
551 span.end,
552 Payload {
553 table: ManuallyDrop::new(t),
554 },
555 )
556 }
557
558 #[inline]
559 pub(crate) fn moment(m: DateTime, span: Span) -> Self {
560 Self::raw(
561 TAG_DATETIME,
562 FLAG_NONE,
563 span.start,
564 span.end,
565 Payload { datetime: m },
566 )
567 }
568}
569#[derive(Clone, Copy, PartialEq, Eq)]
573#[repr(u8)]
574#[allow(unused)]
575pub enum Kind {
576 String = 0,
577 Integer = 1,
578 Float = 2,
579 Boolean = 3,
580 DateTime = 4,
581 Table = 5,
582 Array = 6,
583}
584
585impl std::fmt::Debug for Kind {
586 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
587 self.as_str().fmt(f)
588 }
589}
590
591impl std::fmt::Display for Kind {
592 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
593 self.as_str().fmt(f)
594 }
595}
596
597impl Kind {
598 pub fn as_str(&self) -> &'static str {
600 match self {
601 Kind::String => "string",
602 Kind::Integer => "integer",
603 Kind::Float => "float",
604 Kind::Boolean => "boolean",
605 Kind::Array => "array",
606 Kind::Table => "table",
607 Kind::DateTime => "datetime",
608 }
609 }
610}
611
612impl<'de> Item<'de> {
613 #[inline]
615 pub fn kind(&self) -> Kind {
616 debug_assert!((self.meta.start_and_tag & TAG_MASK) as u8 <= Kind::Array as u8);
617 unsafe { std::mem::transmute::<u8, Kind>(self.meta.start_and_tag as u8 & 0x7) }
624 }
625 #[inline]
626 pub(crate) fn tag(&self) -> u32 {
627 self.meta.tag()
628 }
629
630 #[inline]
633 pub(crate) fn is_scalar(&self) -> bool {
634 self.tag() < TAG_TABLE
635 }
636
637 #[inline]
641 pub fn flag(&self) -> u32 {
642 self.meta.flag()
643 }
644
645 #[inline]
648 pub(crate) fn span_unchecked(&self) -> Span {
649 self.meta.span_unchecked()
650 }
651
652 #[inline]
655 pub fn span(&self) -> Span {
656 self.meta.span()
657 }
658
659 #[inline]
661 pub fn type_str(&self) -> &'static &'static str {
662 match self.kind() {
663 Kind::String => &"string",
664 Kind::Integer => &"integer",
665 Kind::Float => &"float",
666 Kind::Boolean => &"boolean",
667 Kind::Array => &"array",
668 Kind::Table => &"table",
669 Kind::DateTime => &"datetime",
670 }
671 }
672
673 #[inline]
674 pub(crate) fn is_table(&self) -> bool {
675 self.flag() >= FLAG_TABLE
676 }
677
678 #[inline]
679 pub(crate) fn is_array(&self) -> bool {
680 self.flag() & 6 == 2
681 }
682
683 #[inline]
684 pub(crate) fn is_frozen(&self) -> bool {
685 self.flag() == FLAG_FROZEN
686 }
687
688 #[inline]
689 pub(crate) fn is_aot(&self) -> bool {
690 self.flag() == FLAG_AOT
691 }
692
693 #[inline]
694 pub(crate) fn has_header_bit(&self) -> bool {
695 self.flag() == FLAG_HEADER
696 }
697
698 #[inline]
699 pub(crate) fn has_dotted_bit(&self) -> bool {
700 self.flag() == FLAG_DOTTED
701 }
702
703 #[inline]
708 pub(crate) fn is_implicit_table(&self) -> bool {
709 self.flag() == FLAG_TABLE
710 }
711
712 #[inline]
718 pub(crate) unsafe fn split_array_end_flag(&mut self) -> (&mut u32, &mut InternalArray<'de>) {
719 debug_assert!(self.is_array());
720 let ptr = self as *mut Item<'de>;
721 unsafe {
731 let end_flag = &mut *std::ptr::addr_of_mut!((*ptr).meta.end_and_flag);
732 let array =
733 &mut *std::ptr::addr_of_mut!((*ptr).payload.array).cast::<InternalArray<'de>>();
734 (end_flag, array)
735 }
736 }
737}
738
739#[derive(Debug)]
756pub enum Value<'a, 'de> {
757 String(&'a &'de str),
759 Integer(&'a Integer),
761 Float(&'a f64),
763 Boolean(&'a bool),
765 DateTime(&'a DateTime),
767 Table(&'a Table<'de>),
769 Array(&'a Array<'de>),
771}
772
773pub enum ValueMut<'a, 'de> {
777 String(&'a mut &'de str),
779 Integer(&'a mut Integer),
781 Float(&'a mut f64),
783 Boolean(&'a mut bool),
785 DateTime(&'a DateTime),
787 Table(&'a mut Table<'de>),
789 Array(&'a mut Array<'de>),
791}
792
793impl<'de> Item<'de> {
794 pub fn value(&self) -> Value<'_, 'de> {
796 unsafe {
799 match self.kind() {
800 Kind::String => Value::String(&self.payload.string),
801 Kind::Integer => Value::Integer(&self.payload.integer),
802 Kind::Float => Value::Float(&self.payload.float),
803 Kind::Boolean => Value::Boolean(&self.payload.boolean),
804 Kind::Array => Value::Array(self.as_array_unchecked()),
805 Kind::Table => Value::Table(self.as_table_unchecked()),
806 Kind::DateTime => Value::DateTime(&self.payload.datetime),
807 }
808 }
809 }
810
811 pub fn value_mut(&mut self) -> ValueMut<'_, 'de> {
813 unsafe {
816 match self.kind() {
817 Kind::String => ValueMut::String(&mut self.payload.string),
818 Kind::Integer => ValueMut::Integer(&mut self.payload.integer),
819 Kind::Float => ValueMut::Float(&mut self.payload.float),
820 Kind::Boolean => ValueMut::Boolean(&mut self.payload.boolean),
821 Kind::Array => ValueMut::Array(self.as_array_mut_unchecked()),
822 Kind::Table => ValueMut::Table(self.as_table_mut_unchecked()),
823 Kind::DateTime => ValueMut::DateTime(&self.payload.datetime),
824 }
825 }
826 }
827}
828
829impl<'de> Item<'de> {
830 #[inline]
832 pub fn as_str(&self) -> Option<&str> {
833 if self.tag() == TAG_STRING {
834 Some(unsafe { self.payload.string })
836 } else {
837 None
838 }
839 }
840
841 #[doc(hidden)]
842 pub fn with_style_of_array_or_table(mut self, style: TableStyle) -> Item<'de> {
844 match self.value_mut() {
845 ValueMut::Table(table) => table.set_style(style),
846 ValueMut::Array(array) => match style {
847 TableStyle::Header => array.set_style(ArrayStyle::Header),
848 TableStyle::Inline => array.set_style(ArrayStyle::Inline),
849 _ => (),
850 },
851 _ => (),
852 }
853 self
854 }
855
856 #[inline]
858 pub fn as_i128(&self) -> Option<i128> {
859 if self.tag() == TAG_INTEGER {
860 Some(unsafe { self.payload.integer.as_i128() })
862 } else {
863 None
864 }
865 }
866
867 #[inline]
869 pub fn as_i64(&self) -> Option<i64> {
870 if self.tag() == TAG_INTEGER {
871 unsafe { self.payload.integer.as_i64() }
873 } else {
874 None
875 }
876 }
877
878 #[inline]
880 pub fn as_u64(&self) -> Option<u64> {
881 if self.tag() == TAG_INTEGER {
882 unsafe { self.payload.integer.as_u64() }
884 } else {
885 None
886 }
887 }
888
889 #[inline]
894 pub fn as_f64(&self) -> Option<f64> {
895 match self.value() {
896 Value::Float(f) => Some(*f),
897 Value::Integer(i) => Some(i.as_i128() as f64),
898 _ => None,
899 }
900 }
901
902 #[inline]
904 pub fn as_bool(&self) -> Option<bool> {
905 if self.tag() == TAG_BOOLEAN {
906 Some(unsafe { self.payload.boolean })
908 } else {
909 None
910 }
911 }
912
913 #[inline]
915 pub fn as_array(&self) -> Option<&Array<'de>> {
916 if self.tag() == TAG_ARRAY {
917 Some(unsafe { self.as_array_unchecked() })
919 } else {
920 None
921 }
922 }
923
924 #[inline]
926 pub fn as_table(&self) -> Option<&Table<'de>> {
927 if self.is_table() {
928 Some(unsafe { self.as_table_unchecked() })
930 } else {
931 None
932 }
933 }
934
935 #[inline]
937 pub fn as_datetime(&self) -> Option<&DateTime> {
938 if self.tag() == TAG_DATETIME {
939 Some(unsafe { &self.payload.datetime })
941 } else {
942 None
943 }
944 }
945
946 #[inline]
948 pub fn as_array_mut(&mut self) -> Option<&mut Array<'de>> {
949 if self.tag() == TAG_ARRAY {
950 Some(unsafe { self.as_array_mut_unchecked() })
952 } else {
953 None
954 }
955 }
956
957 #[inline]
959 pub fn into_table(self) -> Option<Table<'de>> {
960 if self.is_table() {
961 Some(unsafe { std::mem::transmute::<Item<'de>, Table<'de>>(self) })
965 } else {
966 None
967 }
968 }
969
970 #[inline]
972 pub fn as_table_mut(&mut self) -> Option<&mut Table<'de>> {
973 if self.is_table() {
974 Some(unsafe { self.as_table_mut_unchecked() })
976 } else {
977 None
978 }
979 }
980
981 #[inline]
987 pub(crate) unsafe fn as_array_unchecked(&self) -> &Array<'de> {
988 debug_assert!(self.tag() == TAG_ARRAY);
989 unsafe { &*(self as *const Item<'de>).cast::<Array<'de>>() }
996 }
997
998 #[inline]
1004 pub(crate) unsafe fn as_array_mut_unchecked(&mut self) -> &mut Array<'de> {
1005 debug_assert!(self.tag() == TAG_ARRAY);
1006 unsafe { &mut *(self as *mut Item<'de>).cast::<Array<'de>>() }
1008 }
1009
1010 #[inline]
1016 pub(crate) unsafe fn as_inner_table_mut_unchecked(&mut self) -> &mut InnerTable<'de> {
1017 debug_assert!(self.is_table());
1018 unsafe { &mut self.payload.table }
1021 }
1022
1023 #[inline]
1029 pub(crate) unsafe fn as_table_mut_unchecked(&mut self) -> &mut Table<'de> {
1030 debug_assert!(self.is_table());
1031 unsafe { &mut *(self as *mut Item<'de>).cast::<Table<'de>>() }
1037 }
1038
1039 #[inline]
1045 pub(crate) unsafe fn as_table_unchecked(&self) -> &Table<'de> {
1046 debug_assert!(self.is_table());
1047 unsafe { &*(self as *const Item<'de>).cast::<Table<'de>>() }
1049 }
1050
1051 #[inline]
1053 pub fn has_keys(&self) -> bool {
1054 self.as_table().is_some_and(|t| !t.is_empty())
1055 }
1056
1057 #[inline]
1059 pub fn has_key(&self, key: &str) -> bool {
1060 self.as_table().is_some_and(|t| t.contains_key(key))
1061 }
1062
1063 pub fn clone_in(&self, arena: &'de Arena) -> Item<'de> {
1069 if self.is_scalar() {
1070 unsafe { std::ptr::read(self) }
1076 } else if self.tag() == TAG_ARRAY {
1077 let cloned = unsafe { self.payload.array.clone_in(arena) };
1080 Item {
1081 payload: Payload {
1082 array: ManuallyDrop::new(cloned),
1083 },
1084 meta: self.meta,
1085 }
1086 } else {
1087 let cloned = unsafe { self.payload.table.clone_in(arena) };
1091 Item {
1092 payload: Payload {
1093 table: ManuallyDrop::new(cloned),
1094 },
1095 meta: self.meta,
1096 }
1097 }
1098 }
1099}
1100
1101impl<'de> Item<'de> {
1102 #[inline]
1104 pub fn expected(&self, expected: &'static &'static str) -> Error {
1105 Error::new(
1106 ErrorKind::Wanted {
1107 expected,
1108 found: self.type_str(),
1109 },
1110 self.span_unchecked(),
1111 )
1112 }
1113
1114 #[inline]
1118 pub fn parse<T>(&self) -> Result<T, Error>
1119 where
1120 T: std::str::FromStr,
1121 <T as std::str::FromStr>::Err: std::fmt::Display,
1122 {
1123 let Some(s) = self.as_str() else {
1124 return Err(self.expected(&"a string"));
1125 };
1126 match s.parse() {
1127 Ok(v) => Ok(v),
1128 Err(err) => Err(Error::custom(
1129 format!("failed to parse string: {err}"),
1130 self.span_unchecked(),
1131 )),
1132 }
1133 }
1134}
1135
1136impl fmt::Debug for Item<'_> {
1137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1138 match self.value() {
1139 Value::String(s) => s.fmt(f),
1140 Value::Integer(i) => i.fmt(f),
1141 Value::Float(v) => v.fmt(f),
1142 Value::Boolean(b) => b.fmt(f),
1143 Value::Array(a) => a.fmt(f),
1144 Value::Table(t) => t.fmt(f),
1145 Value::DateTime(m) => {
1146 let mut buf = std::mem::MaybeUninit::uninit();
1147 f.write_str(m.format(&mut buf))
1148 }
1149 }
1150 }
1151}
1152
1153#[derive(Copy, Clone)]
1158pub struct Key<'de> {
1159 pub name: &'de str,
1161 pub span: Span,
1163}
1164
1165impl<'de> Key<'de> {
1166 pub fn new(value: &'de str) -> Self {
1171 Self {
1172 name: value,
1173 span: Span::default(),
1174 }
1175 }
1176 pub fn as_str(&self) -> &'de str {
1178 self.name
1179 }
1180}
1181
1182impl<'de> From<&'de str> for Key<'de> {
1183 fn from(value: &'de str) -> Self {
1184 Self::new(value)
1185 }
1186}
1187
1188#[cfg(target_pointer_width = "64")]
1189const _: () = assert!(std::mem::size_of::<Key<'_>>() == 24);
1190
1191impl std::borrow::Borrow<str> for Key<'_> {
1192 fn borrow(&self) -> &str {
1193 self.name
1194 }
1195}
1196
1197impl fmt::Debug for Key<'_> {
1198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1199 f.write_str(self.name)
1200 }
1201}
1202
1203impl fmt::Display for Key<'_> {
1204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1205 f.write_str(self.name)
1206 }
1207}
1208
1209impl Ord for Key<'_> {
1210 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1211 self.name.cmp(other.name)
1212 }
1213}
1214
1215impl PartialOrd for Key<'_> {
1216 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1217 Some(self.cmp(other))
1218 }
1219}
1220
1221impl PartialEq for Key<'_> {
1222 fn eq(&self, other: &Self) -> bool {
1223 self.name.eq(other.name)
1224 }
1225}
1226
1227impl Eq for Key<'_> {}
1228
1229impl std::hash::Hash for Key<'_> {
1230 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1231 self.name.hash(state);
1232 }
1233}
1234
1235pub(crate) fn equal_items(a: &Item<'_>, b: &Item<'_>, index: Option<&TableIndex<'_>>) -> bool {
1236 if a.kind() != b.kind() {
1237 return false;
1238 }
1239 unsafe {
1244 match a.kind() {
1245 Kind::String => a.payload.string == b.payload.string,
1246 Kind::Integer => a.payload.integer == b.payload.integer,
1247 Kind::Float => {
1248 let af = a.payload.float;
1249 let bf = b.payload.float;
1250 if af.is_nan() && bf.is_nan() {
1251 af.is_sign_negative() == bf.is_sign_negative()
1252 } else {
1253 af.to_bits() == bf.to_bits()
1254 }
1255 }
1256 Kind::Boolean => a.payload.boolean == b.payload.boolean,
1257 Kind::DateTime => a.payload.datetime == b.payload.datetime,
1258 Kind::Array => {
1259 let a = a.payload.array.as_slice();
1260 let b = b.payload.array.as_slice();
1261 if a.len() != b.len() {
1262 return false;
1263 }
1264 for i in 0..a.len() {
1265 if !equal_items(&*a.as_ptr().add(i), &*b.as_ptr().add(i), index) {
1266 return false;
1267 }
1268 }
1269 true
1270 }
1271 Kind::Table => {
1272 let tab_a = a.as_table_unchecked();
1273 let tab_b = b.as_table_unchecked();
1274 if tab_a.len() != tab_b.len() {
1275 return false;
1276 }
1277 for (key, val_a) in tab_a {
1278 let Some((_, val_b)) = tab_b.value.get_entry_with_maybe_index(key.name, index)
1279 else {
1280 return false;
1281 };
1282 if !equal_items(val_a, val_b, index) {
1283 return false;
1284 }
1285 }
1286 true
1287 }
1288 }
1289 }
1290}
1291
1292impl<'de> PartialEq for Item<'de> {
1293 fn eq(&self, other: &Self) -> bool {
1294 equal_items(self, other, None)
1295 }
1296}
1297
1298impl<'de> std::ops::Index<&str> for Item<'de> {
1299 type Output = MaybeItem<'de>;
1300
1301 #[inline]
1302 fn index(&self, index: &str) -> &Self::Output {
1303 if let Some(table) = self.as_table()
1304 && let Some(item) = table.get(index)
1305 {
1306 return MaybeItem::from_ref(item);
1307 }
1308 &NONE
1309 }
1310}
1311
1312impl<'de> std::ops::Index<usize> for Item<'de> {
1313 type Output = MaybeItem<'de>;
1314
1315 #[inline]
1316 fn index(&self, index: usize) -> &Self::Output {
1317 if let Some(arr) = self.as_array()
1318 && let Some(item) = arr.get(index)
1319 {
1320 return MaybeItem::from_ref(item);
1321 }
1322 &NONE
1323 }
1324}
1325
1326impl<'de> std::ops::Index<&str> for MaybeItem<'de> {
1327 type Output = MaybeItem<'de>;
1328
1329 #[inline]
1330 fn index(&self, index: &str) -> &Self::Output {
1331 if let Some(table) = self.as_table()
1332 && let Some(item) = table.get(index)
1333 {
1334 return MaybeItem::from_ref(item);
1335 }
1336 &NONE
1337 }
1338}
1339
1340impl<'de> std::ops::Index<usize> for MaybeItem<'de> {
1341 type Output = MaybeItem<'de>;
1342
1343 #[inline]
1344 fn index(&self, index: usize) -> &Self::Output {
1345 if let Some(arr) = self.as_array()
1346 && let Some(item) = arr.get(index)
1347 {
1348 return MaybeItem::from_ref(item);
1349 }
1350 &NONE
1351 }
1352}
1353
1354impl fmt::Debug for MaybeItem<'_> {
1355 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1356 match self.item() {
1357 Some(item) => item.fmt(f),
1358 None => f.write_str("None"),
1359 }
1360 }
1361}
1362
1363#[repr(C)]
1398pub struct MaybeItem<'de> {
1399 payload: Payload<'de>,
1400 meta: ItemMetadata,
1401}
1402
1403unsafe impl Sync for MaybeItem<'_> {}
1410
1411pub(crate) static NONE: MaybeItem<'static> = MaybeItem {
1412 payload: Payload {
1413 integer: Integer {
1414 value: PackedI128 { value: 0 },
1415 },
1416 },
1417 meta: ItemMetadata {
1418 start_and_tag: TAG_NONE,
1419 end_and_flag: FLAG_NONE,
1420 },
1421};
1422
1423impl<'de> MaybeItem<'de> {
1424 pub fn from_ref<'a>(item: &'a Item<'de>) -> &'a Self {
1426 unsafe { &*(item as *const Item<'de>).cast::<MaybeItem<'de>>() }
1430 }
1431 #[inline]
1432 pub(crate) fn tag(&self) -> u32 {
1433 self.meta.tag()
1434 }
1435 pub fn item(&self) -> Option<&Item<'de>> {
1437 if self.tag() != TAG_NONE {
1438 Some(unsafe { &*(self as *const MaybeItem<'de>).cast::<Item<'de>>() })
1441 } else {
1442 None
1443 }
1444 }
1445 #[inline]
1447 pub fn as_str(&self) -> Option<&str> {
1448 if self.tag() == TAG_STRING {
1449 Some(unsafe { self.payload.string })
1451 } else {
1452 None
1453 }
1454 }
1455
1456 #[inline]
1458 pub fn as_i128(&self) -> Option<i128> {
1459 if self.tag() == TAG_INTEGER {
1460 Some(unsafe { self.payload.integer.as_i128() })
1462 } else {
1463 None
1464 }
1465 }
1466
1467 #[inline]
1469 pub fn as_i64(&self) -> Option<i64> {
1470 if self.tag() == TAG_INTEGER {
1471 unsafe { self.payload.integer.as_i64() }
1473 } else {
1474 None
1475 }
1476 }
1477
1478 #[inline]
1480 pub fn as_u64(&self) -> Option<u64> {
1481 if self.tag() == TAG_INTEGER {
1482 unsafe { self.payload.integer.as_u64() }
1484 } else {
1485 None
1486 }
1487 }
1488
1489 #[inline]
1494 pub fn as_f64(&self) -> Option<f64> {
1495 self.item()?.as_f64()
1496 }
1497
1498 #[inline]
1500 pub fn as_bool(&self) -> Option<bool> {
1501 if self.tag() == TAG_BOOLEAN {
1502 Some(unsafe { self.payload.boolean })
1504 } else {
1505 None
1506 }
1507 }
1508
1509 #[inline]
1511 pub fn as_array(&self) -> Option<&Array<'de>> {
1512 if self.tag() == TAG_ARRAY {
1513 Some(unsafe { &*(self as *const Self).cast::<Array<'de>>() })
1517 } else {
1518 None
1519 }
1520 }
1521
1522 #[inline]
1524 pub fn as_table(&self) -> Option<&Table<'de>> {
1525 if self.tag() == TAG_TABLE {
1526 Some(unsafe { &*(self as *const Self).cast::<Table<'de>>() })
1530 } else {
1531 None
1532 }
1533 }
1534
1535 #[inline]
1537 pub fn as_datetime(&self) -> Option<&DateTime> {
1538 if self.tag() == TAG_DATETIME {
1539 Some(unsafe { &self.payload.datetime })
1541 } else {
1542 None
1543 }
1544 }
1545
1546 pub fn span(&self) -> Span {
1548 if let Some(item) = self.item() {
1549 item.span_unchecked()
1550 } else {
1551 Span::default()
1552 }
1553 }
1554
1555 pub fn value(&self) -> Option<Value<'_, 'de>> {
1557 if let Some(item) = self.item() {
1558 Some(item.value())
1559 } else {
1560 None
1561 }
1562 }
1563}