use std::error::Error as StdError; use std::fmt::{Display, Formatter, Result}; use crate::Key; #[derive(Debug, Clone)] pub(crate) enum CustomError { DuplicateKey { key: String, table: Option>, }, DottedKeyExtendWrongType { key: Vec, actual: &'static str, }, OutOfRange, #[cfg_attr(feature = "unbounded", allow(dead_code))] RecursionLimitExceeded, } impl CustomError { pub(crate) fn duplicate_key(path: &[Key], i: usize) -> Self { assert!(i < path.len()); let key = &path[i]; let repr = key .as_repr() .and_then(|key| key.as_raw().as_str()) .map(|s| s.to_owned()) .unwrap_or_else(|| { #[cfg(feature = "display")] { key.default_repr().as_raw().as_str().unwrap().to_owned() } #[cfg(not(feature = "display"))] { format!("{:?}", key.get()) } }); Self::DuplicateKey { key: repr, table: Some(path[..i].to_vec()), } } pub(crate) fn extend_wrong_type(path: &[Key], i: usize, actual: &'static str) -> Self { assert!(i < path.len()); Self::DottedKeyExtendWrongType { key: path[..=i].to_vec(), actual, } } } impl StdError for CustomError { fn description(&self) -> &'static str { "TOML parse error" } } impl Display for CustomError { fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self { CustomError::DuplicateKey { key, table } => { if let Some(table) = table { if table.is_empty() { write!(f, "duplicate key `{}` in document root", key) } else { let path = table.iter().map(|k| k.get()).collect::>().join("."); write!(f, "duplicate key `{}` in table `{}`", key, path) } } else { write!(f, "duplicate key `{}`", key) } } CustomError::DottedKeyExtendWrongType { key, actual } => { let path = key.iter().map(|k| k.get()).collect::>().join("."); write!( f, "dotted key `{}` attempted to extend non-table type ({})", path, actual ) } CustomError::OutOfRange => write!(f, "value is out of range"), CustomError::RecursionLimitExceeded => write!(f, "recursion limit exceeded"), } } }