1#![allow(clippy::manual_map)]
2#[cfg(test)]
3#[path = "./value_tests.rs"]
4mod tests;
5use crate::{DateTime, Error, ErrorKind, Span, Table};
6use std::fmt;
7use std::mem::ManuallyDrop;
8
9pub use crate::array::Array;
11use crate::table::InnerTable;
13
14pub(crate) const TAG_MASK: u32 = 0x7;
15pub(crate) const TAG_SHIFT: u32 = 3;
16
17pub(crate) const TAG_STRING: u32 = 0;
18pub(crate) const TAG_INTEGER: u32 = 1;
19pub(crate) const TAG_FLOAT: u32 = 2;
20pub(crate) const TAG_BOOLEAN: u32 = 3;
21pub(crate) const TAG_ARRAY: u32 = 4;
22pub(crate) const TAG_TABLE: u32 = 5;
23pub(crate) const TAG_DATETIME: u32 = 6;
24
25pub(crate) const TAG_NONE: u32 = 7;
27
28pub(crate) const FLAG_MASK: u32 = 0x7;
32pub(crate) const FLAG_SHIFT: u32 = 3;
33
34pub(crate) const FLAG_NONE: u32 = 0;
35pub(crate) const FLAG_ARRAY: u32 = 2;
36pub(crate) const FLAG_AOT: u32 = 3;
37pub(crate) const FLAG_TABLE: u32 = 4;
38pub(crate) const FLAG_DOTTED: u32 = 5;
39pub(crate) const FLAG_HEADER: u32 = 6;
40pub(crate) const FLAG_FROZEN: u32 = 7;
41
42#[repr(C, align(8))]
43union Payload<'de> {
44 string: &'de str,
45 integer: i64,
46 float: f64,
47 boolean: bool,
48 array: ManuallyDrop<Array<'de>>,
49 table: ManuallyDrop<InnerTable<'de>>,
50 moment: DateTime,
51}
52
53#[repr(C)]
86pub struct Item<'de> {
87 payload: Payload<'de>,
88 start_and_tag: u32,
89 end_and_flag: u32,
90}
91
92const _: () = assert!(std::mem::size_of::<Item<'_>>() == 24);
93const _: () = assert!(std::mem::align_of::<Item<'_>>() == 8);
94
95impl<'de> Item<'de> {
96 #[inline]
97 fn raw(tag: u32, flag: u32, start: u32, end: u32, payload: Payload<'de>) -> Self {
98 Self {
99 start_and_tag: (start << TAG_SHIFT) | tag,
100 end_and_flag: (end << FLAG_SHIFT) | flag,
101 payload,
102 }
103 }
104
105 #[inline]
106 pub(crate) fn string(s: &'de str, span: Span) -> Self {
107 Self::raw(
108 TAG_STRING,
109 FLAG_NONE,
110 span.start,
111 span.end,
112 Payload { string: s },
113 )
114 }
115
116 #[inline]
117 pub(crate) fn integer(i: i64, span: Span) -> Self {
118 Self::raw(
119 TAG_INTEGER,
120 FLAG_NONE,
121 span.start,
122 span.end,
123 Payload { integer: i },
124 )
125 }
126
127 #[inline]
128 pub(crate) fn float(f: f64, span: Span) -> Self {
129 Self::raw(
130 TAG_FLOAT,
131 FLAG_NONE,
132 span.start,
133 span.end,
134 Payload { float: f },
135 )
136 }
137
138 #[inline]
139 pub(crate) fn boolean(b: bool, span: Span) -> Self {
140 Self::raw(
141 TAG_BOOLEAN,
142 FLAG_NONE,
143 span.start,
144 span.end,
145 Payload { boolean: b },
146 )
147 }
148
149 #[inline]
150 pub(crate) fn array(a: Array<'de>, span: Span) -> Self {
151 Self::raw(
152 TAG_ARRAY,
153 FLAG_ARRAY,
154 span.start,
155 span.end,
156 Payload {
157 array: ManuallyDrop::new(a),
158 },
159 )
160 }
161
162 #[inline]
163 pub(crate) fn table(t: InnerTable<'de>, span: Span) -> Self {
164 Self::raw(
165 TAG_TABLE,
166 FLAG_TABLE,
167 span.start,
168 span.end,
169 Payload {
170 table: ManuallyDrop::new(t),
171 },
172 )
173 }
174
175 #[inline]
177 pub(crate) fn array_aot(a: Array<'de>, span: Span) -> Self {
178 Self::raw(
179 TAG_ARRAY,
180 FLAG_AOT,
181 span.start,
182 span.end,
183 Payload {
184 array: ManuallyDrop::new(a),
185 },
186 )
187 }
188
189 #[inline]
191 pub(crate) fn table_frozen(t: InnerTable<'de>, span: Span) -> Self {
192 Self::raw(
193 TAG_TABLE,
194 FLAG_FROZEN,
195 span.start,
196 span.end,
197 Payload {
198 table: ManuallyDrop::new(t),
199 },
200 )
201 }
202
203 #[inline]
205 pub(crate) fn table_header(t: InnerTable<'de>, span: Span) -> Self {
206 Self::raw(
207 TAG_TABLE,
208 FLAG_HEADER,
209 span.start,
210 span.end,
211 Payload {
212 table: ManuallyDrop::new(t),
213 },
214 )
215 }
216
217 #[inline]
219 pub(crate) fn table_dotted(t: InnerTable<'de>, span: Span) -> Self {
220 Self::raw(
221 TAG_TABLE,
222 FLAG_DOTTED,
223 span.start,
224 span.end,
225 Payload {
226 table: ManuallyDrop::new(t),
227 },
228 )
229 }
230
231 #[inline]
232 pub(crate) fn moment(m: DateTime, span: Span) -> Self {
233 Self::raw(
234 TAG_DATETIME,
235 FLAG_NONE,
236 span.start,
237 span.end,
238 Payload { moment: m },
239 )
240 }
241}
242#[derive(Clone, Copy)]
246#[repr(u8)]
247#[allow(unused)]
248pub enum Kind {
249 String = 0,
250 Integer = 1,
251 Float = 2,
252 Boolean = 3,
253 Array = 4,
254 Table = 5,
255 DateTime = 6,
256}
257
258impl std::fmt::Debug for Kind {
259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260 self.as_str().fmt(f)
261 }
262}
263
264impl std::fmt::Display for Kind {
265 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
266 self.as_str().fmt(f)
267 }
268}
269
270impl Kind {
271 pub fn as_str(self) -> &'static str {
273 match self {
274 Kind::String => "string",
275 Kind::Integer => "integer",
276 Kind::Float => "float",
277 Kind::Boolean => "boolean",
278 Kind::Array => "array",
279 Kind::Table => "table",
280 Kind::DateTime => "datetime",
281 }
282 }
283}
284
285impl<'de> Item<'de> {
286 #[inline]
287 pub fn kind(&self) -> Kind {
288 debug_assert!((self.start_and_tag & TAG_MASK) as u8 <= Kind::DateTime as u8);
289 unsafe { std::mem::transmute::<u8, Kind>(self.start_and_tag as u8 & 0x7) }
292 }
293 #[inline]
294 pub(crate) fn tag(&self) -> u32 {
295 self.start_and_tag & TAG_MASK
296 }
297
298 #[inline]
299 pub(crate) fn flag(&self) -> u32 {
300 self.end_and_flag & FLAG_MASK
301 }
302
303 #[inline]
305 pub fn span(&self) -> Span {
306 Span::new(
307 self.start_and_tag >> TAG_SHIFT,
308 self.end_and_flag >> FLAG_SHIFT,
309 )
310 }
311
312 #[inline]
314 pub fn type_str(&self) -> &'static str {
315 match self.kind() {
316 Kind::String => "string",
317 Kind::Integer => "integer",
318 Kind::Float => "float",
319 Kind::Boolean => "boolean",
320 Kind::Array => "array",
321 Kind::Table => "table",
322 Kind::DateTime => "datetime",
323 }
324 }
325
326 #[inline]
327 pub(crate) fn is_table(&self) -> bool {
328 self.flag() >= FLAG_TABLE
329 }
330
331 #[inline]
332 pub(crate) fn is_array(&self) -> bool {
333 self.flag() & 6 == 2
334 }
335
336 #[inline]
337 pub(crate) fn is_frozen(&self) -> bool {
338 self.flag() == FLAG_FROZEN
339 }
340
341 #[inline]
342 pub(crate) fn is_aot(&self) -> bool {
343 self.flag() == FLAG_AOT
344 }
345
346 #[inline]
347 pub(crate) fn has_header_bit(&self) -> bool {
348 self.flag() == FLAG_HEADER
349 }
350
351 #[inline]
352 pub(crate) fn has_dotted_bit(&self) -> bool {
353 self.flag() == FLAG_DOTTED
354 }
355
356 #[inline]
362 pub(crate) unsafe fn split_array_end_flag(&mut self) -> (&mut u32, &mut Array<'de>) {
363 debug_assert!(self.is_array());
364 let ptr = self as *mut Item<'de>;
365 unsafe {
369 let end_flag = &mut *std::ptr::addr_of_mut!((*ptr).end_and_flag);
370 let array = &mut *std::ptr::addr_of_mut!((*ptr).payload.array).cast::<Array<'de>>();
371 (end_flag, array)
372 }
373 }
374}
375
376#[derive(Debug)]
394pub enum Value<'a, 'de> {
395 String(&'a &'de str),
397 Integer(&'a i64),
399 Float(&'a f64),
401 Boolean(&'a bool),
403 Array(&'a Array<'de>),
405 Table(&'a Table<'de>),
407 DateTime(&'a DateTime),
409}
410
411pub enum ValueMut<'a, 'de> {
415 String(&'a mut &'de str),
417 Integer(&'a mut i64),
419 Float(&'a mut f64),
421 Boolean(&'a mut bool),
423 Array(&'a mut Array<'de>),
425 Table(&'a mut Table<'de>),
427 DateTime(&'a DateTime),
429}
430
431impl<'de> Item<'de> {
432 #[inline(never)]
434 pub fn value(&self) -> Value<'_, 'de> {
435 unsafe {
438 match self.kind() {
439 Kind::String => Value::String(&self.payload.string),
440 Kind::Integer => Value::Integer(&self.payload.integer),
441 Kind::Float => Value::Float(&self.payload.float),
442 Kind::Boolean => Value::Boolean(&self.payload.boolean),
443 Kind::Array => Value::Array(&self.payload.array),
444 Kind::Table => Value::Table(self.as_table_unchecked()),
445 Kind::DateTime => Value::DateTime(&self.payload.moment),
446 }
447 }
448 }
449
450 #[inline(never)]
452 pub fn value_mut(&mut self) -> ValueMut<'_, 'de> {
453 unsafe {
456 match self.kind() {
457 Kind::String => ValueMut::String(&mut self.payload.string),
458 Kind::Integer => ValueMut::Integer(&mut self.payload.integer),
459 Kind::Float => ValueMut::Float(&mut self.payload.float),
460 Kind::Boolean => ValueMut::Boolean(&mut self.payload.boolean),
461 Kind::Array => ValueMut::Array(&mut self.payload.array),
462 Kind::Table => ValueMut::Table(self.as_table_mut_unchecked()),
463 Kind::DateTime => ValueMut::DateTime(&self.payload.moment),
464 }
465 }
466 }
467}
468
469impl<'de> Item<'de> {
470 #[inline]
472 pub fn as_str(&self) -> Option<&str> {
473 if self.tag() == TAG_STRING {
474 Some(unsafe { self.payload.string })
476 } else {
477 None
478 }
479 }
480
481 #[inline]
483 pub fn as_i64(&self) -> Option<i64> {
484 if self.tag() == TAG_INTEGER {
485 Some(unsafe { self.payload.integer })
487 } else {
488 None
489 }
490 }
491
492 #[inline]
497 pub fn as_f64(&self) -> Option<f64> {
498 match self.value() {
499 Value::Float(f) => Some(*f),
500 Value::Integer(i) => Some(*i as f64),
501 _ => None,
502 }
503 }
504
505 #[inline]
507 pub fn as_bool(&self) -> Option<bool> {
508 if self.tag() == TAG_BOOLEAN {
509 Some(unsafe { self.payload.boolean })
511 } else {
512 None
513 }
514 }
515
516 #[inline]
518 pub fn as_array(&self) -> Option<&Array<'de>> {
519 if self.tag() == TAG_ARRAY {
520 Some(unsafe { &self.payload.array })
522 } else {
523 None
524 }
525 }
526
527 #[inline]
529 pub fn as_table(&self) -> Option<&Table<'de>> {
530 if self.is_table() {
531 Some(unsafe { self.as_table_unchecked() })
533 } else {
534 None
535 }
536 }
537
538 #[inline]
540 pub fn as_datetime(&self) -> Option<&DateTime> {
541 if self.tag() == TAG_DATETIME {
542 Some(unsafe { &self.payload.moment })
544 } else {
545 None
546 }
547 }
548
549 #[inline]
551 pub fn as_array_mut(&mut self) -> Option<&mut Array<'de>> {
552 if self.tag() == TAG_ARRAY {
553 Some(unsafe { &mut self.payload.array })
555 } else {
556 None
557 }
558 }
559
560 #[inline]
562 pub fn as_table_mut(&mut self) -> Option<&mut Table<'de>> {
563 if self.is_table() {
564 Some(unsafe { self.as_table_mut_unchecked() })
566 } else {
567 None
568 }
569 }
570
571 #[inline]
573 pub(crate) unsafe fn as_inner_table_mut_unchecked(&mut self) -> &mut InnerTable<'de> {
574 debug_assert!(self.is_table());
575 unsafe { &mut self.payload.table }
576 }
577
578 #[inline]
583 pub(crate) unsafe fn as_table_mut_unchecked(&mut self) -> &mut Table<'de> {
584 debug_assert!(self.is_table());
585 unsafe { &mut *(self as *mut Item<'de>).cast::<Table<'de>>() }
586 }
587
588 #[inline]
594 pub(crate) unsafe fn as_table_unchecked(&self) -> &Table<'de> {
595 debug_assert!(self.is_table());
596 unsafe { &*(self as *const Item<'de>).cast::<Table<'de>>() }
598 }
599
600 #[inline]
602 pub fn has_keys(&self) -> bool {
603 self.as_table().is_some_and(|t| !t.is_empty())
604 }
605
606 #[inline]
608 pub fn has_key(&self, key: &str) -> bool {
609 self.as_table().is_some_and(|t| t.contains_key(key))
610 }
611}
612
613impl<'de> Item<'de> {
614 #[inline]
616 pub fn expected(&self, expected: &'static str) -> Error {
617 Error {
618 kind: ErrorKind::Wanted {
619 expected,
620 found: self.type_str(),
621 },
622 span: self.span(),
623 }
624 }
625
626 #[inline]
630 pub fn parse<T>(&self) -> Result<T, Error>
631 where
632 T: std::str::FromStr,
633 <T as std::str::FromStr>::Err: std::fmt::Display,
634 {
635 let Some(s) = self.as_str() else {
636 return Err(self.expected("a string"));
637 };
638 match s.parse() {
639 Ok(v) => Ok(v),
640 Err(err) => Err(Error {
641 kind: ErrorKind::Custom(format!("failed to parse string: {err}").into()),
642 span: self.span(),
643 }),
644 }
645 }
646}
647
648impl fmt::Debug for Item<'_> {
649 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650 match self.value() {
651 Value::String(s) => s.fmt(f),
652 Value::Integer(i) => i.fmt(f),
653 Value::Float(v) => v.fmt(f),
654 Value::Boolean(b) => b.fmt(f),
655 Value::Array(a) => a.fmt(f),
656 Value::Table(t) => t.fmt(f),
657 Value::DateTime(m) => {
658 let mut buf = std::mem::MaybeUninit::uninit();
659 f.write_str(m.format(&mut buf))
660 }
661 }
662 }
663}
664
665#[cfg(feature = "serde")]
666impl serde::Serialize for Item<'_> {
667 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
668 where
669 S: serde::Serializer,
670 {
671 match self.value() {
672 Value::String(s) => ser.serialize_str(s),
673 Value::Integer(i) => ser.serialize_i64(*i),
674 Value::Float(f) => ser.serialize_f64(*f),
675 Value::Boolean(b) => ser.serialize_bool(*b),
676 Value::Array(arr) => {
677 use serde::ser::SerializeSeq;
678 let mut seq = ser.serialize_seq(Some(arr.len()))?;
679 for ele in arr {
680 seq.serialize_element(ele)?;
681 }
682 seq.end()
683 }
684 Value::Table(tab) => {
685 use serde::ser::SerializeMap;
686 let mut map = ser.serialize_map(Some(tab.len()))?;
687 for (k, v) in tab {
688 map.serialize_entry(&*k.name, v)?;
689 }
690 map.end()
691 }
692 Value::DateTime(m) => {
693 let mut buf = std::mem::MaybeUninit::uninit();
694 ser.serialize_str(m.format(&mut buf))
695 }
696 }
697 }
698}
699
700#[cfg(feature = "serde")]
701impl serde::Serialize for InnerTable<'_> {
702 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
703 where
704 S: serde::Serializer,
705 {
706 use serde::ser::SerializeMap;
707 let mut map = ser.serialize_map(Some(self.len()))?;
708 for (k, v) in self.entries() {
709 map.serialize_entry(&*k.name, v)?;
710 }
711 map.end()
712 }
713}
714
715#[cfg(feature = "serde")]
716impl serde::Serialize for Table<'_> {
717 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
718 where
719 S: serde::Serializer,
720 {
721 self.value.serialize(ser)
722 }
723}
724
725#[derive(Copy, Clone)]
730pub struct Key<'de> {
731 pub name: &'de str,
733 pub span: Span,
735}
736impl<'de> Key<'de> {
737 pub fn as_str(&self) -> &'de str {
739 self.name
740 }
741}
742
743#[cfg(target_pointer_width = "64")]
744const _: () = assert!(std::mem::size_of::<Key<'_>>() == 24);
745
746impl std::borrow::Borrow<str> for Key<'_> {
747 fn borrow(&self) -> &str {
748 self.name
749 }
750}
751
752impl fmt::Debug for Key<'_> {
753 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
754 f.write_str(self.name)
755 }
756}
757
758impl fmt::Display for Key<'_> {
759 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
760 f.write_str(self.name)
761 }
762}
763
764impl Ord for Key<'_> {
765 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
766 self.name.cmp(other.name)
767 }
768}
769
770impl PartialOrd for Key<'_> {
771 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
772 Some(self.cmp(other))
773 }
774}
775
776impl PartialEq for Key<'_> {
777 fn eq(&self, other: &Self) -> bool {
778 self.name.eq(other.name)
779 }
780}
781
782impl Eq for Key<'_> {}
783
784impl<'de> std::ops::Index<&str> for Item<'de> {
785 type Output = MaybeItem<'de>;
786
787 #[inline]
788 fn index(&self, index: &str) -> &Self::Output {
789 if let Some(table) = self.as_table()
790 && let Some(item) = table.get(index)
791 {
792 return MaybeItem::from_ref(item);
793 }
794 &NONE
795 }
796}
797
798impl<'de> std::ops::Index<usize> for Item<'de> {
799 type Output = MaybeItem<'de>;
800
801 #[inline]
802 fn index(&self, index: usize) -> &Self::Output {
803 if let Some(arr) = self.as_array()
804 && let Some(item) = arr.get(index)
805 {
806 return MaybeItem::from_ref(item);
807 }
808 &NONE
809 }
810}
811
812impl<'de> std::ops::Index<&str> for MaybeItem<'de> {
813 type Output = MaybeItem<'de>;
814
815 #[inline]
816 fn index(&self, index: &str) -> &Self::Output {
817 if let Some(table) = self.as_table()
818 && let Some(item) = table.get(index)
819 {
820 return MaybeItem::from_ref(item);
821 }
822 &NONE
823 }
824}
825
826impl<'de> std::ops::Index<usize> for MaybeItem<'de> {
827 type Output = MaybeItem<'de>;
828
829 #[inline]
830 fn index(&self, index: usize) -> &Self::Output {
831 if let Some(arr) = self.as_array()
832 && let Some(item) = arr.get(index)
833 {
834 return MaybeItem::from_ref(item);
835 }
836 &NONE
837 }
838}
839
840#[repr(C)]
876pub struct MaybeItem<'de> {
877 payload: Payload<'de>,
878 start_and_tag: u32,
879 end_and_flag: u32,
880}
881
882unsafe impl Sync for MaybeItem<'_> {}
889
890pub(crate) static NONE: MaybeItem<'static> = MaybeItem {
891 payload: Payload { integer: 0 },
892 start_and_tag: TAG_NONE,
893 end_and_flag: FLAG_NONE,
894};
895
896impl<'de> MaybeItem<'de> {
897 pub fn from_ref<'a>(item: &'a Item<'de>) -> &'a Self {
899 unsafe { &*(item as *const Item<'de>).cast::<MaybeItem<'de>>() }
903 }
904 #[inline]
905 pub(crate) fn tag(&self) -> u32 {
906 self.start_and_tag & TAG_MASK
907 }
908 pub fn item(&self) -> Option<&Item<'de>> {
910 if self.tag() != TAG_NONE {
911 Some(unsafe { &*(self as *const MaybeItem<'de>).cast::<Item<'de>>() })
914 } else {
915 None
916 }
917 }
918 #[inline]
920 pub fn as_str(&self) -> Option<&str> {
921 if self.tag() == TAG_STRING {
922 Some(unsafe { self.payload.string })
924 } else {
925 None
926 }
927 }
928
929 #[inline]
931 pub fn as_i64(&self) -> Option<i64> {
932 if self.tag() == TAG_INTEGER {
933 Some(unsafe { self.payload.integer })
935 } else {
936 None
937 }
938 }
939
940 #[inline]
945 pub fn as_f64(&self) -> Option<f64> {
946 self.item()?.as_f64()
947 }
948
949 #[inline]
951 pub fn as_bool(&self) -> Option<bool> {
952 if self.tag() == TAG_BOOLEAN {
953 Some(unsafe { self.payload.boolean })
955 } else {
956 None
957 }
958 }
959
960 #[inline]
962 pub fn as_array(&self) -> Option<&Array<'de>> {
963 if self.tag() == TAG_ARRAY {
964 Some(unsafe { &self.payload.array })
966 } else {
967 None
968 }
969 }
970
971 #[inline]
973 pub fn as_table(&self) -> Option<&Table<'de>> {
974 if self.tag() == TAG_TABLE {
975 Some(unsafe { &*(self as *const Self).cast::<Table<'de>>() })
979 } else {
980 None
981 }
982 }
983
984 #[inline]
986 pub fn as_datetime(&self) -> Option<&DateTime> {
987 if self.tag() == TAG_DATETIME {
988 Some(unsafe { &self.payload.moment })
990 } else {
991 None
992 }
993 }
994
995 pub fn span(&self) -> Option<Span> {
997 if let Some(item) = self.item() {
998 Some(item.span())
999 } else {
1000 None
1001 }
1002 }
1003
1004 pub fn value(&self) -> Option<Value<'_, 'de>> {
1006 if let Some(item) = self.item() {
1007 Some(item.value())
1008 } else {
1009 None
1010 }
1011 }
1012}