use crate::{Key, Value};
use nonempty::NonEmpty;
use toml::de::DeValue;
use std::borrow::Cow;
use miette::{Diagnostic, SourceSpan};
use thiserror::Error;
use crate::DeserializeErrors;
use crate::util::value_type_description;
use crate::{DeserializeValue, Error};
#[derive(Diagnostic, Error, Debug, Clone, Eq, PartialEq, Hash)]
#[error("Type mismatch")]
pub enum DeserializeNonEmptyVecError<E: Error> {
Empty {
details: String,
#[label("{details}")]
span: SourceSpan,
#[related]
errors: Vec<E>,
},
ElementTypeMismatch {
details: String,
#[label("{details}")]
span: SourceSpan,
#[related]
errors: NonEmpty<E>,
},
NotArray {
details: String,
#[label("{details}")]
span: SourceSpan,
},
}
impl<E: Error> Error for DeserializeNonEmptyVecError<E> {
fn expected_type() -> Cow<'static, str> {
format!("non-empty list of {}", E::expected_type()).into()
}
}
impl<'de, T: DeserializeValue<'de>> DeserializeValue<'de> for NonEmpty<T> {
type Error = DeserializeNonEmptyVecError<T::Error>;
fn deserialize_value<'k>(
_key: Key<'k>,
value: Value<'de>,
) -> Result<Self, DeserializeErrors<Self, NonEmpty<Self::Error>>> {
let details = value_type_description(&value);
let span = value.span();
let DeValue::Array(xs) = value.into_inner() else {
return Err(DeserializeErrors::err(
DeserializeNonEmptyVecError::NotArray {
details: DeserializeNonEmptyVecError::<T::Error>::details(details),
span: span.into(),
},
));
};
let mut errs = vec![];
let mut values = vec![];
for (i, x) in xs.into_iter().enumerate() {
match T::deserialize_value(Key::Index(i), x) {
Ok(t) => {
values.push(t);
}
Err(DeserializeErrors { recovered, errors }) => {
errs.extend(errors);
values.extend(recovered);
}
}
}
let Some(values) = NonEmpty::from_vec(values) else {
return Err(DeserializeErrors::err(DeserializeNonEmptyVecError::Empty {
details: DeserializeNonEmptyVecError::<T::Error>::details(details),
span: span.into(),
errors: errs,
}));
};
if let Some(errors) = NonEmpty::from_vec(errs) {
Err(DeserializeErrors::recovered(
values,
DeserializeNonEmptyVecError::ElementTypeMismatch {
details: DeserializeNonEmptyVecError::<T::Error>::details(details),
span: span.into(),
errors,
},
))
} else {
Ok(values)
}
}
}