oh_my_toml 0.1.0

Awesome TOML configuration derive macro
Documentation
//! Impls for floats

use crate::{Key, Value};
use nonempty::NonEmpty;
use std::borrow::Cow;
use std::num::ParseFloatError;
use std::str::FromStr;

use miette::{Diagnostic, SourceSpan};
use thiserror::Error;

use crate::DeserializeErrors;
use crate::util::value_type_description;
use crate::{DeserializeValue, Error};

/// Failed to deserialize [`f32`] or [`f64`]
#[derive(Diagnostic, Error, Debug, Clone)]
#[diagnostic(help("example decimals: `2.452`, `-155.7` or `100.0`"))]
pub enum DeserializeFloatError {
    /// Invalid float format
    #[error("Invalid float")]
    ParseFloat {
        /// Why the float parsing failed
        error: ParseFloatError,
        /// Location of the error in the source file
        #[label("{error}")]
        span: SourceSpan,
    },
    /// Received TOML value is not a float
    #[error("Type mismatch")]
    TypeMismatch {
        /// Details on why deserialization failed
        details: String,
        /// Location of the error in the source file
        #[label("{details}")]
        span: SourceSpan,
    },
}

impl Error for DeserializeFloatError {
    fn expected_type() -> Cow<'static, str> {
        "decimal".into()
    }
}

/// Deserialize floats
trait Float: FromStr<Err = ParseFloatError> {
    /// Deserialize value
    fn deserialize_value(
        _key: Key,
        value: Value,
    ) -> Result<Self, DeserializeErrors<Self, NonEmpty<DeserializeFloatError>>> {
        value
            .as_ref()
            .as_float()
            .ok_or_else(|| {
                DeserializeErrors::err(DeserializeFloatError::TypeMismatch {
                    details: DeserializeFloatError::details(value_type_description(&value)),
                    span: value.span().into(),
                })
            })?
            .as_str()
            .parse()
            .map_err(|error| {
                DeserializeErrors::err(DeserializeFloatError::ParseFloat {
                    error,
                    span: value.span().into(),
                })
            })
    }
}

impl Float for f32 {}
impl Float for f64 {}

impl DeserializeValue<'_> for f32 {
    type Error = DeserializeFloatError;

    fn deserialize_value(
        key: Key,
        value: Value,
    ) -> Result<Self, DeserializeErrors<Self, NonEmpty<Self::Error>>> {
        <Self as Float>::deserialize_value(key, value)
    }
}

impl DeserializeValue<'_> for f64 {
    type Error = DeserializeFloatError;

    fn deserialize_value(
        key: Key,
        value: Value,
    ) -> Result<Self, DeserializeErrors<Self, NonEmpty<Self::Error>>> {
        <Self as Float>::deserialize_value(key, value)
    }
}