adnv 1.5.0

CLI that tracks, checks and auto-updates infrastructure dependency versions across Terraform, Helm, Docker, Git and npm
Documentation
use std::marker::PhantomData;
use std::str::FromStr;

use serde::Deserialize;
use serde_with::DeserializeAs;

/// Helper for deserializing a struct from a map
/// or a string using [`FromStr`]
pub struct MapOrString;

impl<'de, T> DeserializeAs<'de, T> for MapOrString
where
    T: Deserialize<'de> + FromStr,
    T::Err: std::fmt::Display,
{
    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        use serde::de::Error;
        use serde::de::Visitor;

        struct MapOrStringVisitor<T>(PhantomData<T>);

        impl<'de, T> Visitor<'de> for MapOrStringVisitor<T>
        where
            T: Deserialize<'de> + FromStr,
            T::Err: std::fmt::Display,
        {
            type Value = T;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(formatter, "map or string")
            }

            fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
            where
                A: serde::de::MapAccess<'de>,
            {
                use serde::de::value::MapAccessDeserializer;

                T::deserialize(MapAccessDeserializer::new(map))
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: Error,
            {
                v.parse().map_err(Error::custom)
            }
        }

        deserializer.deserialize_any(MapOrStringVisitor(PhantomData))
    }
}

#[allow(dead_code)]
pub struct Flatten<D>(PhantomData<D>);

impl<'de, T, D> DeserializeAs<'de, Vec<T>> for Flatten<D>
where
    T: Deserialize<'de>,
    D: DeserializeAs<'de, Vec<T>>,
{
    fn deserialize_as<De>(deserializer: De) -> Result<Vec<T>, De::Error>
    where
        De: serde::Deserializer<'de>,
    {
        Ok(<Vec<D>>::deserialize_as(deserializer)?
            .into_iter()
            .flatten()
            .collect())
    }
}

pub struct SingletonMap;

impl<'de, T> DeserializeAs<'de, T> for SingletonMap
where
    T: Deserialize<'de>,
{
    #[inline]
    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        serde_yaml_ng::with::singleton_map::deserialize(deserializer)
    }
}