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<Vec<Key>>,
},
DottedKeyExtendWrongType {
key: Vec<Key>,
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::<Vec<_>>().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::<Vec<_>>().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"),
}
}
}