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, T: FromToml<'de>, const N: usize> FromToml<'de> for [T; N] {
914 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
915 let boxed_slice = Box::<[T]>::from_toml(ctx, value)?;
916 match <Box<[T; N]>>::try_from(boxed_slice) {
917 Ok(array) => Ok(*array),
918 Err(res) => Err(ctx.push_error(Error::custom(
919 format!(
920 "expected an array with a size of {}, found one with a size of {}",
921 N,
922 res.len()
923 ),
924 value.span_unchecked(),
925 ))),
926 }
927 }
928}
929
930macro_rules! impl_from_toml_tuple {
931 ($len:expr, $($idx:tt => $T:ident, $var:ident),+) => {
932 impl<'de, $($T: FromToml<'de>),+> FromToml<'de> for ($($T,)+) {
933 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
934 let arr = value.require_array(ctx)?;
935 if arr.len() != $len {
936 return Err(ctx.push_error(Error::custom(
937 format!(
938 "expected an array with a size of {}, found one with a size of {}",
939 $len,
940 arr.len()
941 ),
942 value.span_unchecked(),
943 )));
944 }
945 let slice = arr.as_slice();
946 let mut had_error = false;
947 $(
948 let $var = match $T::from_toml(ctx, &slice[$idx]) {
949 Ok(v) => Some(v),
950 Err(_) => { had_error = true; None }
951 };
952 )+
953 if had_error {
954 return Err(Failed);
955 }
956 Ok(($($var.unwrap(),)+))
957 }
958 }
959 };
960}
961
962impl_from_toml_tuple!(1, 0 => A, a);
963impl_from_toml_tuple!(2, 0 => A, a, 1 => B, b);
964impl_from_toml_tuple!(3, 0 => A, a, 1 => B, b, 2 => C, c);
965
966impl<'de> FromToml<'de> for String {
967 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
968 match value.as_str() {
969 Some(s) => Ok(s.to_string()),
970 None => Err(ctx.report_expected_but_found(&"a string", value)),
971 }
972 }
973}
974
975impl<'de> FromToml<'de> for PathBuf {
976 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
977 match value.as_str() {
978 Some(s) => Ok(PathBuf::from(s)),
979 None => Err(ctx.report_expected_but_found(&"a path", value)),
980 }
981 }
982}
983
984impl<'de, T: FromToml<'de>> FromToml<'de> for Option<T> {
985 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
986 T::from_toml(ctx, value).map(Some)
987 }
988}
989
990impl<'de, T: FromToml<'de>> FromToml<'de> for Box<T> {
991 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
992 match T::from_toml(ctx, value) {
993 Ok(v) => Ok(Box::new(v)),
994 Err(e) => Err(e),
995 }
996 }
997}
998impl<'de, T: FromToml<'de>> FromToml<'de> for Box<[T]> {
999 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1000 match Vec::<T>::from_toml(ctx, value) {
1001 Ok(vec) => Ok(vec.into_boxed_slice()),
1002 Err(e) => Err(e),
1003 }
1004 }
1005}
1006impl<'de> FromToml<'de> for Box<str> {
1007 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1008 match value.value() {
1009 item::Value::String(&s) => Ok(s.into()),
1010 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1011 }
1012 }
1013}
1014impl<'de> FromToml<'de> for &'de str {
1015 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1016 match value.value() {
1017 item::Value::String(s) => Ok(*s),
1018 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1019 }
1020 }
1021}
1022
1023impl<'de> FromToml<'de> for std::borrow::Cow<'de, str> {
1024 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1025 match value.value() {
1026 item::Value::String(s) => Ok(std::borrow::Cow::Borrowed(*s)),
1027 _ => Err(ctx.report_expected_but_found(&"a string", value)),
1028 }
1029 }
1030}
1031
1032impl<'de> FromToml<'de> for bool {
1033 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1034 match value.as_bool() {
1035 Some(b) => Ok(b),
1036 None => Err(ctx.report_expected_but_found(&"a bool", value)),
1037 }
1038 }
1039}
1040
1041fn deser_integer_ctx<'de>(
1042 ctx: &mut Context<'de>,
1043 value: &Item<'de>,
1044 min: i128,
1045 max: i128,
1046 ty: &'static &'static str,
1047 range: &'static &'static str,
1048) -> Result<i128, Failed> {
1049 match value.as_i128() {
1050 Some(i) if i >= min && i <= max => Ok(i),
1051 Some(_) => Err(ctx.report_out_of_range(ty, range, value)),
1052 None => Err(ctx.report_expected_but_found(&"an integer", value)),
1053 }
1054}
1055
1056macro_rules! integer_new {
1057 ($($num:ty => $range:literal),+) => {$(
1058 impl<'de> FromToml<'de> for $num {
1059 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1060 match deser_integer_ctx(ctx, value, <$num>::MIN as i128, <$num>::MAX as i128, &stringify!($num), &$range) {
1061 Ok(i) => Ok(i as $num),
1062 Err(e) => Err(e),
1063 }
1064 }
1065 }
1066 )+};
1067}
1068
1069integer_new!(
1070 i8 => "-128..=127",
1071 i16 => "-32768..=32767",
1072 i32 => "-2147483648..=2147483647",
1073 u8 => "0..=255",
1074 u16 => "0..=65535",
1075 u32 => "0..=4294967295"
1076);
1077
1078impl<'de> FromToml<'de> for isize {
1079 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1080 #[cfg(target_pointer_width = "32")]
1081 const RANGE: &str = "-2147483648..=2147483647";
1082 #[cfg(target_pointer_width = "64")]
1083 const RANGE: &str = "-9223372036854775808..=9223372036854775807";
1084 match deser_integer_ctx(
1085 ctx,
1086 value,
1087 isize::MIN as i128,
1088 isize::MAX as i128,
1089 &"isize",
1090 &RANGE,
1091 ) {
1092 Ok(i) => Ok(i as isize),
1093 Err(e) => Err(e),
1094 }
1095 }
1096}
1097
1098impl<'de> FromToml<'de> for i64 {
1099 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1100 match deser_integer_ctx(
1101 ctx,
1102 value,
1103 i64::MIN as i128,
1104 i64::MAX as i128,
1105 &"i64",
1106 &"-9223372036854775808..=9223372036854775807",
1107 ) {
1108 Ok(i) => Ok(i as i64),
1109 Err(e) => Err(e),
1110 }
1111 }
1112}
1113
1114impl<'de> FromToml<'de> for u64 {
1115 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1116 match deser_integer_ctx(
1117 ctx,
1118 value,
1119 0,
1120 u64::MAX as i128,
1121 &"u64",
1122 &"0..=18446744073709551615",
1123 ) {
1124 Ok(i) => Ok(i as u64),
1125 Err(e) => Err(e),
1126 }
1127 }
1128}
1129
1130impl<'de> FromToml<'de> for i128 {
1131 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1132 match deser_integer_ctx(
1133 ctx,
1134 value,
1135 i128::MIN,
1136 i128::MAX,
1137 &"i128",
1138 &"-170141183460469231731687303715884105728..=170141183460469231731687303715884105727",
1139 ) {
1140 Ok(i) => Ok(i),
1141 Err(e) => Err(e),
1142 }
1143 }
1144}
1145
1146impl<'de> FromToml<'de> for u128 {
1147 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1148 match deser_integer_ctx(
1149 ctx,
1150 value,
1151 0,
1152 i128::MAX,
1153 &"u128",
1154 &"0..=340282366920938463463374607431768211455",
1155 ) {
1156 Ok(i) => Ok(i as u128),
1157 Err(e) => Err(e),
1158 }
1159 }
1160}
1161
1162impl<'de> FromToml<'de> for usize {
1163 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1164 #[cfg(target_pointer_width = "32")]
1165 const RANGE: &str = "0..=4294967295";
1166 #[cfg(target_pointer_width = "64")]
1167 const RANGE: &str = "0..=18446744073709551615";
1168 match deser_integer_ctx(ctx, value, 0, usize::MAX as i128, &"usize", &RANGE) {
1169 Ok(i) => Ok(i as usize),
1170 Err(e) => Err(e),
1171 }
1172 }
1173}
1174
1175impl<'de> FromToml<'de> for f32 {
1176 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1177 match value.as_f64() {
1178 Some(f) => Ok(f as f32),
1179 None => Err(ctx.report_expected_but_found(&"a float", value)),
1180 }
1181 }
1182}
1183
1184impl<'de> FromToml<'de> for f64 {
1185 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1186 match value.as_f64() {
1187 Some(f) => Ok(f),
1188 None => Err(ctx.report_expected_but_found(&"a float", value)),
1189 }
1190 }
1191}
1192
1193impl<'de, T> FromToml<'de> for Vec<T>
1194where
1195 T: FromToml<'de>,
1196{
1197 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1198 let arr = value.require_array(ctx)?;
1199 let mut result = Vec::with_capacity(arr.len());
1200 let mut had_error = false;
1201 for item in arr {
1202 match T::from_toml(ctx, item) {
1203 Ok(v) => result.push(v),
1204 Err(_) => had_error = true,
1205 }
1206 }
1207 if had_error { Err(Failed) } else { Ok(result) }
1208 }
1209}
1210
1211impl<'de, T> FromToml<'de> for BTreeSet<T>
1212where
1213 T: Ord + FromToml<'de>,
1214{
1215 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1216 let arr = value.require_array(ctx)?;
1217 let mut result = BTreeSet::new();
1218 let mut had_error = false;
1219 for item in arr {
1220 match T::from_toml(ctx, item) {
1221 Ok(v) => {
1222 result.insert(v);
1223 }
1224 Err(_) => had_error = true,
1225 }
1226 }
1227 if had_error { Err(Failed) } else { Ok(result) }
1228 }
1229}
1230
1231impl<'de, K, V> FromToml<'de> for BTreeMap<K, V>
1232where
1233 K: Ord + FromToml<'de>,
1234 V: FromToml<'de>,
1235{
1236 fn from_toml(ctx: &mut Context<'de>, value: &Item<'de>) -> Result<Self, Failed> {
1237 let table = value.require_table(ctx)?;
1238 let mut map = BTreeMap::new();
1239 let mut had_error = false;
1240 for (key, item) in table {
1241 let k = match key_from_toml(ctx, key) {
1242 Ok(k) => k,
1243 Err(_) => {
1244 had_error = true;
1245 continue;
1246 }
1247 };
1248 match V::from_toml(ctx, item) {
1249 Ok(v) => {
1250 map.insert(k, v);
1251 }
1252 Err(_) => had_error = true,
1253 }
1254 }
1255 if had_error { Err(Failed) } else { Ok(map) }
1256 }
1257}
1258
1259impl<'de> Item<'de> {
1260 #[doc(alias = "expect_custom_string")]
1266 pub fn require_custom_string(
1267 &self,
1268 ctx: &mut Context<'de>,
1269 expected: &'static &'static str,
1270 ) -> Result<&'de str, Failed> {
1271 match self.value() {
1272 item::Value::String(s) => Ok(*s),
1273 _ => Err(ctx.report_expected_but_found(expected, self)),
1274 }
1275 }
1276 #[doc(alias = "expect_string")]
1278 pub fn require_string(&self, ctx: &mut Context<'de>) -> Result<&'de str, Failed> {
1279 match self.value() {
1280 item::Value::String(s) => Ok(*s),
1281 _ => Err(ctx.report_expected_but_found(&"a string", self)),
1282 }
1283 }
1284
1285 #[doc(alias = "expect_array")]
1287 pub fn require_array(&self, ctx: &mut Context<'de>) -> Result<&crate::Array<'de>, Failed> {
1288 match self.as_array() {
1289 Some(arr) => Ok(arr),
1290 None => Err(ctx.report_expected_but_found(&"an array", self)),
1291 }
1292 }
1293
1294 #[doc(alias = "expect_table")]
1296 pub fn require_table(&self, ctx: &mut Context<'de>) -> Result<&crate::Table<'de>, Failed> {
1297 match self.as_table() {
1298 Some(table) => Ok(table),
1299 None => Err(ctx.report_expected_but_found(&"a table", self)),
1300 }
1301 }
1302
1303 pub fn table_helper<'ctx, 'item>(
1308 &'item self,
1309 ctx: &'ctx mut Context<'de>,
1310 ) -> Result<TableHelper<'ctx, 'item, 'de>, Failed> {
1311 let Some(table) = self.as_table() else {
1312 return Err(ctx.report_expected_but_found(&"a table", self));
1313 };
1314 Ok(TableHelper::new(ctx, table))
1315 }
1316}
1317
1318#[derive(Debug)]
1334pub struct FromTomlError {
1335 pub errors: Vec<Error>,
1337}
1338
1339impl Display for FromTomlError {
1340 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1341 let Some(first) = self.errors.first() else {
1342 return f.write_str("deserialization failed");
1343 };
1344 Display::fmt(first, f)?;
1345 let remaining = self.errors.len() - 1;
1346 if remaining > 0 {
1347 write!(
1348 f,
1349 " (+{remaining} more error{})",
1350 if remaining == 1 { "" } else { "s" }
1351 )?;
1352 }
1353 Ok(())
1354 }
1355}
1356
1357impl std::error::Error for FromTomlError {}
1358
1359impl From<Error> for FromTomlError {
1360 fn from(error: Error) -> Self {
1361 Self {
1362 errors: vec![error],
1363 }
1364 }
1365}
1366
1367impl From<Vec<Error>> for FromTomlError {
1368 fn from(errors: Vec<Error>) -> Self {
1369 Self { errors }
1370 }
1371}
1372
1373impl IntoIterator for FromTomlError {
1374 type Item = Error;
1375 type IntoIter = std::vec::IntoIter<Error>;
1376 fn into_iter(self) -> Self::IntoIter {
1377 self.errors.into_iter()
1378 }
1379}
1380
1381impl<'a> IntoIterator for &'a FromTomlError {
1382 type Item = &'a Error;
1383 type IntoIter = std::slice::Iter<'a, Error>;
1384 fn into_iter(self) -> Self::IntoIter {
1385 self.errors.iter()
1386 }
1387}