1#![allow(unsafe_code)]
2#![allow(clippy::manual_map)]
3#[cfg(test)]
4#[path = "./value_tests.rs"]
5mod tests;
6use crate::{Error, ErrorKind, Span, Table};
7use std::fmt;
8use std::mem::ManuallyDrop;
9
10pub use crate::array::Array;
12use crate::table::InnerTable;
14
15pub(crate) const TAG_MASK: u32 = 0x7;
16pub(crate) const TAG_SHIFT: u32 = 3;
17
18pub(crate) const TAG_STRING: u32 = 0;
19pub(crate) const TAG_INTEGER: u32 = 1;
20pub(crate) const TAG_FLOAT: u32 = 2;
21pub(crate) const TAG_BOOLEAN: u32 = 3;
22pub(crate) const TAG_ARRAY: u32 = 4;
23pub(crate) const TAG_TABLE: u32 = 5;
24
25pub(crate) const TAG_NONE: u32 = 6;
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}
51
52#[repr(C)]
74pub struct Item<'de> {
75 payload: Payload<'de>,
76 start_and_tag: u32,
77 end_and_flag: u32,
78}
79
80const _: () = assert!(std::mem::size_of::<Item<'_>>() == 24);
81const _: () = assert!(std::mem::align_of::<Item<'_>>() == 8);
82
83impl<'de> Item<'de> {
84 #[inline]
85 fn raw(tag: u32, flag: u32, start: u32, end: u32, payload: Payload<'de>) -> Self {
86 Self {
87 start_and_tag: (start << TAG_SHIFT) | tag,
88 end_and_flag: (end << FLAG_SHIFT) | flag,
89 payload,
90 }
91 }
92
93 #[inline]
94 pub(crate) fn string(s: &'de str, span: Span) -> Self {
95 Self::raw(
96 TAG_STRING,
97 FLAG_NONE,
98 span.start,
99 span.end,
100 Payload { string: s },
101 )
102 }
103
104 #[inline]
105 pub(crate) fn integer(i: i64, span: Span) -> Self {
106 Self::raw(
107 TAG_INTEGER,
108 FLAG_NONE,
109 span.start,
110 span.end,
111 Payload { integer: i },
112 )
113 }
114
115 #[inline]
116 pub(crate) fn float(f: f64, span: Span) -> Self {
117 Self::raw(
118 TAG_FLOAT,
119 FLAG_NONE,
120 span.start,
121 span.end,
122 Payload { float: f },
123 )
124 }
125
126 #[inline]
127 pub(crate) fn boolean(b: bool, span: Span) -> Self {
128 Self::raw(
129 TAG_BOOLEAN,
130 FLAG_NONE,
131 span.start,
132 span.end,
133 Payload { boolean: b },
134 )
135 }
136
137 #[inline]
138 pub(crate) fn array(a: Array<'de>, span: Span) -> Self {
139 Self::raw(
140 TAG_ARRAY,
141 FLAG_ARRAY,
142 span.start,
143 span.end,
144 Payload {
145 array: ManuallyDrop::new(a),
146 },
147 )
148 }
149
150 #[inline]
151 pub(crate) fn table(t: InnerTable<'de>, span: Span) -> Self {
152 Self::raw(
153 TAG_TABLE,
154 FLAG_TABLE,
155 span.start,
156 span.end,
157 Payload {
158 table: ManuallyDrop::new(t),
159 },
160 )
161 }
162
163 #[inline]
165 pub(crate) fn array_aot(a: Array<'de>, span: Span) -> Self {
166 Self::raw(
167 TAG_ARRAY,
168 FLAG_AOT,
169 span.start,
170 span.end,
171 Payload {
172 array: ManuallyDrop::new(a),
173 },
174 )
175 }
176
177 #[inline]
179 pub(crate) fn table_frozen(t: InnerTable<'de>, span: Span) -> Self {
180 Self::raw(
181 TAG_TABLE,
182 FLAG_FROZEN,
183 span.start,
184 span.end,
185 Payload {
186 table: ManuallyDrop::new(t),
187 },
188 )
189 }
190
191 #[inline]
193 pub(crate) fn table_header(t: InnerTable<'de>, span: Span) -> Self {
194 Self::raw(
195 TAG_TABLE,
196 FLAG_HEADER,
197 span.start,
198 span.end,
199 Payload {
200 table: ManuallyDrop::new(t),
201 },
202 )
203 }
204
205 #[inline]
207 pub(crate) fn table_dotted(t: InnerTable<'de>, span: Span) -> Self {
208 Self::raw(
209 TAG_TABLE,
210 FLAG_DOTTED,
211 span.start,
212 span.end,
213 Payload {
214 table: ManuallyDrop::new(t),
215 },
216 )
217 }
218}
219#[derive(Clone, Copy)]
220#[repr(u8)]
221#[allow(unused)]
222enum Kind {
223 String = 0,
224 Integer = 1,
225 Float = 2,
226 Boolean = 3,
227 Array = 4,
228 Table = 5,
229}
230
231impl<'de> Item<'de> {
232 #[inline]
233 fn kind(&self) -> Kind {
234 unsafe { std::mem::transmute::<u8, Kind>(self.start_and_tag as u8 & 0x7) }
235 }
236 #[inline]
237 pub(crate) fn tag(&self) -> u32 {
238 self.start_and_tag & TAG_MASK
239 }
240
241 #[inline]
242 pub(crate) fn flag(&self) -> u32 {
243 self.end_and_flag & FLAG_MASK
244 }
245
246 #[inline]
248 pub fn span(&self) -> Span {
249 Span::new(
250 self.start_and_tag >> TAG_SHIFT,
251 self.end_and_flag >> FLAG_SHIFT,
252 )
253 }
254
255 #[inline]
257 pub fn type_str(&self) -> &'static str {
258 match self.tag() {
259 TAG_STRING => "string",
260 TAG_INTEGER => "integer",
261 TAG_FLOAT => "float",
262 TAG_BOOLEAN => "boolean",
263 TAG_ARRAY => "array",
264 _ => "table",
265 }
266 }
267
268 #[inline]
269 pub(crate) fn is_table(&self) -> bool {
270 self.flag() >= FLAG_TABLE
271 }
272
273 #[inline]
274 pub(crate) fn is_array(&self) -> bool {
275 self.flag() & 6 == 2
276 }
277
278 #[inline]
279 pub(crate) fn is_frozen(&self) -> bool {
280 self.flag() == FLAG_FROZEN
281 }
282
283 #[inline]
284 pub(crate) fn is_aot(&self) -> bool {
285 self.flag() == FLAG_AOT
286 }
287
288 #[inline]
289 pub(crate) fn has_header_bit(&self) -> bool {
290 self.flag() == FLAG_HEADER
291 }
292
293 #[inline]
294 pub(crate) fn has_dotted_bit(&self) -> bool {
295 self.flag() == FLAG_DOTTED
296 }
297
298 #[inline]
304 pub(crate) unsafe fn split_array_end_flag(&mut self) -> (&mut u32, &mut Array<'de>) {
305 debug_assert!(self.is_array());
306 let ptr = self as *mut Item<'de>;
307 unsafe {
308 let end_flag = &mut *std::ptr::addr_of_mut!((*ptr).end_and_flag);
309 let array = &mut *std::ptr::addr_of_mut!((*ptr).payload.array).cast::<Array<'de>>();
310 (end_flag, array)
311 }
312 }
313}
314
315pub enum Value<'a, 'de> {
333 String(&'a &'de str),
335 Integer(&'a i64),
337 Float(&'a f64),
339 Boolean(&'a bool),
341 Array(&'a Array<'de>),
343 Table(&'a Table<'de>),
345}
346
347pub enum ValueMut<'a, 'de> {
351 String(&'a mut &'de str),
353 Integer(&'a mut i64),
355 Float(&'a mut f64),
357 Boolean(&'a mut bool),
359 Array(&'a mut Array<'de>),
361 Table(&'a mut Table<'de>),
363}
364
365impl<'de> Item<'de> {
366 #[inline(never)]
368 pub fn value(&self) -> Value<'_, 'de> {
369 unsafe {
370 match self.kind() {
371 Kind::String => Value::String(&self.payload.string),
372 Kind::Integer => Value::Integer(&self.payload.integer),
373 Kind::Float => Value::Float(&self.payload.float),
374 Kind::Boolean => Value::Boolean(&self.payload.boolean),
375 Kind::Array => Value::Array(&self.payload.array),
376 Kind::Table => Value::Table(self.as_spanned_table_unchecked()),
377 }
378 }
379 }
380
381 #[inline(never)]
383 pub fn value_mut(&mut self) -> ValueMut<'_, 'de> {
384 unsafe {
385 match self.kind() {
386 Kind::String => ValueMut::String(&mut self.payload.string),
387 Kind::Integer => ValueMut::Integer(&mut self.payload.integer),
388 Kind::Float => ValueMut::Float(&mut self.payload.float),
389 Kind::Boolean => ValueMut::Boolean(&mut self.payload.boolean),
390 Kind::Array => ValueMut::Array(&mut self.payload.array),
391 Kind::Table => ValueMut::Table(self.as_spanned_table_mut_unchecked()),
392 }
393 }
394 }
395}
396
397impl<'de> Item<'de> {
398 #[inline]
400 pub fn as_str(&self) -> Option<&str> {
401 if self.tag() == TAG_STRING {
402 Some(unsafe { self.payload.string })
403 } else {
404 None
405 }
406 }
407
408 #[inline]
410 pub fn as_i64(&self) -> Option<i64> {
411 if self.tag() == TAG_INTEGER {
412 Some(unsafe { self.payload.integer })
413 } else {
414 None
415 }
416 }
417
418 #[inline]
423 pub fn as_f64(&self) -> Option<f64> {
424 match self.value() {
425 Value::Float(f) => Some(*f),
426 Value::Integer(i) => Some(*i as f64),
427 _ => None,
428 }
429 }
430
431 #[inline]
433 pub fn as_bool(&self) -> Option<bool> {
434 if self.tag() == TAG_BOOLEAN {
435 Some(unsafe { self.payload.boolean })
436 } else {
437 None
438 }
439 }
440
441 #[inline]
443 pub fn as_array(&self) -> Option<&Array<'de>> {
444 if self.tag() == TAG_ARRAY {
445 Some(unsafe { &self.payload.array })
446 } else {
447 None
448 }
449 }
450
451 #[inline]
453 pub fn as_table(&self) -> Option<&Table<'de>> {
454 if self.is_table() {
455 Some(unsafe { self.as_spanned_table_unchecked() })
456 } else {
457 None
458 }
459 }
460 pub fn expect_array(&mut self) -> Result<&mut Array<'de>, Error> {
462 if self.is_array() {
463 Ok(unsafe { &mut self.payload.array })
464 } else {
465 Err(self.expected("a array"))
466 }
467 }
468 pub fn expect_table(&mut self) -> Result<&mut Table<'de>, Error> {
472 if self.is_table() {
473 Ok(unsafe { self.as_spanned_table_mut_unchecked() })
474 } else {
475 Err(self.expected("a table"))
476 }
477 }
478
479 #[inline]
481 pub fn as_array_mut(&mut self) -> Option<&mut Array<'de>> {
482 if self.tag() == TAG_ARRAY {
483 Some(unsafe { &mut self.payload.array })
484 } else {
485 None
486 }
487 }
488
489 #[inline]
491 pub fn as_table_mut(&mut self) -> Option<&mut Table<'de>> {
492 if self.is_table() {
493 Some(unsafe { self.as_spanned_table_mut_unchecked() })
494 } else {
495 None
496 }
497 }
498
499 #[inline]
501 pub(crate) unsafe fn as_table_mut_unchecked(&mut self) -> &mut InnerTable<'de> {
502 debug_assert!(self.is_table());
503 unsafe { &mut self.payload.table }
504 }
505
506 #[inline]
511 pub(crate) unsafe fn as_spanned_table_mut_unchecked(&mut self) -> &mut Table<'de> {
512 debug_assert!(self.is_table());
513 unsafe { &mut *(self as *mut Item<'de>).cast::<Table<'de>>() }
514 }
515
516 #[inline]
517 pub(crate) unsafe fn as_spanned_table_unchecked(&self) -> &Table<'de> {
518 debug_assert!(self.is_table());
519 unsafe { &*(self as *const Item<'de>).cast::<Table<'de>>() }
520 }
521
522 #[inline]
524 pub fn has_keys(&self) -> bool {
525 self.as_table().is_some_and(|t| !t.is_empty())
526 }
527
528 #[inline]
530 pub fn has_key(&self, key: &str) -> bool {
531 self.as_table().is_some_and(|t| t.contains_key(key))
532 }
533}
534
535impl<'de> Item<'de> {
536 #[inline]
538 pub fn expected(&self, expected: &'static str) -> Error {
539 Error {
540 kind: ErrorKind::Wanted {
541 expected,
542 found: self.type_str(),
543 },
544 span: self.span(),
545 }
546 }
547
548 #[inline]
552 pub fn parse<T, E>(&mut self) -> Result<T, Error>
553 where
554 T: std::str::FromStr<Err = E>,
555 E: std::fmt::Display,
556 {
557 let s = self.take_string(None)?;
558 match s.parse() {
559 Ok(v) => Ok(v),
560 Err(err) => Err(Error {
561 kind: ErrorKind::Custom(format!("failed to parse string: {err}").into()),
562 span: self.span(),
563 }),
564 }
565 }
566
567 #[inline]
569 pub fn take_string(&mut self, msg: Option<&'static str>) -> Result<&'de str, Error> {
570 let span = self.span();
571 match self.value() {
572 Value::String(s) => Ok(*s),
573 _ => Err(Error {
574 kind: ErrorKind::Wanted {
575 expected: msg.unwrap_or("a string"),
576 found: self.type_str(),
577 },
578 span,
579 }),
580 }
581 }
582}
583
584impl fmt::Debug for Item<'_> {
585 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
586 match self.value() {
587 Value::String(s) => s.fmt(f),
588 Value::Integer(i) => i.fmt(f),
589 Value::Float(v) => v.fmt(f),
590 Value::Boolean(b) => b.fmt(f),
591 Value::Array(a) => a.fmt(f),
592 Value::Table(t) => t.fmt(f),
593 }
594 }
595}
596
597#[cfg(feature = "serde")]
598impl serde::Serialize for Item<'_> {
599 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
600 where
601 S: serde::Serializer,
602 {
603 match self.value() {
604 Value::String(s) => ser.serialize_str(s),
605 Value::Integer(i) => ser.serialize_i64(*i),
606 Value::Float(f) => ser.serialize_f64(*f),
607 Value::Boolean(b) => ser.serialize_bool(*b),
608 Value::Array(arr) => {
609 use serde::ser::SerializeSeq;
610 let mut seq = ser.serialize_seq(Some(arr.len()))?;
611 for ele in arr {
612 seq.serialize_element(ele)?;
613 }
614 seq.end()
615 }
616 Value::Table(tab) => {
617 use serde::ser::SerializeMap;
618 let mut map = ser.serialize_map(Some(tab.len()))?;
619 for (k, v) in tab {
620 map.serialize_entry(&*k.name, v)?;
621 }
622 map.end()
623 }
624 }
625 }
626}
627
628#[cfg(feature = "serde")]
629impl serde::Serialize for InnerTable<'_> {
630 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
631 where
632 S: serde::Serializer,
633 {
634 use serde::ser::SerializeMap;
635 let mut map = ser.serialize_map(Some(self.len()))?;
636 for (k, v) in self.entries() {
637 map.serialize_entry(&*k.name, v)?;
638 }
639 map.end()
640 }
641}
642
643#[cfg(feature = "serde")]
644impl serde::Serialize for Table<'_> {
645 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
646 where
647 S: serde::Serializer,
648 {
649 self.value.serialize(ser)
650 }
651}
652
653#[derive(Copy, Clone)]
658pub struct Key<'de> {
659 pub name: &'de str,
661 pub span: Span,
663}
664impl<'de> Key<'de> {
665 pub fn as_str(&self) -> &'de str {
667 self.name
668 }
669}
670
671#[cfg(target_pointer_width = "64")]
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}