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, Option<&mut MaybeTomlPath>)> = Vec::new();
31 for error in errors.iter_mut() {
32 if error.path.is_uncomputed() {
33 pending.push((
34 error.path.uncomputed_ptr() as *const u8,
35 Some(&mut error.path),
36 ));
37 }
38 }
39 if pending.is_empty() {
40 return;
41 }
42 pending.sort_unstable_by_key(|(addr, _)| *addr as usize);
43
44 let mut path_stack: [PathComponent<'_>; 32] = [PathComponent::Index(0); 32];
45 compute_paths_walk(root.as_item(), &mut pending, &mut path_stack, 0);
46}
47
48fn pending_region_start(
49 pending: &[(*const u8, Option<&mut MaybeTomlPath>)],
50 base_addr: usize,
51) -> usize {
52 pending.partition_point(|p| (p.0 as usize) < base_addr)
53}
54
55fn compute_paths_walk<'de>(
56 item: &Item<'de>,
57 pending: &mut [(*const u8, Option<&mut MaybeTomlPath>)],
58 path_stack: &mut [PathComponent<'de>; 32],
59 path_depth: usize,
60) {
61 if path_depth >= path_stack.len() {
62 return;
63 }
64 match item.value() {
65 Value::Table(table) => {
66 let entries = table.entries();
67 if entries.is_empty() {
68 return;
69 }
70 let entry_size = std::mem::size_of::<(Key<'_>, Item<'_>)>();
71 let base = entries.as_ptr() as *const u8;
72 let end = unsafe { base.add(entries.len() * entry_size) };
74 let base_addr = base as usize;
75 let end_addr = end as usize;
76
77 let start_idx = pending_region_start(pending, base_addr);
78 for slot in &mut pending[start_idx..] {
79 if (slot.0 as usize) >= end_addr {
80 break;
81 }
82 let Some(path) = slot.1.take() else { continue };
83 let byte_offset = unsafe { slot.0.byte_offset_from(base) } as usize;
85 let entry_index = byte_offset / entry_size;
86 path_stack[path_depth] = PathComponent::Key(entries[entry_index].0);
87 *path = MaybeTomlPath::from_components(&path_stack[..path_depth + 1]);
88 }
89
90 for (key, child) in table {
91 path_stack[path_depth] = PathComponent::Key(*key);
92 compute_paths_walk(child, pending, path_stack, path_depth + 1);
93 }
94 }
95 Value::Array(array) => {
96 let slice = array.as_slice();
97 if slice.is_empty() {
98 return;
99 }
100 let item_size = std::mem::size_of::<Item<'_>>();
101 let base = slice.as_ptr() as *const u8;
102 let end = unsafe { base.add(slice.len() * item_size) };
104 let base_addr = base as usize;
105 let end_addr = end as usize;
106
107 let start_idx = pending_region_start(pending, base_addr);
108 for slot in &mut pending[start_idx..] {
109 if (slot.0 as usize) >= end_addr {
110 break;
111 }
112 let Some(path) = slot.1.take() else { continue };
113 let byte_offset = unsafe { slot.0.byte_offset_from(base) } as usize;
115 let elem_index = byte_offset / item_size;
116 path_stack[path_depth] = PathComponent::Index(elem_index);
117 *path = MaybeTomlPath::from_components(&path_stack[..path_depth + 1]);
118 }
119
120 let mut idx = 0; for child in array {
122 path_stack[path_depth] = PathComponent::Index(idx);
123 compute_paths_walk(child, pending, path_stack, path_depth + 1);
124 idx += 1;
125 }
126 }
127 _ => (),
128 }
129}
130
131pub struct TableHelper<'ctx, 'table, 'de> {
166 pub ctx: &'ctx mut Context<'de>,
167 pub table: &'table Table<'de>,
168 table_id: i32,
170 used_count: u32,
172 used: &'de mut FixedBitset,
173}
174
175#[repr(transparent)]
176struct FixedBitset([u64]);
177
178impl FixedBitset {
179 #[allow(clippy::mut_from_ref)]
180 pub fn new(capacity: usize, arena: &Arena) -> &mut FixedBitset {
181 let bitset_bucket_count = capacity.div_ceil(64);
182 let bitset = arena
183 .alloc(bitset_bucket_count * std::mem::size_of::<u64>())
184 .cast::<u64>();
185 for offset in 0..bitset_bucket_count {
186 unsafe {
189 bitset.add(offset).write(0);
190 }
191 }
192 let slice = unsafe { std::slice::from_raw_parts_mut(bitset.as_ptr(), bitset_bucket_count) };
194 unsafe { &mut *(slice as *mut [u64] as *mut FixedBitset) }
196 }
197
198 pub fn insert(&mut self, index: usize) -> bool {
199 let offset = index >> 6;
200 let bit = 1 << (index & 63);
201 let old = self.0[offset];
202 self.0[offset] |= bit;
203 old & bit == 0
204 }
205
206 pub fn get(&self, index: usize) -> bool {
207 let offset = index >> 6;
208 let bit = 1 << (index & 63);
209 self.0[offset] & bit != 0
210 }
211}
212
213pub struct RemainingEntriesIter<'t, 'de> {
218 entries: &'t [(Key<'de>, Item<'de>)],
219 remaining_cells: std::slice::Iter<'de, u64>,
220 bits: u64,
221}
222impl RemainingEntriesIter<'_, '_> {
223 fn next_bucket(&mut self) -> bool {
224 let Some(bucket) = self.remaining_cells.next() else {
225 return false;
226 };
227 debug_assert!(self.entries.len() > 64);
228 let Some(remaining) = self.entries.get(64..) else {
229 return false;
230 };
231 self.entries = remaining;
232 self.bits = !*bucket;
233 true
234 }
235}
236
237impl<'t, 'de> Iterator for RemainingEntriesIter<'t, 'de> {
238 type Item = &'t (Key<'de>, Item<'de>);
239
240 fn next(&mut self) -> Option<Self::Item> {
241 loop {
242 if let Some(bits) = NonZeroU64::new(self.bits) {
243 let bit_index = bits.trailing_zeros() as usize;
244 self.bits &= self.bits - 1;
245 return self.entries.get(bit_index);
246 }
247 if !self.next_bucket() {
248 return None;
249 }
250 }
251 }
252}
253
254impl<'ctx, 't, 'de> TableHelper<'ctx, 't, 'de> {
255 pub fn new(ctx: &'ctx mut Context<'de>, table: &'t Table<'de>) -> Self {
260 let table_id = if table.len() > INDEXED_TABLE_THRESHOLD && table.meta.is_span_mode() {
261 table.entries()[0].0.span.start as i32
262 } else {
263 -1
264 };
265 Self {
266 used: FixedBitset::new(table.len(), ctx.arena),
267 ctx,
268 table,
269 table_id,
270 used_count: 0,
271 }
272 }
273
274 pub fn get_entry(&self, key: &str) -> Option<&'t (Key<'de>, Item<'de>)> {
281 if self.table_id < 0 {
282 for entry in self.table.entries() {
283 if entry.0.name == key {
284 return Some(entry);
285 }
286 }
287 None
288 } else {
289 match self.ctx.index.get(&KeyRef::new(key, self.table_id as u32)) {
290 Some(index) => Some(&self.table.entries()[*index]),
291 None => None,
292 }
293 }
294 }
295
296 pub fn required_mapped<T>(
307 &mut self,
308 name: &'static str,
309 func: fn(&Item<'de>) -> Result<T, Error>,
310 ) -> Result<T, Failed> {
311 let Some((_, item)) = self.optional_entry(name) else {
312 return Err(self.report_missing_field(name));
313 };
314
315 match func(item) {
316 Ok(t) => Ok(t),
317 Err(e) => Err(self.ctx.push_error(Error::custom(e, item.span_unchecked()))),
318 }
319 }
320
321 pub fn optional_mapped<T>(
328 &mut self,
329 name: &'static str,
330 func: fn(&Item<'de>) -> Result<T, Error>,
331 ) -> Option<T> {
332 let Some((_, item)) = self.optional_entry(name) else {
333 return None;
334 };
335
336 match func(item) {
337 Ok(t) => Some(t),
338 Err(e) => {
339 self.ctx.push_error(Error::custom(e, item.span_unchecked()));
340 None
341 }
342 }
343 }
344
345 pub fn required_item(&mut self, name: &'static str) -> Result<&'t Item<'de>, Failed> {
356 if let Ok((_, item)) = self.required_entry(name) {
357 Ok(item)
358 } else {
359 Err(self.report_missing_field(name))
360 }
361 }
362
363 pub fn optional_item(&mut self, name: &'static str) -> Option<&'t Item<'de>> {
369 if let Some((_, item)) = self.optional_entry(name) {
370 Some(item)
371 } else {
372 None
373 }
374 }
375
376 pub fn required_entry(
387 &mut self,
388 name: &'static str,
389 ) -> Result<&'t (Key<'de>, Item<'de>), Failed> {
390 match self.optional_entry(name) {
391 Some(entry) => Ok(entry),
392 None => Err(self.report_missing_field(name)),
393 }
394 }
395
396 pub fn optional_entry(&mut self, key: &str) -> Option<&'t (Key<'de>, Item<'de>)> {
402 let Some(entry) = self.get_entry(key) else {
403 return None;
404 };
405 let index = unsafe {
412 let ptr = entry as *const (Key<'de>, Item<'de>);
413 let base = self.table.entries().as_ptr();
414 ptr.offset_from(base) as usize
415 };
416 if self.used.insert(index) {
417 self.used_count += 1;
418 }
419 Some(entry)
420 }
421
422 #[cold]
423 fn report_missing_field(&mut self, name: &'static str) -> Failed {
424 self.ctx.errors.push(Error::new_with_path(
425 ErrorKind::MissingField(name),
426 self.table.span(),
427 MaybeTomlPath::uncomputed(self.table.as_item()),
428 ));
429 Failed
430 }
431
432 pub fn required<T: FromToml<'de>>(&mut self, name: &'static str) -> Result<T, Failed> {
442 let Some((_, val)) = self.optional_entry(name) else {
443 return Err(self.report_missing_field(name));
444 };
445
446 T::from_toml(self.ctx, val)
447 }
448
449 pub fn optional<T: FromToml<'de>>(&mut self, name: &str) -> Option<T> {
456 let Some((_, val)) = self.optional_entry(name) else {
457 return None;
458 };
459
460 #[allow(clippy::manual_ok_err)]
461 match T::from_toml(self.ctx, val) {
462 Ok(value) => Some(value),
463 Err(_) => None,
464 }
465 }
466
467 pub fn remaining_count(&self) -> usize {
469 self.table.len() - self.used_count as usize
470 }
471
472 pub fn into_remaining(self) -> RemainingEntriesIter<'t, 'de> {
474 let entries = self.table.entries();
475 let mut remaining_cells = self.used.0.iter();
476 RemainingEntriesIter {
477 bits: if let Some(value) = remaining_cells.next() {
478 !*value
479 } else {
480 0
481 },
482 entries,
483 remaining_cells,
484 }
485 }
486
487 #[doc(alias = "expect_empty")]
499 #[inline(never)]
500 pub fn require_empty(self) -> Result<(), Failed> {
501 if self.used_count as usize == self.table.len() {
502 return Ok(());
503 }
504
505 let mut had_unexpected = false;
506 for (i, (key, item)) in self.table.entries().iter().enumerate() {
507 if !self.used.get(i) {
508 self.ctx.errors.push(Error {
509 kind: ErrorInner::Static(ErrorKind::UnexpectedKey { tag: 0 }),
510 span: key.span,
511 path: MaybeTomlPath::uncomputed(item),
512 });
513
514 had_unexpected = true;
515 }
516 }
517
518 if had_unexpected { Err(Failed) } else { Ok(()) }
519 }
520}
521
522pub struct Context<'de> {
531 pub arena: &'de Arena,
532 pub(crate) index: HashMap<KeyRef<'de>, usize>,
533 pub errors: Vec<Error>,
534 pub(crate) source: &'de str,
535}
536
537impl<'de> Context<'de> {
538 pub fn source(&self) -> &'de str {
540 self.source
541 }
542
543 #[cold]
545 pub fn report_expected_but_found(
546 &mut self,
547 message: &'static &'static str,
548 found: &Item<'de>,
549 ) -> Failed {
550 let path = MaybeTomlPath::uncomputed(found);
551 self.errors.push(Error::new_with_path(
552 ErrorKind::Wanted {
553 expected: message,
554 found: found.type_str(),
555 },
556 found.span(),
557 path,
558 ));
559 Failed
560 }
561
562 #[cold]
564 pub fn report_unexpected_variant(
565 &mut self,
566 expected: &'static [&'static str],
567 found: &Item<'de>,
568 ) -> Failed {
569 let path = MaybeTomlPath::uncomputed(found);
570 self.errors.push(Error::new_with_path(
571 ErrorKind::UnexpectedVariant { expected },
572 found.span(),
573 path,
574 ));
575 Failed
576 }
577
578 #[cold]
580 pub fn report_error_at(&mut self, message: &'static str, at: Span) -> Failed {
581 self.errors.push(Error::custom_static(message, at));
582 Failed
583 }
584 #[cold]
586 pub fn push_error(&mut self, error: Error) -> Failed {
587 self.errors.push(error);
588 Failed
589 }
590
591 #[cold]
604 pub fn report_custom_error(&mut self, error: impl ToString, item: &Item<'de>) -> Failed {
605 self.push_error(Error::custom_at(error, item))
606 }
607
608 #[cold]
610 pub fn report_out_of_range(
611 &mut self,
612 ty: &'static &'static str,
613 range: &'static &'static str,
614 found: &Item<'de>,
615 ) -> Failed {
616 let path = MaybeTomlPath::uncomputed(found);
617 self.errors.push(Error::new_with_path(
618 ErrorKind::OutOfRange { ty, range },
619 found.span(),
620 path,
621 ));
622 Failed
623 }
624
625 #[cold]
630 pub fn report_missing_field(&mut self, name: &'static str, item: &Item<'de>) -> Failed {
631 let path = MaybeTomlPath::uncomputed(item);
632 self.errors.push(Error::new_with_path(
633 ErrorKind::MissingField(name),
634 item.span(),
635 path,
636 ));
637 Failed
638 }
639
640 #[cold]
645 pub fn report_duplicate_field(
646 &mut self,
647 name: &'static str,
648 key_span: Span,
649 first_key_span: Span,
650 item: &Item<'de>,
651 ) -> Failed {
652 self.push_error(Error::new_with_path(
653 ErrorKind::DuplicateField {
654 field: name,
655 first: first_key_span,
656 },
657 key_span,
658 MaybeTomlPath::uncomputed(item),
659 ))
660 }
661
662 #[cold]
667 pub fn report_deprecated_field(
668 &mut self,
669 tag: u32,
670 old: &'static &'static str,
671 new: &'static &'static str,
672 key_span: Span,
673 item: &Item<'de>,
674 ) {
675 self.errors.push(Error::new_with_path(
676 ErrorKind::Deprecated { tag, old, new },
677 key_span,
678 MaybeTomlPath::uncomputed(item),
679 ));
680 }
681
682 #[cold]
684 pub fn report_unexpected_key(&mut self, tag: u32, item: &Item<'de>, key_span: Span) -> Failed {
685 let path = MaybeTomlPath::uncomputed(item);
686 self.errors.push(Error::new_with_path(
687 ErrorKind::UnexpectedKey { tag },
688 key_span,
689 path,
690 ));
691 Failed
692 }
693}
694
695pub use crate::Failed;
696
697#[cfg_attr(feature = "derive", doc = "```")]
710#[cfg_attr(not(feature = "derive"), doc = "```ignore")]
711#[cfg_attr(feature = "derive", doc = "```")]
728#[cfg_attr(not(feature = "derive"), doc = "```ignore")]
729pub trait FromToml<'de>: Sized {
791 fn from_toml(ctx: &mut Context<'de>, item: &Item<'de>) -> Result<Self, Failed>;
793}
794
795#[diagnostic::on_unimplemented(
804 message = "`{Self}` does not implement `FromFlattened`",
805 note = "if `{Self}` implements `FromToml`, you can use `#[toml(flatten, with = flatten_any)]` instead of a manual `FromFlattened` impl"
806)]
807pub trait FromFlattened<'de>: Sized {
808 type Partial;
810 fn init() -> Self::Partial;
812 fn insert(
814 ctx: &mut Context<'de>,
815 key: &Key<'de>,
816 item: &Item<'de>,
817 partial: &mut Self::Partial,
818 ) -> Result<(), Failed>;
819 fn finish(
823 ctx: &mut Context<'de>,
824 parent: &Table<'de>,
825 partial: Self::Partial,
826 ) -> Result<Self, Failed>;
827}
828
829fn key_from_toml<'de, K: FromToml<'de>>(
831 ctx: &mut Context<'de>,
832 key: &Key<'de>,
833) -> Result<K, Failed> {
834 let item = Item::string_spanned(key.name, key.span);
835 K::from_toml(ctx, &item)
836}
837
838impl<'de, K, V, H> FromFlattened<'de> for std::collections::HashMap<K, V, H>
839where
840 K: Hash + Eq + FromToml<'de>,
841 V: FromToml<'de>,
842 H: Default + BuildHasher,
843{
844 type Partial = Self;
845 fn init() -> Self {
846 std::collections::HashMap::default()
847 }
848 fn insert(
849 ctx: &mut Context<'de>,
850 key: &Key<'de>,
851 item: &Item<'de>,
852 partial: &mut Self::Partial,
853 ) -> Result<(), Failed> {
854 let k = key_from_toml(ctx, key)?;
855 let v = match V::from_toml(ctx, item) {
856 Ok(v) => v,
857 Err(_) => return Err(Failed),
858 };
859 partial.insert(k, v);
860 Ok(())
861 }
862 fn finish(
863 _ctx: &mut Context<'de>,
864 _parent: &Table<'de>,
865 partial: Self::Partial,
866 ) -> Result<Self, Failed> {
867 Ok(partial)
868 }
869}
870
871impl<'de, K, V, H> FromToml<'de> for std::collections::HashMap<K, V, H>
872where
873 K: Hash + Eq + FromToml<'de>,
874 V: FromToml<'de>,
875 H: Default + BuildHasher,
876{
877 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
878 let table = value.require_table(ctx)?;
879 let mut map = std::collections::HashMap::default();
880 let mut had_error = false;
881 for (key, item) in table {
882 let k = match key_from_toml(ctx, key) {
883 Ok(k) => k,
884 Err(_) => {
885 had_error = true;
886 continue;
887 }
888 };
889 match V::from_toml(ctx, item) {
890 Ok(v) => {
891 map.insert(k, v);
892 }
893 Err(_) => had_error = true,
894 }
895 }
896 if had_error { Err(Failed) } else { Ok(map) }
897 }
898}
899
900impl<'de, K, V> FromFlattened<'de> for BTreeMap<K, V>
901where
902 K: Ord + FromToml<'de>,
903 V: FromToml<'de>,
904{
905 type Partial = Self;
906 fn init() -> Self {
907 BTreeMap::new()
908 }
909 fn insert(
910 ctx: &mut Context<'de>,
911 key: &Key<'de>,
912 item: &Item<'de>,
913 partial: &mut Self::Partial,
914 ) -> Result<(), Failed> {
915 let k = key_from_toml(ctx, key)?;
916 let v = match V::from_toml(ctx, item) {
917 Ok(v) => v,
918 Err(_) => return Err(Failed),
919 };
920 partial.insert(k, v);
921 Ok(())
922 }
923 fn finish(
924 _ctx: &mut Context<'de>,
925 _parent: &Table<'de>,
926 partial: Self::Partial,
927 ) -> Result<Self, Failed> {
928 Ok(partial)
929 }
930}
931
932impl<'de> FromFlattened<'de> for Table<'de> {
933 type Partial = Table<'de>;
934 fn init() -> Self::Partial {
935 Table::new()
936 }
937 fn insert(
938 ctx: &mut Context<'de>,
939 key: &Key<'de>,
940 item: &Item<'de>,
941 partial: &mut Self::Partial,
942 ) -> Result<(), Failed> {
943 partial.insert_unique(*key, item.clone_in(ctx.arena), ctx.arena);
944 Ok(())
945 }
946 fn finish(
947 _ctx: &mut Context<'de>,
948 parent: &Table<'de>,
949 mut partial: Self::Partial,
950 ) -> Result<Self, Failed> {
951 partial.meta = parent.meta;
952 Ok(partial)
953 }
954}
955
956impl<'de> FromFlattened<'de> for Item<'de> {
957 type Partial = Table<'de>;
958 fn init() -> Self::Partial {
959 Table::new()
960 }
961 fn insert(
962 ctx: &mut Context<'de>,
963 key: &Key<'de>,
964 item: &Item<'de>,
965 partial: &mut Self::Partial,
966 ) -> Result<(), Failed> {
967 <Table<'de> as FromFlattened<'de>>::insert(ctx, key, item, partial)
968 }
969 fn finish(
970 _ctx: &mut Context<'de>,
971 parent: &Table<'de>,
972 mut partial: Self::Partial,
973 ) -> Result<Self, Failed> {
974 partial.meta = parent.meta;
975 Ok(partial.into_item())
976 }
977}
978
979impl<'de, T: FromToml<'de>, const N: usize> FromToml<'de> for [T; N] {
980 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
981 let boxed_slice = Box::<[T]>::from_toml(ctx, value)?;
982 match <Box<[T; N]>>::try_from(boxed_slice) {
983 Ok(array) => Ok(*array),
984 Err(res) => Err(ctx.push_error(Error::custom(
985 format!(
986 "expected an array with a size of {}, found one with a size of {}",
987 N,
988 res.len()
989 ),
990 value.span_unchecked(),
991 ))),
992 }
993 }
994}
995
996macro_rules! impl_from_toml_tuple {
997 ($len:expr, $($idx:tt => $T:ident, $var:ident),+) => {
998 impl<'de, $($T: FromToml<'de>),+> FromToml<'de> for ($($T,)+) {
999 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1000 let arr = value.require_array(ctx)?;
1001 if arr.len() != $len {
1002 return Err(ctx.push_error(Error::custom(
1003 format!(
1004 "expected an array with a size of {}, found one with a size of {}",
1005 $len,
1006 arr.len()
1007 ),
1008 value.span_unchecked(),
1009 )));
1010 }
1011 let slice = arr.as_slice();
1012 let mut had_error = false;
1013 $(
1014 let $var = match $T::from_toml(ctx, &slice[$idx]) {
1015 Ok(v) => Some(v),
1016 Err(_) => { had_error = true; None }
1017 };
1018 )+
1019 if had_error {
1020 return Err(Failed);
1021 }
1022 Ok(($($var.unwrap(),)+))
1023 }
1024 }
1025 };
1026}
1027
1028impl_from_toml_tuple!(1, 0 => A, a);
1029impl_from_toml_tuple!(2, 0 => A, a, 1 => B, b);
1030impl_from_toml_tuple!(3, 0 => A, a, 1 => B, b, 2 => C, c);
1031
1032impl<'de> FromToml<'de> for String {
1033 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1034 match value.as_str() {
1035 Some(s) => Ok(s.to_string()),
1036 None => Err(ctx.report_expected_but_found(&"a string", value)),
1037 }
1038 }
1039}
1040
1041impl<'de> FromToml<'de> for PathBuf {
1042 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1043 match value.as_str() {
1044 Some(s) => Ok(PathBuf::from(s)),
1045 None => Err(ctx.report_expected_but_found(&"a path", value)),
1046 }
1047 }
1048}
1049
1050impl<'de, T: FromToml<'de>> FromToml<'de> for Option<T> {
1051 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1052 T::from_toml(ctx, value).map(Some)
1053 }
1054}
1055
1056impl<'de, T: FromToml<'de>> FromToml<'de> for Box<T> {
1057 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1058 match T::from_toml(ctx, value) {
1059 Ok(v) => Ok(Box::new(v)),
1060 Err(e) => Err(e),
1061 }
1062 }
1063}
1064impl<'de, T: FromToml<'de>> FromToml<'de> for Box<[T]> {
1065 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1066 match Vec::<T>::from_toml(ctx, value) {
1067 Ok(vec) => Ok(vec.into_boxed_slice()),
1068 Err(e) => Err(e),
1069 }
1070 }
1071}
1072impl<'de> FromToml<'de> for Box<str> {
1073 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1074 match value.value() {
1075 item::Value::String(&s) => Ok(s.into()),
1076 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1077 }
1078 }
1079}
1080impl<'de> FromToml<'de> for &'de str {
1081 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1082 match value.value() {
1083 item::Value::String(s) => Ok(*s),
1084 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1085 }
1086 }
1087}
1088
1089impl<'de> FromToml<'de> for std::borrow::Cow<'de, str> {
1090 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1091 match value.value() {
1092 item::Value::String(s) => Ok(std::borrow::Cow::Borrowed(*s)),
1093 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1094 }
1095 }
1096}
1097
1098impl<'de> FromToml<'de> for bool {
1099 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1100 match value.as_bool() {
1101 Some(b) => Ok(b),
1102 None => Err(ctx.report_expected_but_found(&"a bool", value)),
1103 }
1104 }
1105}
1106
1107fn deser_integer_ctx<'de>(
1108 ctx: &mut Context<'de>,
1109 value: &Item<'de>,
1110 min: i128,
1111 max: i128,
1112 ty: &'static &'static str,
1113 range: &'static &'static str,
1114) -> Result<i128, Failed> {
1115 match value.as_i128() {
1116 Some(i) if i >= min && i <= max => Ok(i),
1117 Some(_) => Err(ctx.report_out_of_range(ty, range, value)),
1118 None => Err(ctx.report_expected_but_found(&"an integer", value)),
1119 }
1120}
1121
1122macro_rules! integer_new {
1123 ($($num:ty => $range:literal),+) => {$(
1124 impl<'de> FromToml<'de> for $num {
1125 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1126 match deser_integer_ctx(ctx, value, <$num>::MIN as i128, <$num>::MAX as i128, &stringify!($num), &$range) {
1127 Ok(i) => Ok(i as $num),
1128 Err(e) => Err(e),
1129 }
1130 }
1131 }
1132 )+};
1133}
1134
1135integer_new!(
1136 i8 => "-128..=127",
1137 i16 => "-32768..=32767",
1138 i32 => "-2147483648..=2147483647",
1139 u8 => "0..=255",
1140 u16 => "0..=65535",
1141 u32 => "0..=4294967295"
1142);
1143
1144impl<'de> FromToml<'de> for isize {
1145 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1146 #[cfg(target_pointer_width = "32")]
1147 const RANGE: &str = "-2147483648..=2147483647";
1148 #[cfg(target_pointer_width = "64")]
1149 const RANGE: &str = "-9223372036854775808..=9223372036854775807";
1150 match deser_integer_ctx(
1151 ctx,
1152 value,
1153 isize::MIN as i128,
1154 isize::MAX as i128,
1155 &"isize",
1156 &RANGE,
1157 ) {
1158 Ok(i) => Ok(i as isize),
1159 Err(e) => Err(e),
1160 }
1161 }
1162}
1163
1164impl<'de> FromToml<'de> for i64 {
1165 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1166 match deser_integer_ctx(
1167 ctx,
1168 value,
1169 i64::MIN as i128,
1170 i64::MAX as i128,
1171 &"i64",
1172 &"-9223372036854775808..=9223372036854775807",
1173 ) {
1174 Ok(i) => Ok(i as i64),
1175 Err(e) => Err(e),
1176 }
1177 }
1178}
1179
1180impl<'de> FromToml<'de> for u64 {
1181 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1182 match deser_integer_ctx(
1183 ctx,
1184 value,
1185 0,
1186 u64::MAX as i128,
1187 &"u64",
1188 &"0..=18446744073709551615",
1189 ) {
1190 Ok(i) => Ok(i as u64),
1191 Err(e) => Err(e),
1192 }
1193 }
1194}
1195
1196impl<'de> FromToml<'de> for i128 {
1197 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1198 match deser_integer_ctx(
1199 ctx,
1200 value,
1201 i128::MIN,
1202 i128::MAX,
1203 &"i128",
1204 &"-170141183460469231731687303715884105728..=170141183460469231731687303715884105727",
1205 ) {
1206 Ok(i) => Ok(i),
1207 Err(e) => Err(e),
1208 }
1209 }
1210}
1211
1212impl<'de> FromToml<'de> for u128 {
1213 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1214 match deser_integer_ctx(
1215 ctx,
1216 value,
1217 0,
1218 i128::MAX,
1219 &"u128",
1220 &"0..=340282366920938463463374607431768211455",
1221 ) {
1222 Ok(i) => Ok(i as u128),
1223 Err(e) => Err(e),
1224 }
1225 }
1226}
1227
1228impl<'de> FromToml<'de> for usize {
1229 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1230 #[cfg(target_pointer_width = "32")]
1231 const RANGE: &str = "0..=4294967295";
1232 #[cfg(target_pointer_width = "64")]
1233 const RANGE: &str = "0..=18446744073709551615";
1234 match deser_integer_ctx(ctx, value, 0, usize::MAX as i128, &"usize", &RANGE) {
1235 Ok(i) => Ok(i as usize),
1236 Err(e) => Err(e),
1237 }
1238 }
1239}
1240
1241impl<'de> FromToml<'de> for f32 {
1242 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1243 match value.as_f64() {
1244 Some(f) => Ok(f as f32),
1245 None => Err(ctx.report_expected_but_found(&"a float", value)),
1246 }
1247 }
1248}
1249
1250impl<'de> FromToml<'de> for f64 {
1251 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1252 match value.as_f64() {
1253 Some(f) => Ok(f),
1254 None => Err(ctx.report_expected_but_found(&"a float", value)),
1255 }
1256 }
1257}
1258
1259impl<'de, T> FromToml<'de> for Vec<T>
1260where
1261 T: FromToml<'de>,
1262{
1263 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1264 let arr = value.require_array(ctx)?;
1265 let mut result = Vec::with_capacity(arr.len());
1266 let mut had_error = false;
1267 for item in arr {
1268 match T::from_toml(ctx, item) {
1269 Ok(v) => result.push(v),
1270 Err(_) => had_error = true,
1271 }
1272 }
1273 if had_error { Err(Failed) } else { Ok(result) }
1274 }
1275}
1276
1277impl<'de, T> FromToml<'de> for BTreeSet<T>
1278where
1279 T: Ord + FromToml<'de>,
1280{
1281 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1282 let arr = value.require_array(ctx)?;
1283 let mut result = BTreeSet::new();
1284 let mut had_error = false;
1285 for item in arr {
1286 match T::from_toml(ctx, item) {
1287 Ok(v) => {
1288 result.insert(v);
1289 }
1290 Err(_) => had_error = true,
1291 }
1292 }
1293 if had_error { Err(Failed) } else { Ok(result) }
1294 }
1295}
1296
1297impl<'de, K, V> FromToml<'de> for BTreeMap<K, V>
1298where
1299 K: Ord + FromToml<'de>,
1300 V: FromToml<'de>,
1301{
1302 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1303 let table = value.require_table(ctx)?;
1304 let mut map = BTreeMap::new();
1305 let mut had_error = false;
1306 for (key, item) in table {
1307 let k = match key_from_toml(ctx, key) {
1308 Ok(k) => k,
1309 Err(_) => {
1310 had_error = true;
1311 continue;
1312 }
1313 };
1314 match V::from_toml(ctx, item) {
1315 Ok(v) => {
1316 map.insert(k, v);
1317 }
1318 Err(_) => had_error = true,
1319 }
1320 }
1321 if had_error { Err(Failed) } else { Ok(map) }
1322 }
1323}
1324
1325impl<'de> Item<'de> {
1326 #[doc(alias = "expect_custom_string")]
1332 pub fn require_custom_string(
1333 &self,
1334 ctx: &mut Context<'de>,
1335 expected: &'static &'static str,
1336 ) -> Result<&'de str, Failed> {
1337 match self.value() {
1338 item::Value::String(s) => Ok(*s),
1339 _ => Err(ctx.report_expected_but_found(expected, self)),
1340 }
1341 }
1342 #[doc(alias = "expect_string")]
1344 pub fn require_string(&self, ctx: &mut Context<'de>) -> Result<&'de str, Failed> {
1345 match self.value() {
1346 item::Value::String(s) => Ok(*s),
1347 _ => Err(ctx.report_expected_but_found(&"a string", self)),
1348 }
1349 }
1350
1351 #[doc(alias = "expect_array")]
1353 pub fn require_array(&self, ctx: &mut Context<'de>) -> Result<&crate::Array<'de>, Failed> {
1354 match self.as_array() {
1355 Some(arr) => Ok(arr),
1356 None => Err(ctx.report_expected_but_found(&"an array", self)),
1357 }
1358 }
1359
1360 #[doc(alias = "expect_table")]
1362 pub fn require_table(&self, ctx: &mut Context<'de>) -> Result<&crate::Table<'de>, Failed> {
1363 match self.as_table() {
1364 Some(table) => Ok(table),
1365 None => Err(ctx.report_expected_but_found(&"a table", self)),
1366 }
1367 }
1368
1369 pub fn table_helper<'ctx, 'item>(
1374 &'item self,
1375 ctx: &'ctx mut Context<'de>,
1376 ) -> Result<TableHelper<'ctx, 'item, 'de>, Failed> {
1377 let Some(table) = self.as_table() else {
1378 return Err(ctx.report_expected_but_found(&"a table", self));
1379 };
1380 Ok(TableHelper::new(ctx, table))
1381 }
1382}
1383
1384#[derive(Debug)]
1400pub struct FromTomlError {
1401 pub errors: Vec<Error>,
1403}
1404
1405impl Display for FromTomlError {
1406 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1407 let Some(first) = self.errors.first() else {
1408 return f.write_str("deserialization failed");
1409 };
1410 Display::fmt(first, f)?;
1411 let remaining = self.errors.len() - 1;
1412 if remaining > 0 {
1413 write!(
1414 f,
1415 " (+{remaining} more error{})",
1416 if remaining == 1 { "" } else { "s" }
1417 )?;
1418 }
1419 Ok(())
1420 }
1421}
1422
1423impl std::error::Error for FromTomlError {}
1424
1425impl From<Error> for FromTomlError {
1426 fn from(error: Error) -> Self {
1427 Self {
1428 errors: vec![error],
1429 }
1430 }
1431}
1432
1433impl From<Vec<Error>> for FromTomlError {
1434 fn from(errors: Vec<Error>) -> Self {
1435 Self { errors }
1436 }
1437}
1438
1439impl IntoIterator for FromTomlError {
1440 type Item = Error;
1441 type IntoIter = std::vec::IntoIter<Error>;
1442 fn into_iter(self) -> Self::IntoIter {
1443 self.errors.into_iter()
1444 }
1445}
1446
1447impl<'a> IntoIterator for &'a FromTomlError {
1448 type Item = &'a Error;
1449 type IntoIter = std::slice::Iter<'a, Error>;
1450 fn into_iter(self) -> Self::IntoIter {
1451 self.errors.iter()
1452 }
1453}