1#[cfg(all(test, feature = "to-toml"))]
2#[path = "./de_tests.rs"]
3mod tests;
4
5use std::collections::{BTreeMap, BTreeSet};
6use std::hash::BuildHasher;
7use std::hash::Hash;
8use std::num::NonZeroU64;
9use std::path::PathBuf;
10
11use foldhash::HashMap;
12
13use std::fmt::{self, Debug, Display};
14
15use crate::Value;
16use crate::error::ErrorInner;
17use crate::{
18 Arena, Key, Span, Table,
19 error::{Error, ErrorKind, MaybeTomlPath, PathComponent},
20 item::{self, Item},
21 parser::{INDEXED_TABLE_THRESHOLD, KeyRef},
22};
23
24pub(crate) fn compute_paths(root: &Table<'_>, errors: &mut [Error]) {
30 let mut pending: Vec<(*const u8, &mut MaybeTomlPath)> = Vec::new();
31 for error in errors.iter_mut() {
32 if error.path.is_uncomputed() {
33 pending.push((error.path.uncomputed_ptr() as *const u8, &mut error.path));
34 }
35 }
36 if pending.is_empty() {
37 return;
38 }
39
40 let mut path_stack: [PathComponent<'_>; 32] = [PathComponent::Index(0); 32];
41 compute_paths_walk(root.as_item(), &mut pending, &mut path_stack, 0);
42}
43
44fn compute_paths_walk<'de>(
45 item: &Item<'de>,
46 pending: &mut Vec<(*const u8, &mut MaybeTomlPath)>,
47 path_stack: &mut [PathComponent<'de>; 32],
48 path_depth: usize,
49) {
50 if path_depth >= path_stack.len() {
51 return;
52 }
53 match item.value() {
54 Value::Table(table) => {
55 let entries = table.entries();
56 if entries.is_empty() {
57 return;
58 }
59 let entry_size = std::mem::size_of::<(Key<'_>, Item<'_>)>();
60 let base = entries.as_ptr() as *const u8;
61 let end = unsafe { base.add(entries.len() * entry_size) };
63
64 let mut i = 0;
65 while let Some((ptr, path)) = pending.get_mut(i) {
66 let ptr: *const u8 = *ptr;
67 if ptr >= base && ptr < end {
69 let byte_offset = unsafe { ptr.byte_offset_from(base) } as usize;
70 let entry_index = byte_offset / entry_size;
71 if entry_index < entries.len() {
72 path_stack[path_depth] = PathComponent::Key(entries[entry_index].0);
73 **path = MaybeTomlPath::from_components(&path_stack[..path_depth + 1]);
74 pending.swap_remove(i);
75 continue;
76 }
77 }
78 i += 1;
79 }
80
81 for (key, child) in table {
82 path_stack[path_depth] = PathComponent::Key(*key);
83 compute_paths_walk(child, pending, path_stack, path_depth + 1);
84 }
85 }
86 Value::Array(array) => {
87 let slice = array.as_slice();
88 if slice.is_empty() {
89 return;
90 }
91 let item_size = std::mem::size_of::<Item<'_>>();
92 let base = slice.as_ptr() as *const u8;
93 let end = unsafe { base.add(slice.len() * item_size) };
95
96 let mut i = 0;
97 while let Some((ptr, path)) = pending.get_mut(i) {
98 let ptr = *ptr;
99 if ptr >= base && ptr < end {
100 let byte_offset = unsafe { ptr.byte_offset_from(base) } as usize;
101 let elem_index = byte_offset / item_size;
102 if elem_index < slice.len() {
103 path_stack[path_depth] = PathComponent::Index(elem_index);
104 **path = MaybeTomlPath::from_components(&path_stack[..path_depth + 1]);
105 pending.swap_remove(i);
106 continue;
107 }
108 }
109 i += 1;
110 }
111
112 let mut idx = 0; for child in array {
114 path_stack[path_depth] = PathComponent::Index(idx);
115 compute_paths_walk(child, pending, path_stack, path_depth + 1);
116 idx += 1;
117 }
118 }
119 _ => (),
120 }
121}
122
123pub struct TableHelper<'ctx, 'table, 'de> {
158 pub ctx: &'ctx mut Context<'de>,
159 pub table: &'table Table<'de>,
160 table_id: i32,
162 used_count: u32,
164 used: &'de mut FixedBitset,
165}
166
167#[repr(transparent)]
168struct FixedBitset([u64]);
169
170impl FixedBitset {
171 #[allow(clippy::mut_from_ref)]
172 pub fn new(capacity: usize, arena: &Arena) -> &mut FixedBitset {
173 let bitset_bucket_count = capacity.div_ceil(64);
174 let bitset = arena
175 .alloc(bitset_bucket_count * std::mem::size_of::<u64>())
176 .cast::<u64>();
177 for offset in 0..bitset_bucket_count {
178 unsafe {
181 bitset.add(offset).write(0);
182 }
183 }
184 let slice = unsafe { std::slice::from_raw_parts_mut(bitset.as_ptr(), bitset_bucket_count) };
186 unsafe { &mut *(slice as *mut [u64] as *mut FixedBitset) }
188 }
189
190 pub fn insert(&mut self, index: usize) -> bool {
191 let offset = index >> 6;
192 let bit = 1 << (index & 63);
193 let old = self.0[offset];
194 self.0[offset] |= bit;
195 old & bit == 0
196 }
197
198 pub fn get(&self, index: usize) -> bool {
199 let offset = index >> 6;
200 let bit = 1 << (index & 63);
201 self.0[offset] & bit != 0
202 }
203}
204
205pub struct RemainingEntriesIter<'t, 'de> {
210 entries: &'t [(Key<'de>, Item<'de>)],
211 remaining_cells: std::slice::Iter<'de, u64>,
212 bits: u64,
213}
214impl RemainingEntriesIter<'_, '_> {
215 fn next_bucket(&mut self) -> bool {
216 let Some(bucket) = self.remaining_cells.next() else {
217 return false;
218 };
219 debug_assert!(self.entries.len() > 64);
220 let Some(remaining) = self.entries.get(64..) else {
221 return false;
222 };
223 self.entries = remaining;
224 self.bits = !*bucket;
225 true
226 }
227}
228
229impl<'t, 'de> Iterator for RemainingEntriesIter<'t, 'de> {
230 type Item = &'t (Key<'de>, Item<'de>);
231
232 fn next(&mut self) -> Option<Self::Item> {
233 loop {
234 if let Some(bits) = NonZeroU64::new(self.bits) {
235 let bit_index = bits.trailing_zeros() as usize;
236 self.bits &= self.bits - 1;
237 return self.entries.get(bit_index);
238 }
239 if !self.next_bucket() {
240 return None;
241 }
242 }
243 }
244}
245
246impl<'ctx, 't, 'de> TableHelper<'ctx, 't, 'de> {
247 pub fn new(ctx: &'ctx mut Context<'de>, table: &'t Table<'de>) -> Self {
252 let table_id = if table.len() > INDEXED_TABLE_THRESHOLD && table.meta.is_span_mode() {
253 table.entries()[0].0.span.start as i32
254 } else {
255 -1
256 };
257 Self {
258 used: FixedBitset::new(table.len(), ctx.arena),
259 ctx,
260 table,
261 table_id,
262 used_count: 0,
263 }
264 }
265
266 pub fn get_entry(&self, key: &str) -> Option<&'t (Key<'de>, Item<'de>)> {
273 if self.table_id < 0 {
274 for entry in self.table.entries() {
275 if entry.0.name == key {
276 return Some(entry);
277 }
278 }
279 None
280 } else {
281 match self.ctx.index.get(&KeyRef::new(key, self.table_id as u32)) {
282 Some(index) => Some(&self.table.entries()[*index]),
283 None => None,
284 }
285 }
286 }
287
288 pub fn required_mapped<T>(
299 &mut self,
300 name: &'static str,
301 func: fn(&Item<'de>) -> Result<T, Error>,
302 ) -> Result<T, Failed> {
303 let Some((_, item)) = self.optional_entry(name) else {
304 return Err(self.report_missing_field(name));
305 };
306
307 match func(item) {
308 Ok(t) => Ok(t),
309 Err(e) => Err(self.ctx.push_error(Error::custom(e, item.span_unchecked()))),
310 }
311 }
312
313 pub fn optional_mapped<T>(
320 &mut self,
321 name: &'static str,
322 func: fn(&Item<'de>) -> Result<T, Error>,
323 ) -> Option<T> {
324 let Some((_, item)) = self.optional_entry(name) else {
325 return None;
326 };
327
328 match func(item) {
329 Ok(t) => Some(t),
330 Err(e) => {
331 self.ctx.push_error(Error::custom(e, item.span_unchecked()));
332 None
333 }
334 }
335 }
336
337 pub fn required_item(&mut self, name: &'static str) -> Result<&'t Item<'de>, Failed> {
348 if let Ok((_, item)) = self.required_entry(name) {
349 Ok(item)
350 } else {
351 Err(self.report_missing_field(name))
352 }
353 }
354
355 pub fn optional_item(&mut self, name: &'static str) -> Option<&'t Item<'de>> {
361 if let Some((_, item)) = self.optional_entry(name) {
362 Some(item)
363 } else {
364 None
365 }
366 }
367
368 pub fn required_entry(
379 &mut self,
380 name: &'static str,
381 ) -> Result<&'t (Key<'de>, Item<'de>), Failed> {
382 match self.optional_entry(name) {
383 Some(entry) => Ok(entry),
384 None => Err(self.report_missing_field(name)),
385 }
386 }
387
388 pub fn optional_entry(&mut self, key: &str) -> Option<&'t (Key<'de>, Item<'de>)> {
394 let Some(entry) = self.get_entry(key) else {
395 return None;
396 };
397 let index = unsafe {
404 let ptr = entry as *const (Key<'de>, Item<'de>);
405 let base = self.table.entries().as_ptr();
406 ptr.offset_from(base) as usize
407 };
408 if self.used.insert(index) {
409 self.used_count += 1;
410 }
411 Some(entry)
412 }
413
414 #[cold]
415 fn report_missing_field(&mut self, name: &'static str) -> Failed {
416 self.ctx.errors.push(Error::new_with_path(
417 ErrorKind::MissingField(name),
418 self.table.span(),
419 MaybeTomlPath::uncomputed(self.table.as_item()),
420 ));
421 Failed
422 }
423
424 pub fn required<T: FromToml<'de>>(&mut self, name: &'static str) -> Result<T, Failed> {
434 let Some((_, val)) = self.optional_entry(name) else {
435 return Err(self.report_missing_field(name));
436 };
437
438 T::from_toml(self.ctx, val)
439 }
440
441 pub fn optional<T: FromToml<'de>>(&mut self, name: &str) -> Option<T> {
448 let Some((_, val)) = self.optional_entry(name) else {
449 return None;
450 };
451
452 #[allow(clippy::manual_ok_err)]
453 match T::from_toml(self.ctx, val) {
454 Ok(value) => Some(value),
455 Err(_) => None,
456 }
457 }
458
459 pub fn remaining_count(&self) -> usize {
461 self.table.len() - self.used_count as usize
462 }
463
464 pub fn into_remaining(self) -> RemainingEntriesIter<'t, 'de> {
466 let entries = self.table.entries();
467 let mut remaining_cells = self.used.0.iter();
468 RemainingEntriesIter {
469 bits: if let Some(value) = remaining_cells.next() {
470 !*value
471 } else {
472 0
473 },
474 entries,
475 remaining_cells,
476 }
477 }
478
479 #[doc(alias = "expect_empty")]
491 #[inline(never)]
492 pub fn require_empty(self) -> Result<(), Failed> {
493 if self.used_count as usize == self.table.len() {
494 return Ok(());
495 }
496
497 let mut had_unexpected = false;
498 for (i, (key, item)) in self.table.entries().iter().enumerate() {
499 if !self.used.get(i) {
500 self.ctx.errors.push(Error {
501 kind: ErrorInner::Static(ErrorKind::UnexpectedKey { tag: 0 }),
502 span: key.span,
503 path: MaybeTomlPath::uncomputed(item),
504 });
505
506 had_unexpected = true;
507 }
508 }
509
510 if had_unexpected { Err(Failed) } else { Ok(()) }
511 }
512}
513
514pub struct Context<'de> {
523 pub arena: &'de Arena,
524 pub(crate) index: HashMap<KeyRef<'de>, usize>,
525 pub errors: Vec<Error>,
526 pub(crate) source: &'de str,
527}
528
529impl<'de> Context<'de> {
530 pub fn source(&self) -> &'de str {
532 self.source
533 }
534
535 #[cold]
537 pub fn report_expected_but_found(
538 &mut self,
539 message: &'static &'static str,
540 found: &Item<'de>,
541 ) -> Failed {
542 let path = MaybeTomlPath::uncomputed(found);
543 self.errors.push(Error::new_with_path(
544 ErrorKind::Wanted {
545 expected: message,
546 found: found.type_str(),
547 },
548 found.span(),
549 path,
550 ));
551 Failed
552 }
553
554 #[cold]
556 pub fn report_unexpected_variant(
557 &mut self,
558 expected: &'static [&'static str],
559 found: &Item<'de>,
560 ) -> Failed {
561 let path = MaybeTomlPath::uncomputed(found);
562 self.errors.push(Error::new_with_path(
563 ErrorKind::UnexpectedVariant { expected },
564 found.span(),
565 path,
566 ));
567 Failed
568 }
569
570 #[cold]
572 pub fn report_error_at(&mut self, message: &'static str, at: Span) -> Failed {
573 self.errors.push(Error::custom_static(message, at));
574 Failed
575 }
576 #[cold]
578 pub fn push_error(&mut self, error: Error) -> Failed {
579 self.errors.push(error);
580 Failed
581 }
582
583 #[cold]
585 pub fn report_custom_error(&mut self, error: impl ToString, item: &Item<'de>) -> Failed {
586 self.push_error(Error::custom(error, item.span()))
587 }
588
589 #[cold]
591 pub fn report_out_of_range(
592 &mut self,
593 ty: &'static &'static str,
594 range: &'static &'static str,
595 found: &Item<'de>,
596 ) -> Failed {
597 let path = MaybeTomlPath::uncomputed(found);
598 self.errors.push(Error::new_with_path(
599 ErrorKind::OutOfRange { ty, range },
600 found.span(),
601 path,
602 ));
603 Failed
604 }
605
606 #[cold]
611 pub fn report_missing_field(&mut self, name: &'static str, item: &Item<'de>) -> Failed {
612 let path = MaybeTomlPath::uncomputed(item);
613 self.errors.push(Error::new_with_path(
614 ErrorKind::MissingField(name),
615 item.span(),
616 path,
617 ));
618 Failed
619 }
620
621 #[cold]
626 pub fn report_duplicate_field(
627 &mut self,
628 name: &'static str,
629 key_span: Span,
630 first_key_span: Span,
631 item: &Item<'de>,
632 ) -> Failed {
633 self.push_error(Error::new_with_path(
634 ErrorKind::DuplicateField {
635 field: name,
636 first: first_key_span,
637 },
638 key_span,
639 MaybeTomlPath::uncomputed(item),
640 ))
641 }
642
643 #[cold]
648 pub fn report_deprecated_field(
649 &mut self,
650 tag: u32,
651 old: &'static &'static str,
652 new: &'static &'static str,
653 key_span: Span,
654 item: &Item<'de>,
655 ) {
656 self.errors.push(Error::new_with_path(
657 ErrorKind::Deprecated { tag, old, new },
658 key_span,
659 MaybeTomlPath::uncomputed(item),
660 ));
661 }
662
663 #[cold]
665 pub fn report_unexpected_key(&mut self, tag: u32, item: &Item<'de>, key_span: Span) -> Failed {
666 let path = MaybeTomlPath::uncomputed(item);
667 self.errors.push(Error::new_with_path(
668 ErrorKind::UnexpectedKey { tag },
669 key_span,
670 path,
671 ));
672 Failed
673 }
674}
675
676pub use crate::Failed;
677
678#[cfg_attr(feature = "derive", doc = "```")]
691#[cfg_attr(not(feature = "derive"), doc = "```ignore")]
692#[cfg_attr(feature = "derive", doc = "```")]
709#[cfg_attr(not(feature = "derive"), doc = "```ignore")]
710pub trait FromToml<'de>: Sized {
772 fn from_toml(ctx: &mut Context<'de>, item: &Item<'de>) -> Result<Self, Failed>;
774}
775
776#[diagnostic::on_unimplemented(
785 message = "`{Self}` does not implement `FromFlattened`",
786 note = "if `{Self}` implements `FromToml`, you can use `#[toml(flatten, with = flatten_any)]` instead of a manual `FromFlattened` impl"
787)]
788pub trait FromFlattened<'de>: Sized {
789 type Partial;
791 fn init() -> Self::Partial;
793 fn insert(
795 ctx: &mut Context<'de>,
796 key: &Key<'de>,
797 item: &Item<'de>,
798 partial: &mut Self::Partial,
799 ) -> Result<(), Failed>;
800 fn finish(
804 ctx: &mut Context<'de>,
805 parent: &Table<'de>,
806 partial: Self::Partial,
807 ) -> Result<Self, Failed>;
808}
809
810fn key_from_toml<'de, K: FromToml<'de>>(
812 ctx: &mut Context<'de>,
813 key: &Key<'de>,
814) -> Result<K, Failed> {
815 let item = Item::string_spanned(key.name, key.span);
816 K::from_toml(ctx, &item)
817}
818
819impl<'de, K, V, H> FromFlattened<'de> for std::collections::HashMap<K, V, H>
820where
821 K: Hash + Eq + FromToml<'de>,
822 V: FromToml<'de>,
823 H: Default + BuildHasher,
824{
825 type Partial = Self;
826 fn init() -> Self {
827 std::collections::HashMap::default()
828 }
829 fn insert(
830 ctx: &mut Context<'de>,
831 key: &Key<'de>,
832 item: &Item<'de>,
833 partial: &mut Self::Partial,
834 ) -> Result<(), Failed> {
835 let k = key_from_toml(ctx, key)?;
836 let v = match V::from_toml(ctx, item) {
837 Ok(v) => v,
838 Err(_) => return Err(Failed),
839 };
840 partial.insert(k, v);
841 Ok(())
842 }
843 fn finish(
844 _ctx: &mut Context<'de>,
845 _parent: &Table<'de>,
846 partial: Self::Partial,
847 ) -> Result<Self, Failed> {
848 Ok(partial)
849 }
850}
851
852impl<'de, K, V, H> FromToml<'de> for std::collections::HashMap<K, V, H>
853where
854 K: Hash + Eq + FromToml<'de>,
855 V: FromToml<'de>,
856 H: Default + BuildHasher,
857{
858 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
859 let table = value.require_table(ctx)?;
860 let mut map = std::collections::HashMap::default();
861 let mut had_error = false;
862 for (key, item) in table {
863 let k = match key_from_toml(ctx, key) {
864 Ok(k) => k,
865 Err(_) => {
866 had_error = true;
867 continue;
868 }
869 };
870 match V::from_toml(ctx, item) {
871 Ok(v) => {
872 map.insert(k, v);
873 }
874 Err(_) => had_error = true,
875 }
876 }
877 if had_error { Err(Failed) } else { Ok(map) }
878 }
879}
880
881impl<'de, K, V> FromFlattened<'de> for BTreeMap<K, V>
882where
883 K: Ord + FromToml<'de>,
884 V: FromToml<'de>,
885{
886 type Partial = Self;
887 fn init() -> Self {
888 BTreeMap::new()
889 }
890 fn insert(
891 ctx: &mut Context<'de>,
892 key: &Key<'de>,
893 item: &Item<'de>,
894 partial: &mut Self::Partial,
895 ) -> Result<(), Failed> {
896 let k = key_from_toml(ctx, key)?;
897 let v = match V::from_toml(ctx, item) {
898 Ok(v) => v,
899 Err(_) => return Err(Failed),
900 };
901 partial.insert(k, v);
902 Ok(())
903 }
904 fn finish(
905 _ctx: &mut Context<'de>,
906 _parent: &Table<'de>,
907 partial: Self::Partial,
908 ) -> Result<Self, Failed> {
909 Ok(partial)
910 }
911}
912
913impl<'de> FromFlattened<'de> for Table<'de> {
914 type Partial = Table<'de>;
915 fn init() -> Self::Partial {
916 Table::new()
917 }
918 fn insert(
919 ctx: &mut Context<'de>,
920 key: &Key<'de>,
921 item: &Item<'de>,
922 partial: &mut Self::Partial,
923 ) -> Result<(), Failed> {
924 partial.insert_unique(*key, item.clone_in(ctx.arena), ctx.arena);
925 Ok(())
926 }
927 fn finish(
928 _ctx: &mut Context<'de>,
929 parent: &Table<'de>,
930 mut partial: Self::Partial,
931 ) -> Result<Self, Failed> {
932 partial.meta = parent.meta;
933 Ok(partial)
934 }
935}
936
937impl<'de> FromFlattened<'de> for Item<'de> {
938 type Partial = Table<'de>;
939 fn init() -> Self::Partial {
940 Table::new()
941 }
942 fn insert(
943 ctx: &mut Context<'de>,
944 key: &Key<'de>,
945 item: &Item<'de>,
946 partial: &mut Self::Partial,
947 ) -> Result<(), Failed> {
948 <Table<'de> as FromFlattened<'de>>::insert(ctx, key, item, partial)
949 }
950 fn finish(
951 _ctx: &mut Context<'de>,
952 parent: &Table<'de>,
953 mut partial: Self::Partial,
954 ) -> Result<Self, Failed> {
955 partial.meta = parent.meta;
956 Ok(partial.into_item())
957 }
958}
959
960impl<'de, T: FromToml<'de>, const N: usize> FromToml<'de> for [T; N] {
961 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
962 let boxed_slice = Box::<[T]>::from_toml(ctx, value)?;
963 match <Box<[T; N]>>::try_from(boxed_slice) {
964 Ok(array) => Ok(*array),
965 Err(res) => Err(ctx.push_error(Error::custom(
966 format!(
967 "expected an array with a size of {}, found one with a size of {}",
968 N,
969 res.len()
970 ),
971 value.span_unchecked(),
972 ))),
973 }
974 }
975}
976
977macro_rules! impl_from_toml_tuple {
978 ($len:expr, $($idx:tt => $T:ident, $var:ident),+) => {
979 impl<'de, $($T: FromToml<'de>),+> FromToml<'de> for ($($T,)+) {
980 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
981 let arr = value.require_array(ctx)?;
982 if arr.len() != $len {
983 return Err(ctx.push_error(Error::custom(
984 format!(
985 "expected an array with a size of {}, found one with a size of {}",
986 $len,
987 arr.len()
988 ),
989 value.span_unchecked(),
990 )));
991 }
992 let slice = arr.as_slice();
993 let mut had_error = false;
994 $(
995 let $var = match $T::from_toml(ctx, &slice[$idx]) {
996 Ok(v) => Some(v),
997 Err(_) => { had_error = true; None }
998 };
999 )+
1000 if had_error {
1001 return Err(Failed);
1002 }
1003 Ok(($($var.unwrap(),)+))
1004 }
1005 }
1006 };
1007}
1008
1009impl_from_toml_tuple!(1, 0 => A, a);
1010impl_from_toml_tuple!(2, 0 => A, a, 1 => B, b);
1011impl_from_toml_tuple!(3, 0 => A, a, 1 => B, b, 2 => C, c);
1012
1013impl<'de> FromToml<'de> for String {
1014 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1015 match value.as_str() {
1016 Some(s) => Ok(s.to_string()),
1017 None => Err(ctx.report_expected_but_found(&"a string", value)),
1018 }
1019 }
1020}
1021
1022impl<'de> FromToml<'de> for PathBuf {
1023 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1024 match value.as_str() {
1025 Some(s) => Ok(PathBuf::from(s)),
1026 None => Err(ctx.report_expected_but_found(&"a path", value)),
1027 }
1028 }
1029}
1030
1031impl<'de, T: FromToml<'de>> FromToml<'de> for Option<T> {
1032 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1033 T::from_toml(ctx, value).map(Some)
1034 }
1035}
1036
1037impl<'de, T: FromToml<'de>> FromToml<'de> for Box<T> {
1038 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1039 match T::from_toml(ctx, value) {
1040 Ok(v) => Ok(Box::new(v)),
1041 Err(e) => Err(e),
1042 }
1043 }
1044}
1045impl<'de, T: FromToml<'de>> FromToml<'de> for Box<[T]> {
1046 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1047 match Vec::<T>::from_toml(ctx, value) {
1048 Ok(vec) => Ok(vec.into_boxed_slice()),
1049 Err(e) => Err(e),
1050 }
1051 }
1052}
1053impl<'de> FromToml<'de> for Box<str> {
1054 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1055 match value.value() {
1056 item::Value::String(&s) => Ok(s.into()),
1057 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1058 }
1059 }
1060}
1061impl<'de> FromToml<'de> for &'de str {
1062 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1063 match value.value() {
1064 item::Value::String(s) => Ok(*s),
1065 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1066 }
1067 }
1068}
1069
1070impl<'de> FromToml<'de> for std::borrow::Cow<'de, str> {
1071 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1072 match value.value() {
1073 item::Value::String(s) => Ok(std::borrow::Cow::Borrowed(*s)),
1074 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1075 }
1076 }
1077}
1078
1079impl<'de> FromToml<'de> for bool {
1080 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1081 match value.as_bool() {
1082 Some(b) => Ok(b),
1083 None => Err(ctx.report_expected_but_found(&"a bool", value)),
1084 }
1085 }
1086}
1087
1088fn deser_integer_ctx<'de>(
1089 ctx: &mut Context<'de>,
1090 value: &Item<'de>,
1091 min: i128,
1092 max: i128,
1093 ty: &'static &'static str,
1094 range: &'static &'static str,
1095) -> Result<i128, Failed> {
1096 match value.as_i128() {
1097 Some(i) if i >= min && i <= max => Ok(i),
1098 Some(_) => Err(ctx.report_out_of_range(ty, range, value)),
1099 None => Err(ctx.report_expected_but_found(&"an integer", value)),
1100 }
1101}
1102
1103macro_rules! integer_new {
1104 ($($num:ty => $range:literal),+) => {$(
1105 impl<'de> FromToml<'de> for $num {
1106 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1107 match deser_integer_ctx(ctx, value, <$num>::MIN as i128, <$num>::MAX as i128, &stringify!($num), &$range) {
1108 Ok(i) => Ok(i as $num),
1109 Err(e) => Err(e),
1110 }
1111 }
1112 }
1113 )+};
1114}
1115
1116integer_new!(
1117 i8 => "-128..=127",
1118 i16 => "-32768..=32767",
1119 i32 => "-2147483648..=2147483647",
1120 u8 => "0..=255",
1121 u16 => "0..=65535",
1122 u32 => "0..=4294967295"
1123);
1124
1125impl<'de> FromToml<'de> for isize {
1126 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1127 #[cfg(target_pointer_width = "32")]
1128 const RANGE: &str = "-2147483648..=2147483647";
1129 #[cfg(target_pointer_width = "64")]
1130 const RANGE: &str = "-9223372036854775808..=9223372036854775807";
1131 match deser_integer_ctx(
1132 ctx,
1133 value,
1134 isize::MIN as i128,
1135 isize::MAX as i128,
1136 &"isize",
1137 &RANGE,
1138 ) {
1139 Ok(i) => Ok(i as isize),
1140 Err(e) => Err(e),
1141 }
1142 }
1143}
1144
1145impl<'de> FromToml<'de> for i64 {
1146 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1147 match deser_integer_ctx(
1148 ctx,
1149 value,
1150 i64::MIN as i128,
1151 i64::MAX as i128,
1152 &"i64",
1153 &"-9223372036854775808..=9223372036854775807",
1154 ) {
1155 Ok(i) => Ok(i as i64),
1156 Err(e) => Err(e),
1157 }
1158 }
1159}
1160
1161impl<'de> FromToml<'de> for u64 {
1162 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1163 match deser_integer_ctx(
1164 ctx,
1165 value,
1166 0,
1167 u64::MAX as i128,
1168 &"u64",
1169 &"0..=18446744073709551615",
1170 ) {
1171 Ok(i) => Ok(i as u64),
1172 Err(e) => Err(e),
1173 }
1174 }
1175}
1176
1177impl<'de> FromToml<'de> for i128 {
1178 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1179 match deser_integer_ctx(
1180 ctx,
1181 value,
1182 i128::MIN,
1183 i128::MAX,
1184 &"i128",
1185 &"-170141183460469231731687303715884105728..=170141183460469231731687303715884105727",
1186 ) {
1187 Ok(i) => Ok(i),
1188 Err(e) => Err(e),
1189 }
1190 }
1191}
1192
1193impl<'de> FromToml<'de> for u128 {
1194 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1195 match deser_integer_ctx(
1196 ctx,
1197 value,
1198 0,
1199 i128::MAX,
1200 &"u128",
1201 &"0..=340282366920938463463374607431768211455",
1202 ) {
1203 Ok(i) => Ok(i as u128),
1204 Err(e) => Err(e),
1205 }
1206 }
1207}
1208
1209impl<'de> FromToml<'de> for usize {
1210 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1211 #[cfg(target_pointer_width = "32")]
1212 const RANGE: &str = "0..=4294967295";
1213 #[cfg(target_pointer_width = "64")]
1214 const RANGE: &str = "0..=18446744073709551615";
1215 match deser_integer_ctx(ctx, value, 0, usize::MAX as i128, &"usize", &RANGE) {
1216 Ok(i) => Ok(i as usize),
1217 Err(e) => Err(e),
1218 }
1219 }
1220}
1221
1222impl<'de> FromToml<'de> for f32 {
1223 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1224 match value.as_f64() {
1225 Some(f) => Ok(f as f32),
1226 None => Err(ctx.report_expected_but_found(&"a float", value)),
1227 }
1228 }
1229}
1230
1231impl<'de> FromToml<'de> for f64 {
1232 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1233 match value.as_f64() {
1234 Some(f) => Ok(f),
1235 None => Err(ctx.report_expected_but_found(&"a float", value)),
1236 }
1237 }
1238}
1239
1240impl<'de, T> FromToml<'de> for Vec<T>
1241where
1242 T: FromToml<'de>,
1243{
1244 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1245 let arr = value.require_array(ctx)?;
1246 let mut result = Vec::with_capacity(arr.len());
1247 let mut had_error = false;
1248 for item in arr {
1249 match T::from_toml(ctx, item) {
1250 Ok(v) => result.push(v),
1251 Err(_) => had_error = true,
1252 }
1253 }
1254 if had_error { Err(Failed) } else { Ok(result) }
1255 }
1256}
1257
1258impl<'de, T> FromToml<'de> for BTreeSet<T>
1259where
1260 T: Ord + FromToml<'de>,
1261{
1262 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1263 let arr = value.require_array(ctx)?;
1264 let mut result = BTreeSet::new();
1265 let mut had_error = false;
1266 for item in arr {
1267 match T::from_toml(ctx, item) {
1268 Ok(v) => {
1269 result.insert(v);
1270 }
1271 Err(_) => had_error = true,
1272 }
1273 }
1274 if had_error { Err(Failed) } else { Ok(result) }
1275 }
1276}
1277
1278impl<'de, K, V> FromToml<'de> for BTreeMap<K, V>
1279where
1280 K: Ord + FromToml<'de>,
1281 V: FromToml<'de>,
1282{
1283 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1284 let table = value.require_table(ctx)?;
1285 let mut map = BTreeMap::new();
1286 let mut had_error = false;
1287 for (key, item) in table {
1288 let k = match key_from_toml(ctx, key) {
1289 Ok(k) => k,
1290 Err(_) => {
1291 had_error = true;
1292 continue;
1293 }
1294 };
1295 match V::from_toml(ctx, item) {
1296 Ok(v) => {
1297 map.insert(k, v);
1298 }
1299 Err(_) => had_error = true,
1300 }
1301 }
1302 if had_error { Err(Failed) } else { Ok(map) }
1303 }
1304}
1305
1306impl<'de> Item<'de> {
1307 #[doc(alias = "expect_custom_string")]
1313 pub fn require_custom_string(
1314 &self,
1315 ctx: &mut Context<'de>,
1316 expected: &'static &'static str,
1317 ) -> Result<&'de str, Failed> {
1318 match self.value() {
1319 item::Value::String(s) => Ok(*s),
1320 _ => Err(ctx.report_expected_but_found(expected, self)),
1321 }
1322 }
1323 #[doc(alias = "expect_string")]
1325 pub fn require_string(&self, ctx: &mut Context<'de>) -> Result<&'de str, Failed> {
1326 match self.value() {
1327 item::Value::String(s) => Ok(*s),
1328 _ => Err(ctx.report_expected_but_found(&"a string", self)),
1329 }
1330 }
1331
1332 #[doc(alias = "expect_array")]
1334 pub fn require_array(&self, ctx: &mut Context<'de>) -> Result<&crate::Array<'de>, Failed> {
1335 match self.as_array() {
1336 Some(arr) => Ok(arr),
1337 None => Err(ctx.report_expected_but_found(&"an array", self)),
1338 }
1339 }
1340
1341 #[doc(alias = "expect_table")]
1343 pub fn require_table(&self, ctx: &mut Context<'de>) -> Result<&crate::Table<'de>, Failed> {
1344 match self.as_table() {
1345 Some(table) => Ok(table),
1346 None => Err(ctx.report_expected_but_found(&"a table", self)),
1347 }
1348 }
1349
1350 pub fn table_helper<'ctx, 'item>(
1355 &'item self,
1356 ctx: &'ctx mut Context<'de>,
1357 ) -> Result<TableHelper<'ctx, 'item, 'de>, Failed> {
1358 let Some(table) = self.as_table() else {
1359 return Err(ctx.report_expected_but_found(&"a table", self));
1360 };
1361 Ok(TableHelper::new(ctx, table))
1362 }
1363}
1364
1365#[derive(Debug)]
1381pub struct FromTomlError {
1382 pub errors: Vec<Error>,
1384}
1385
1386impl Display for FromTomlError {
1387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1388 let Some(first) = self.errors.first() else {
1389 return f.write_str("deserialization failed");
1390 };
1391 Display::fmt(first, f)?;
1392 let remaining = self.errors.len() - 1;
1393 if remaining > 0 {
1394 write!(
1395 f,
1396 " (+{remaining} more error{})",
1397 if remaining == 1 { "" } else { "s" }
1398 )?;
1399 }
1400 Ok(())
1401 }
1402}
1403
1404impl std::error::Error for FromTomlError {}
1405
1406impl From<Error> for FromTomlError {
1407 fn from(error: Error) -> Self {
1408 Self {
1409 errors: vec![error],
1410 }
1411 }
1412}
1413
1414impl From<Vec<Error>> for FromTomlError {
1415 fn from(errors: Vec<Error>) -> Self {
1416 Self { errors }
1417 }
1418}
1419
1420impl IntoIterator for FromTomlError {
1421 type Item = Error;
1422 type IntoIter = std::vec::IntoIter<Error>;
1423 fn into_iter(self) -> Self::IntoIter {
1424 self.errors.into_iter()
1425 }
1426}
1427
1428impl<'a> IntoIterator for &'a FromTomlError {
1429 type Item = &'a Error;
1430 type IntoIter = std::slice::Iter<'a, Error>;
1431 fn into_iter(self) -> Self::IntoIter {
1432 self.errors.iter()
1433 }
1434}