1#![allow(unsafe_code)]
2#![allow(clippy::manual_map)]
3#[cfg(test)]
4#[path = "./value_tests.rs"]
5mod tests;
6use crate::str::Str;
7use crate::{Error, ErrorKind, Span, Table};
8use std::fmt;
9use std::mem::ManuallyDrop;
10
11pub use crate::array::Array;
13use crate::table::InnerTable;
15
16pub(crate) const TAG_MASK: u32 = 0x7;
17pub(crate) const TAG_SHIFT: u32 = 3;
18
19pub(crate) const TAG_STRING: u32 = 0;
20pub(crate) const TAG_INTEGER: u32 = 1;
21pub(crate) const TAG_FLOAT: u32 = 2;
22pub(crate) const TAG_BOOLEAN: u32 = 3;
23pub(crate) const TAG_ARRAY: u32 = 4;
24pub(crate) const TAG_TABLE: u32 = 5;
25
26pub(crate) const TAG_NONE: u32 = 6;
28
29pub(crate) const FLAG_MASK: u32 = 0x7;
33pub(crate) const FLAG_SHIFT: u32 = 3;
34
35pub(crate) const FLAG_NONE: u32 = 0;
36pub(crate) const FLAG_ARRAY: u32 = 2;
37pub(crate) const FLAG_AOT: u32 = 3;
38pub(crate) const FLAG_TABLE: u32 = 4;
39pub(crate) const FLAG_DOTTED: u32 = 5;
40pub(crate) const FLAG_HEADER: u32 = 6;
41pub(crate) const FLAG_FROZEN: u32 = 7;
42
43#[repr(C)]
44union Payload<'de> {
45 string: Str<'de>,
46 integer: i64,
47 float: f64,
48 boolean: bool,
49 array: ManuallyDrop<Array<'de>>,
50 table: ManuallyDrop<InnerTable<'de>>,
51}
52
53#[repr(C)]
75pub struct Item<'de> {
76 payload: Payload<'de>,
77 start_and_tag: u32,
78 end_and_flag: u32,
79}
80
81const _: () = assert!(std::mem::size_of::<Item<'_>>() == 24);
82const _: () = assert!(std::mem::align_of::<Item<'_>>() == 8);
83
84impl<'de> Item<'de> {
85 #[inline]
86 fn raw(tag: u32, flag: u32, start: u32, end: u32, payload: Payload<'de>) -> Self {
87 Self {
88 start_and_tag: (start << TAG_SHIFT) | tag,
89 end_and_flag: (end << FLAG_SHIFT) | flag,
90 payload,
91 }
92 }
93
94 #[inline]
95 pub(crate) fn string(s: Str<'de>, span: Span) -> Self {
96 Self::raw(
97 TAG_STRING,
98 FLAG_NONE,
99 span.start,
100 span.end,
101 Payload { string: s },
102 )
103 }
104
105 #[inline]
106 pub(crate) fn integer(i: i64, span: Span) -> Self {
107 Self::raw(
108 TAG_INTEGER,
109 FLAG_NONE,
110 span.start,
111 span.end,
112 Payload { integer: i },
113 )
114 }
115
116 #[inline]
117 pub(crate) fn float(f: f64, span: Span) -> Self {
118 Self::raw(
119 TAG_FLOAT,
120 FLAG_NONE,
121 span.start,
122 span.end,
123 Payload { float: f },
124 )
125 }
126
127 #[inline]
128 pub(crate) fn boolean(b: bool, span: Span) -> Self {
129 Self::raw(
130 TAG_BOOLEAN,
131 FLAG_NONE,
132 span.start,
133 span.end,
134 Payload { boolean: b },
135 )
136 }
137
138 #[inline]
139 pub(crate) fn array(a: Array<'de>, span: Span) -> Self {
140 Self::raw(
141 TAG_ARRAY,
142 FLAG_ARRAY,
143 span.start,
144 span.end,
145 Payload {
146 array: ManuallyDrop::new(a),
147 },
148 )
149 }
150
151 #[inline]
152 pub(crate) fn table(t: InnerTable<'de>, span: Span) -> Self {
153 Self::raw(
154 TAG_TABLE,
155 FLAG_TABLE,
156 span.start,
157 span.end,
158 Payload {
159 table: ManuallyDrop::new(t),
160 },
161 )
162 }
163
164 #[inline]
166 pub(crate) fn array_aot(a: Array<'de>, span: Span) -> Self {
167 Self::raw(
168 TAG_ARRAY,
169 FLAG_AOT,
170 span.start,
171 span.end,
172 Payload {
173 array: ManuallyDrop::new(a),
174 },
175 )
176 }
177
178 #[inline]
180 pub(crate) fn table_frozen(t: InnerTable<'de>, span: Span) -> Self {
181 Self::raw(
182 TAG_TABLE,
183 FLAG_FROZEN,
184 span.start,
185 span.end,
186 Payload {
187 table: ManuallyDrop::new(t),
188 },
189 )
190 }
191
192 #[inline]
194 pub(crate) fn table_header(t: InnerTable<'de>, span: Span) -> Self {
195 Self::raw(
196 TAG_TABLE,
197 FLAG_HEADER,
198 span.start,
199 span.end,
200 Payload {
201 table: ManuallyDrop::new(t),
202 },
203 )
204 }
205
206 #[inline]
208 pub(crate) fn table_dotted(t: InnerTable<'de>, span: Span) -> Self {
209 Self::raw(
210 TAG_TABLE,
211 FLAG_DOTTED,
212 span.start,
213 span.end,
214 Payload {
215 table: ManuallyDrop::new(t),
216 },
217 )
218 }
219}
220#[derive(Clone, Copy)]
221#[repr(u8)]
222#[allow(unused)]
223enum Kind {
224 String = 0,
225 Integer = 1,
226 Float = 2,
227 Boolean = 3,
228 Array = 4,
229 Table = 5,
230}
231
232impl<'de> Item<'de> {
233 #[inline]
234 fn kind(&self) -> Kind {
235 unsafe { std::mem::transmute::<u8, Kind>(self.start_and_tag as u8 & 0x7) }
236 }
237 #[inline]
238 pub(crate) fn tag(&self) -> u32 {
239 self.start_and_tag & TAG_MASK
240 }
241
242 #[inline]
243 pub(crate) fn flag(&self) -> u32 {
244 self.end_and_flag & FLAG_MASK
245 }
246
247 #[inline]
249 pub fn span(&self) -> Span {
250 Span::new(
251 self.start_and_tag >> TAG_SHIFT,
252 self.end_and_flag >> FLAG_SHIFT,
253 )
254 }
255
256 #[inline]
258 pub fn type_str(&self) -> &'static str {
259 match self.tag() {
260 TAG_STRING => "string",
261 TAG_INTEGER => "integer",
262 TAG_FLOAT => "float",
263 TAG_BOOLEAN => "boolean",
264 TAG_ARRAY => "array",
265 _ => "table",
266 }
267 }
268
269 #[inline]
270 pub(crate) fn is_table(&self) -> bool {
271 self.flag() >= FLAG_TABLE
272 }
273
274 #[inline]
275 pub(crate) fn is_array(&self) -> bool {
276 self.flag() & 6 == 2
277 }
278
279 #[inline]
280 pub(crate) fn is_frozen(&self) -> bool {
281 self.flag() == FLAG_FROZEN
282 }
283
284 #[inline]
285 pub(crate) fn is_aot(&self) -> bool {
286 self.flag() == FLAG_AOT
287 }
288
289 #[inline]
290 pub(crate) fn has_header_bit(&self) -> bool {
291 self.flag() == FLAG_HEADER
292 }
293
294 #[inline]
295 pub(crate) fn has_dotted_bit(&self) -> bool {
296 self.flag() == FLAG_DOTTED
297 }
298
299 #[inline]
305 pub(crate) unsafe fn split_array_end_flag(&mut self) -> (&mut u32, &mut Array<'de>) {
306 debug_assert!(self.is_array());
307 let ptr = self as *mut Item<'de>;
308 unsafe {
309 let end_flag = &mut *std::ptr::addr_of_mut!((*ptr).end_and_flag);
310 let array = &mut *std::ptr::addr_of_mut!((*ptr).payload.array).cast::<Array<'de>>();
311 (end_flag, array)
312 }
313 }
314}
315
316pub enum Value<'a, 'de> {
334 String(&'a Str<'de>),
336 Integer(&'a i64),
338 Float(&'a f64),
340 Boolean(&'a bool),
342 Array(&'a Array<'de>),
344 Table(&'a Table<'de>),
346}
347
348pub enum ValueMut<'a, 'de> {
352 String(&'a mut Str<'de>),
354 Integer(&'a mut i64),
356 Float(&'a mut f64),
358 Boolean(&'a mut bool),
360 Array(&'a mut Array<'de>),
362 Table(&'a mut Table<'de>),
364}
365
366impl<'de> Item<'de> {
367 #[inline(never)]
369 pub fn value(&self) -> Value<'_, 'de> {
370 unsafe {
371 match self.kind() {
372 Kind::String => Value::String(&self.payload.string),
373 Kind::Integer => Value::Integer(&self.payload.integer),
374 Kind::Float => Value::Float(&self.payload.float),
375 Kind::Boolean => Value::Boolean(&self.payload.boolean),
376 Kind::Array => Value::Array(&self.payload.array),
377 Kind::Table => Value::Table(self.as_spanned_table_unchecked()),
378 }
379 }
380 }
381
382 #[inline(never)]
384 pub fn value_mut(&mut self) -> ValueMut<'_, 'de> {
385 unsafe {
386 match self.kind() {
387 Kind::String => ValueMut::String(&mut self.payload.string),
388 Kind::Integer => ValueMut::Integer(&mut self.payload.integer),
389 Kind::Float => ValueMut::Float(&mut self.payload.float),
390 Kind::Boolean => ValueMut::Boolean(&mut self.payload.boolean),
391 Kind::Array => ValueMut::Array(&mut self.payload.array),
392 Kind::Table => ValueMut::Table(self.as_spanned_table_mut_unchecked()),
393 }
394 }
395 }
396}
397
398impl<'de> Item<'de> {
399 #[inline]
401 pub fn as_str(&self) -> Option<&str> {
402 if self.tag() == TAG_STRING {
403 Some(unsafe { &self.payload.string })
404 } else {
405 None
406 }
407 }
408
409 #[inline]
411 pub fn as_i64(&self) -> Option<i64> {
412 if self.tag() == TAG_INTEGER {
413 Some(unsafe { self.payload.integer })
414 } else {
415 None
416 }
417 }
418
419 #[inline]
424 pub fn as_f64(&self) -> Option<f64> {
425 match self.value() {
426 Value::Float(f) => Some(*f),
427 Value::Integer(i) => Some(*i as f64),
428 _ => None,
429 }
430 }
431
432 #[inline]
434 pub fn as_bool(&self) -> Option<bool> {
435 if self.tag() == TAG_BOOLEAN {
436 Some(unsafe { self.payload.boolean })
437 } else {
438 None
439 }
440 }
441
442 #[inline]
444 pub fn as_array(&self) -> Option<&Array<'de>> {
445 if self.tag() == TAG_ARRAY {
446 Some(unsafe { &self.payload.array })
447 } else {
448 None
449 }
450 }
451
452 #[inline]
454 pub fn as_table(&self) -> Option<&Table<'de>> {
455 if self.is_table() {
456 Some(unsafe { self.as_spanned_table_unchecked() })
457 } else {
458 None
459 }
460 }
461 pub fn expect_array(&mut self) -> Result<&mut Array<'de>, Error> {
463 if self.is_array() {
464 Ok(unsafe { &mut self.payload.array })
465 } else {
466 Err(self.expected("a array"))
467 }
468 }
469 pub fn expect_table(&mut self) -> Result<&mut Table<'de>, Error> {
473 if self.is_table() {
474 Ok(unsafe { self.as_spanned_table_mut_unchecked() })
475 } else {
476 Err(self.expected("a table"))
477 }
478 }
479
480 #[inline]
482 pub fn as_array_mut(&mut self) -> Option<&mut Array<'de>> {
483 if self.tag() == TAG_ARRAY {
484 Some(unsafe { &mut self.payload.array })
485 } else {
486 None
487 }
488 }
489
490 #[inline]
492 pub fn as_table_mut(&mut self) -> Option<&mut Table<'de>> {
493 if self.is_table() {
494 Some(unsafe { self.as_spanned_table_mut_unchecked() })
495 } else {
496 None
497 }
498 }
499
500 #[inline]
502 pub(crate) unsafe fn as_table_mut_unchecked(&mut self) -> &mut InnerTable<'de> {
503 debug_assert!(self.is_table());
504 unsafe { &mut self.payload.table }
505 }
506
507 #[inline]
512 pub(crate) unsafe fn as_spanned_table_mut_unchecked(&mut self) -> &mut Table<'de> {
513 debug_assert!(self.is_table());
514 unsafe { &mut *(self as *mut Item<'de>).cast::<Table<'de>>() }
515 }
516
517 #[inline]
518 pub(crate) unsafe fn as_spanned_table_unchecked(&self) -> &Table<'de> {
519 debug_assert!(self.is_table());
520 unsafe { &*(self as *const Item<'de>).cast::<Table<'de>>() }
521 }
522
523 #[inline]
525 pub fn has_keys(&self) -> bool {
526 self.as_table().is_some_and(|t| !t.is_empty())
527 }
528
529 #[inline]
531 pub fn has_key(&self, key: &str) -> bool {
532 self.as_table().is_some_and(|t| t.contains_key(key))
533 }
534}
535
536impl<'de> Item<'de> {
537 #[inline]
539 pub fn expected(&self, expected: &'static str) -> Error {
540 Error {
541 kind: ErrorKind::Wanted {
542 expected,
543 found: self.type_str(),
544 },
545 span: self.span(),
546 }
547 }
548
549 #[inline]
553 pub fn parse<T, E>(&mut self) -> Result<T, Error>
554 where
555 T: std::str::FromStr<Err = E>,
556 E: std::fmt::Display,
557 {
558 let s = self.take_string(None)?;
559 match s.parse() {
560 Ok(v) => Ok(v),
561 Err(err) => Err(Error {
562 kind: ErrorKind::Custom(format!("failed to parse string: {err}").into()),
563 span: self.span(),
564 }),
565 }
566 }
567
568 #[inline]
570 pub fn take_string(&mut self, msg: Option<&'static str>) -> Result<Str<'de>, Error> {
571 let span = self.span();
572 match self.value() {
573 Value::String(s) => Ok(*s),
574 _ => Err(Error {
575 kind: ErrorKind::Wanted {
576 expected: msg.unwrap_or("a string"),
577 found: self.type_str(),
578 },
579 span,
580 }),
581 }
582 }
583}
584
585impl fmt::Debug for Item<'_> {
586 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587 match self.value() {
588 Value::String(s) => s.fmt(f),
589 Value::Integer(i) => i.fmt(f),
590 Value::Float(v) => v.fmt(f),
591 Value::Boolean(b) => b.fmt(f),
592 Value::Array(a) => a.fmt(f),
593 Value::Table(t) => t.fmt(f),
594 }
595 }
596}
597
598#[cfg(feature = "serde")]
599impl serde::Serialize for Item<'_> {
600 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
601 where
602 S: serde::Serializer,
603 {
604 match self.value() {
605 Value::String(s) => ser.serialize_str(s),
606 Value::Integer(i) => ser.serialize_i64(*i),
607 Value::Float(f) => ser.serialize_f64(*f),
608 Value::Boolean(b) => ser.serialize_bool(*b),
609 Value::Array(arr) => {
610 use serde::ser::SerializeSeq;
611 let mut seq = ser.serialize_seq(Some(arr.len()))?;
612 for ele in arr {
613 seq.serialize_element(ele)?;
614 }
615 seq.end()
616 }
617 Value::Table(tab) => {
618 use serde::ser::SerializeMap;
619 let mut map = ser.serialize_map(Some(tab.len()))?;
620 for (k, v) in tab {
621 map.serialize_entry(&*k.name, v)?;
622 }
623 map.end()
624 }
625 }
626 }
627}
628
629#[cfg(feature = "serde")]
630impl serde::Serialize for InnerTable<'_> {
631 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
632 where
633 S: serde::Serializer,
634 {
635 use serde::ser::SerializeMap;
636 let mut map = ser.serialize_map(Some(self.len()))?;
637 for (k, v) in self.entries() {
638 map.serialize_entry(&*k.name, v)?;
639 }
640 map.end()
641 }
642}
643
644#[cfg(feature = "serde")]
645impl serde::Serialize for Table<'_> {
646 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
647 where
648 S: serde::Serializer,
649 {
650 self.value.serialize(ser)
651 }
652}
653
654#[derive(Copy, Clone)]
659pub struct Key<'de> {
660 pub name: Str<'de>,
662 pub span: Span,
664}
665impl<'de> Key<'de> {
666 pub fn as_str(&self) -> &'de str {
668 self.name.as_str()
669 }
670}
671
672const _: () = assert!(std::mem::size_of::<Key<'_>>() == 24);
673
674impl std::borrow::Borrow<str> for Key<'_> {
675 fn borrow(&self) -> &str {
676 &self.name
677 }
678}
679
680impl fmt::Debug for Key<'_> {
681 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
682 f.write_str(&self.name)
683 }
684}
685
686impl fmt::Display for Key<'_> {
687 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
688 f.write_str(&self.name)
689 }
690}
691
692impl Ord for Key<'_> {
693 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
694 self.name.cmp(&other.name)
695 }
696}
697
698impl PartialOrd for Key<'_> {
699 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
700 Some(self.cmp(other))
701 }
702}
703
704impl PartialEq for Key<'_> {
705 fn eq(&self, other: &Self) -> bool {
706 self.name.eq(&other.name)
707 }
708}
709
710impl Eq for Key<'_> {}
711
712impl<'de> std::ops::Index<&str> for Item<'de> {
713 type Output = MaybeItem<'de>;
714
715 #[inline]
716 fn index(&self, index: &str) -> &Self::Output {
717 if let Some(table) = self.as_table()
718 && let Some(item) = table.get(index)
719 {
720 return MaybeItem::from_ref(item);
721 }
722 &NONE
723 }
724}
725
726impl<'de> std::ops::Index<usize> for Item<'de> {
727 type Output = MaybeItem<'de>;
728
729 #[inline]
730 fn index(&self, index: usize) -> &Self::Output {
731 if let Some(arr) = self.as_array()
732 && let Some(item) = arr.get(index)
733 {
734 return MaybeItem::from_ref(item);
735 }
736 &NONE
737 }
738}
739
740impl<'de> std::ops::Index<&str> for MaybeItem<'de> {
741 type Output = MaybeItem<'de>;
742
743 #[inline]
744 fn index(&self, index: &str) -> &Self::Output {
745 if let Some(table) = self.as_table()
746 && let Some(item) = table.get(index)
747 {
748 return MaybeItem::from_ref(item);
749 }
750 &NONE
751 }
752}
753
754impl<'de> std::ops::Index<usize> for MaybeItem<'de> {
755 type Output = MaybeItem<'de>;
756
757 #[inline]
758 fn index(&self, index: usize) -> &Self::Output {
759 if let Some(arr) = self.as_array()
760 && let Some(item) = arr.get(index)
761 {
762 return MaybeItem::from_ref(item);
763 }
764 &NONE
765 }
766}
767
768#[repr(C)]
804pub struct MaybeItem<'de> {
805 payload: Payload<'de>,
806 start_and_tag: u32,
807 end_and_flag: u32,
808}
809
810unsafe impl Sync for MaybeItem<'_> {}
811
812pub(crate) static NONE: MaybeItem<'static> = MaybeItem {
813 payload: Payload { integer: 0 },
814 start_and_tag: TAG_NONE,
815 end_and_flag: FLAG_NONE,
816};
817
818impl<'de> MaybeItem<'de> {
819 pub fn from_ref<'a>(item: &'a Item<'de>) -> &'a Self {
821 unsafe { &*(item as *const Item<'de>).cast::<MaybeItem<'de>>() }
822 }
823 #[inline]
824 pub(crate) fn tag(&self) -> u32 {
825 self.start_and_tag & TAG_MASK
826 }
827 pub fn item(&self) -> Option<&Item<'de>> {
829 if self.tag() != TAG_NONE {
830 Some(unsafe { &*(self as *const MaybeItem<'de>).cast::<Item<'de>>() })
831 } else {
832 None
833 }
834 }
835 #[inline]
837 pub fn as_str(&self) -> Option<&str> {
838 if self.tag() == TAG_STRING {
839 Some(unsafe { &self.payload.string })
840 } else {
841 None
842 }
843 }
844
845 #[inline]
847 pub fn as_i64(&self) -> Option<i64> {
848 if self.tag() == TAG_INTEGER {
849 Some(unsafe { self.payload.integer })
850 } else {
851 None
852 }
853 }
854
855 #[inline]
860 pub fn as_f64(&self) -> Option<f64> {
861 self.item()?.as_f64()
862 }
863
864 #[inline]
866 pub fn as_bool(&self) -> Option<bool> {
867 if self.tag() == TAG_BOOLEAN {
868 Some(unsafe { self.payload.boolean })
869 } else {
870 None
871 }
872 }
873
874 #[inline]
876 pub fn as_array(&self) -> Option<&Array<'de>> {
877 if self.tag() == TAG_ARRAY {
878 Some(unsafe { &self.payload.array })
879 } else {
880 None
881 }
882 }
883
884 #[inline]
886 pub fn as_table(&self) -> Option<&Table<'de>> {
887 if self.tag() == TAG_TABLE {
888 Some(unsafe { &*(self as *const Self).cast::<Table<'de>>() })
889 } else {
890 None
891 }
892 }
893
894 pub fn span(&self) -> Option<Span> {
896 if let Some(item) = self.item() {
897 Some(item.span())
898 } else {
899 None
900 }
901 }
902
903 pub fn value(&self) -> Option<Value<'_, 'de>> {
905 if let Some(item) = self.item() {
906 Some(item.value())
907 } else {
908 None
909 }
910 }
911}