oh_my_toml 0.1.0

Awesome TOML configuration derive macro
Documentation
//! Impl for [`nonempty::NonEmpty`]

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};

/// Failed to deserialize a [`NonEmpty`](nonempty::NonEmpty) vector
#[derive(Diagnostic, Error, Debug, Clone, Eq, PartialEq, Hash)]
#[error("Type mismatch")]
pub enum DeserializeNonEmptyVecError<E: Error> {
    /// Everything about the list if good except the fact that it is empty
    Empty {
        /// Details on why deserialization failed
        details: String,
        /// Location of the error in the source file
        #[label("{details}")]
        span: SourceSpan,
        /// A list of errors for each inner element that failed to deserialize
        #[related]
        errors: Vec<E>,
    },
    /// Type of elements does not correspond to the type we expected
    ElementTypeMismatch {
        /// Details on why deserialization failed
        details: String,
        /// Location of the error in the source file
        #[label("{details}")]
        span: SourceSpan,
        /// A list of errors for each inner element that failed to deserialize
        #[related]
        errors: NonEmpty<E>,
    },
    /// The list's type is incorrect - it is not a list
    NotArray {
        /// Details on why deserialization failed
        details: String,
        /// Span of the item which is not an array
        #[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)
        }
    }
}