figa 0.3.0

A layered configuration library for Rust
Documentation
use core::fmt;

#[cfg(any(feature = "std", feature = "hashbrown"))]
use core::hash::{BuildHasher, Hash};

#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};

use serde::{
    de::{DeserializeOwned, DeserializeSeed, Visitor},
    Deserializer,
};

pub struct Append<'a, F>(pub &'a mut F);

impl<'de, T> DeserializeSeed<'de> for Append<'_, Option<T>>
where
    T: DeserializeOwned,
{
    type Value = ();

    #[inline]
    fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_option(self)
    }
}

impl<'de, T> Visitor<'de> for Append<'_, Option<T>>
where
    T: DeserializeOwned,
{
    type Value = ();

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("option")
    }

    #[inline]
    fn visit_none<E>(self) -> Result<(), E>
    where
        E: serde::de::Error,
    {
        Ok(())
    }

    #[inline]
    fn visit_some<D>(self, deserializer: D) -> Result<(), D::Error>
    where
        D: Deserializer<'de>,
    {
        *self.0 = Some(T::deserialize(deserializer)?);
        Ok(())
    }
}

#[cfg(feature = "alloc")]
impl<'de> DeserializeSeed<'de> for Append<'_, String> {
    type Value = ();

    #[inline]
    fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_str(self)
    }
}

#[cfg(feature = "alloc")]
impl<'de> Visitor<'de> for Append<'_, String> {
    type Value = ();

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("string")
    }

    #[inline]
    fn visit_str<E>(self, value: &str) -> Result<(), E>
    where
        E: serde::de::Error,
    {
        self.0.push_str(value);
        Ok(())
    }
}

#[cfg(feature = "alloc")]
impl<'de, F> DeserializeSeed<'de> for Append<'_, Vec<F>>
where
    F: DeserializeOwned,
{
    type Value = ();

    #[inline]
    fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_seq(self)
    }
}

#[cfg(feature = "alloc")]
impl<'de, F> Visitor<'de> for Append<'_, Vec<F>>
where
    F: DeserializeOwned,
{
    type Value = ();

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("sequence")
    }

    #[inline]
    fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
    where
        A: serde::de::SeqAccess<'de>,
    {
        while let Some(value) = seq.next_element()? {
            self.0.push(value);
        }
        Ok(())
    }
}

#[cfg(any(feature = "alloc", feature = "hashbrown"))]
macro_rules! append_map {
    ($($map:ident)::+ <K, V $(, $tail:ident)*> $(where $($param:ident : $bound:path),* $(,)?)?) => {
        impl<'de, K, V $(, $tail)*> DeserializeSeed<'de> for Append<'_, $($map)::+ <K, V $(, $tail)*>>
        where
            K: DeserializeOwned,
            V: DeserializeOwned,
            $($($param: $bound,)*)?
        {
            type Value = ();

            #[inline]
            fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
            where
                D: Deserializer<'de>,
            {
                deserializer.deserialize_map(self)
            }
        }

        impl<'de, K, V $(, $tail)*> Visitor<'de> for Append<'_, $($map)::+ <K, V $(, $tail)*>>
        where
            K: DeserializeOwned,
            V: DeserializeOwned,
            $($($param: $bound,)*)?
        {
            type Value = ();

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("map")
            }

            #[inline]
            fn visit_map<X>(self, mut map: X) -> Result<(), X::Error>
            where
                X: serde::de::MapAccess<'de>,
            {
                while let Some((key, value)) = map.next_entry()? {
                    self.0.insert(key, value);
                }
                Ok(())
            }
        }
    };
}

#[cfg(any(feature = "alloc", feature = "hashbrown"))]
macro_rules! append_set {
    ($($set:ident)::+ <T $(, $tail:ident)*> $(where $($param:ident : $bound:path),* $(,)?)?) => {
        impl<'de, T $(, $tail)*> DeserializeSeed<'de> for Append<'_, $($set)::+ <T $(, $tail)*>>
        where
            T: DeserializeOwned,
            $($($param: $bound,)*)?
        {
            type Value = ();

            #[inline]
            fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
            where
                D: Deserializer<'de>,
            {
                deserializer.deserialize_seq(self)
            }
        }

        impl<'de, T $(, $tail)*> Visitor<'de> for Append<'_, $($set)::+ <T $(, $tail)*>>
        where
            T: DeserializeOwned,
            $($($param: $bound,)*)?
        {
            type Value = ();

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("set")
            }

            #[inline]
            fn visit_seq<X>(self, mut seq: X) -> Result<(), X::Error>
            where
                X: serde::de::SeqAccess<'de>,
            {
                while let Some(value) = seq.next_element()? {
                    self.0.insert(value);
                }
                Ok(())
            }
        }
    };
}

#[cfg(feature = "alloc")]
append_map!(alloc::collections::BTreeMap<K, V> where K: Ord);

#[cfg(feature = "alloc")]
append_set!(alloc::collections::BTreeSet<T> where T: Ord);

#[cfg(feature = "std")]
append_map!(std::collections::HashMap<K, V, S> where K: Eq, K: Hash, S: BuildHasher);

#[cfg(feature = "std")]
append_set!(std::collections::HashSet<T, S> where T: Eq, T: Hash, S: BuildHasher);

#[cfg(feature = "hashbrown")]
append_map!(hashbrown::HashMap<K, V, S> where K: Eq, K: Hash, S: BuildHasher);

#[cfg(feature = "hashbrown")]
append_set!(hashbrown::HashSet<T, S> where T: Eq, T: Hash, S: BuildHasher);