pochoir-lang 0.12.2

Custom parser and interpreter for the pochoir template engine
Documentation
//! Defines the [`Object`] structure.
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::{borrow::Borrow, fmt, hash::Hash};

use crate::{value, IntoValue, Value};

// Copied from the [indexmap](https://github.com/bluss/indexmap/blob/1ce0afebcc9dca0316ed8dd0e3a16f66c03fef91/src/macros.rs) crate by `bluss` and `cuviper`, under the MIT license.
#[macro_export]
macro_rules! object {
    (@single $($x:tt)*) => (());
    (@count $($rest:expr),*) => (<[()]>::len(&[$($crate::object!(@single $rest)),*]));

    ($($key:expr => $value:expr,)+) => { $crate::object!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let _cap = $crate::object!(@count $($key),*);
            let mut _obj = $crate::Object::with_capacity(_cap);
            $(
                _obj.insert($key, $value);
            )*
            _obj
        }
    };
}

#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Object {
    inner: IndexMap<String, Value>,
}

impl Object {
    pub fn new() -> Self {
        Self {
            inner: IndexMap::new(),
        }
    }

    pub fn with_capacity(n: usize) -> Self {
        Self {
            inner: IndexMap::with_capacity(n),
        }
    }

    pub fn insert<K: Into<String>, V: IntoValue>(&mut self, key: K, val: V) {
        self.inner.insert(key.into(), val.into_value());
    }

    pub fn insert_serialize<K: Into<String>, V: Serialize>(&mut self, key: K, val: V) {
        if let Ok(val) = value::serialize_to_value(val) {
            self.inner.insert(key.into(), val);
        }
    }

    pub fn remove<K: Hash + Eq + ?Sized>(&mut self, key: &K) -> Option<Value>
    where
        String: Borrow<K>,
    {
        self.inner.swap_remove(key)
    }

    pub fn contains_key<K: Hash + Eq + ?Sized>(&self, key: &K) -> bool
    where
        String: Borrow<K>,
    {
        self.inner.contains_key(key)
    }

    pub fn get<K: Hash + Eq + ?Sized>(&self, key: &K) -> Option<&Value>
    where
        String: Borrow<K>,
    {
        self.inner.get(key)
    }

    pub fn get_mut<K: Hash + Eq + ?Sized>(&mut self, key: &K) -> Option<&mut Value>
    where
        String: Borrow<K>,
    {
        self.inner.get_mut(key)
    }

    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }

    pub fn len(&self) -> usize {
        self.inner.len()
    }

    pub fn iter(&self) -> indexmap::map::Iter<'_, String, Value> {
        self.inner.iter()
    }

    pub fn iter_mut(&mut self) -> indexmap::map::IterMut<'_, String, Value> {
        self.inner.iter_mut()
    }
}

impl From<IndexMap<String, Value>> for Object {
    fn from(inner: IndexMap<String, Value>) -> Self {
        Self { inner }
    }
}

impl From<Object> for IndexMap<String, Value> {
    fn from(val: Object) -> Self {
        val.inner
    }
}

impl FromIterator<(String, Value)> for Object {
    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
        let mut obj = Self::new();

        for (k, v) in iter {
            obj.insert(k, v);
        }

        Self { inner: obj.inner }
    }
}

impl IntoIterator for Object {
    type Item = (String, Value);

    type IntoIter = indexmap::map::IntoIter<String, Value>;

    fn into_iter(self) -> Self::IntoIter {
        self.inner.into_iter()
    }
}

impl<'a> IntoIterator for &'a Object {
    type Item = (&'a String, &'a Value);

    type IntoIter = indexmap::map::Iter<'a, String, Value>;

    fn into_iter(self) -> Self::IntoIter {
        self.inner.iter()
    }
}

impl<'a> IntoIterator for &'a mut Object {
    type IntoIter = indexmap::map::IterMut<'a, String, Value>;
    type Item = (&'a String, &'a mut Value);

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

impl Extend<(String, Value)> for Object {
    fn extend<T: IntoIterator<Item = (String, Value)>>(&mut self, iter: T) {
        for (k, v) in iter {
            self.insert(k, v);
        }
    }
}

impl fmt::Display for Object {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", Value::Object(self.clone()))
    }
}

#[cfg(test)]
mod tests {
    use crate::deserialize_from_value;

    use super::*;

    #[test]
    fn deserialize_object() {
        let obj = object! {
            "name" => "John",
            "age" => 32,
        };
        let val = Value::Object(obj.clone());
        assert_eq!(deserialize_from_value::<Object>(val).unwrap(), obj);
    }
}