uri-template-core 0.1.0

RFC6570 URI Template library for Rust, with parsing, expansion, compile-time checked macros, and no_std support.
Documentation
use alloc::borrow::Cow;
use core::hash::Hash;

mod scalar;
mod values;
pub use scalar::Scalar;
pub use values::BTreeValues;
#[cfg(feature = "std")]
pub use values::HashValues;

pub trait Values<'v, 's> {
    fn var(&self, name: &str) -> Option<Cow<'_, Value<'v, 's>>>;
}

pub trait ToValue<'v, 's> {
    fn to_value(&self) -> Value<'v, 's>;
}
impl<'v, 's: 'v, T> ToValue<'v, 's> for T
where
    T: Into<Value<'v, 's>> + Clone,
{
    #[inline]
    fn to_value(&self) -> Value<'v, 's> {
        self.clone().into()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Value<'v, 's: 'v> {
    Scalar(Scalar<'v>),
    List(Cow<'v, [Scalar<'s>]>),
    /// An ordered associative array of key-value pairs
    Keys(Cow<'v, [(Scalar<'s>, Scalar<'s>)]>),
}

impl Value<'_, '_> {
    pub fn into_static(self) -> Value<'static, 'static> {
        match self {
            Self::Scalar(s) => Value::Scalar(s.into_static()),
            Self::List(list) => Value::List(Cow::Owned(
                list.into_owned()
                    .into_iter()
                    .map(|s| s.into_static())
                    .collect(),
            )),
            Self::Keys(items) => Value::Keys(Cow::Owned(
                items
                    .into_owned()
                    .into_iter()
                    .map(|(k, v)| (k.into_static(), v.into_static()))
                    .collect(),
            )),
        }
    }

    pub(crate) fn should_expand(&self) -> bool {
        match self {
            Self::Scalar(_) => true,
            Self::List(s) => !s.is_empty(),
            Self::Keys(items) => !items.is_empty(),
        }
    }
}

#[cfg(feature = "serde")]
pub use serde_impl::deserialize_owned_value;

#[cfg(feature = "serde")]
mod serde_impl {
    use alloc::borrow::Cow;
    use core::marker::PhantomData;

    use super::{Scalar, Value};
    use serde::{Deserialize, de::Visitor};

    pub fn deserialize_owned_value<'de, D>(
        deserializer: D,
    ) -> Result<Value<'static, 'static>, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer
            .deserialize_any(ValueVisitor(PhantomData))
            .map(move |v| v.into_static())
    }

    pub struct ScalarValueVisitor<'a>(PhantomData<&'a ()>);
    impl<'de: 'a, 'a> Deserialize<'de> for Scalar<'a> {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            deserializer.deserialize_any(ScalarValueVisitor(PhantomData))
        }
    }
    impl<'de: 'a, 'a> Visitor<'de> for ScalarValueVisitor<'a> {
        type Value = Scalar<'a>;

        fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
            formatter
                .write_str("a string/number/boolean, list of value, or list of key-value pairs")
        }

        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(v.to_owned().into()))
        }

        fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(Cow::Borrowed(v)))
        }

        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(v.into()))
        }

        fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(Cow::Owned(v.to_string())))
        }

        fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(v.to_string().into()))
        }

        fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(v.to_string().into()))
        }

        fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(v.to_string().into()))
        }

        fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(v.to_string().into()))
        }

        fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(Scalar(v.to_string().into()))
        }
    }

    pub struct ValueVisitor<'v, 's: 'v>(PhantomData<(&'v (), &'s ())>);
    impl<'de: 'v + 's, 'v, 's: 'v> Deserialize<'de> for Value<'v, 's> {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            deserializer.deserialize_any(ValueVisitor(PhantomData))
        }
    }

    impl<'de: 'v + 's, 'v, 's: 'v> Visitor<'de> for ValueVisitor<'v, 's> {
        type Value = Value<'v, 'v>;
        fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
            formatter
                .write_str("a string/number/boolean, list of value, or list of key-value pairs")
        }

        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
        where
            A: serde::de::SeqAccess<'de>,
        {
            let mut values = Vec::new();

            while let Some(value) = seq.next_element::<Scalar<'v>>()? {
                values.push(value);
            }
            Ok(Value::List(Cow::Owned(values)))
        }

        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
        where
            A: serde::de::MapAccess<'de>,
        {
            let mut items = Vec::new();
            while let Some((key, value)) = map.next_entry::<Scalar<'v>, Scalar<'v>>()? {
                items.push((key, value));
            }
            Ok(Value::Keys(Cow::Owned(items)))
        }

        // delegate to ScalarValueVisitor
        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_str(v)
                .map(Value::Scalar)
        }
        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_string(v)
                .map(Value::Scalar)
        }
        fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_borrowed_str(v)
                .map(Value::Scalar)
        }
        fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_bool(v)
                .map(Value::Scalar)
        }
        fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_i64(v)
                .map(Value::Scalar)
        }
        fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_i128(v)
                .map(Value::Scalar)
        }
        fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_u64(v)
                .map(Value::Scalar)
        }
        fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_u128(v)
                .map(Value::Scalar)
        }
        fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ScalarValueVisitor(PhantomData)
                .visit_f64(v)
                .map(Value::Scalar)
        }
    }
}