anyerr 0.1.1

Dynamic error library with rich error wrapping and context support
Documentation
mod facade;

pub use facade::*;

use std::borrow::Borrow;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::marker::PhantomData;
use std::slice::Iter as SliceIter;

use crate::context::iter::CommonIter;
use crate::context::{AbstractContext, Context, Entry};
use crate::converter::Converter;

/// The iterator of [`MapContext`].
pub type MapIter<'a, E> = CommonIter<'a, E, SliceIter<'a, E>>;

/// The common implementation of all map-like contexts.
#[derive(Debug, PartialEq, Eq)]
pub struct MapContext<E: Entry, C: Converter> {
    entries: Vec<E>,
    _phantom: PhantomData<C>,
}

impl<E: Entry, C: Converter> MapContext<E, C> {
    /// Creates a new [`MapContext`].
    pub fn new() -> Self {
        Self::from(Vec::<E>::new())
    }
}

impl<E: Entry, C: Converter> From<Vec<E>> for MapContext<E, C> {
    fn from(entries: Vec<E>) -> Self {
        Self {
            entries,
            _phantom: Default::default(),
        }
    }
}

impl<E: Entry, C: Converter, Q, R> From<Vec<(Q, R)>> for MapContext<E, C>
where
    Q: Into<<Self as AbstractContext>::Key>,
    R: Into<<Self as AbstractContext>::Value>,
{
    fn from(entries: Vec<(Q, R)>) -> Self {
        entries.into_iter().collect()
    }
}

impl<E: Entry, C: Converter> FromIterator<E> for MapContext<E, C> {
    fn from_iter<T: IntoIterator<Item = E>>(iter: T) -> Self {
        iter.into_iter().collect::<Vec<_>>().into()
    }
}

impl<E: Entry, C: Converter, Q, R> FromIterator<(Q, R)> for MapContext<E, C>
where
    Q: Into<<Self as AbstractContext>::Key>,
    R: Into<<Self as AbstractContext>::Value>,
{
    fn from_iter<T: IntoIterator<Item = (Q, R)>>(iter: T) -> Self {
        iter.into_iter()
            .map(|(key, value)| E::new(key.into(), value.into()))
            .collect()
    }
}

impl<E: Entry, C: Converter> Default for MapContext<E, C> {
    fn default() -> Self {
        Self::new()
    }
}

impl<E: Entry, C: Converter> AbstractContext for MapContext<E, C> {
    type Key = E::Key;

    type Value = E::Value;

    type Entry = E;

    type Iter<'a>
        = MapIter<'a, E>
    where
        E: 'a;

    fn iter(&self) -> Self::Iter<'_> {
        self.entries.iter().into()
    }
}

impl<E: Entry, C: Converter> Context for MapContext<E, C> {
    type Converter = C;

    fn insert<Q, R>(&mut self, key: Q, value: R)
    where
        Q: Into<Self::Key>,
        R: Into<Self::Value>,
    {
        self.entries.push(Self::Entry::new(key, value));
    }

    fn get<Q>(&self, key: &Q) -> Option<&<Self::Entry as Entry>::ValueBorrowed>
    where
        <Self::Entry as Entry>::KeyBorrowed: Borrow<Q>,
        Q: Debug + Eq + Hash + ?Sized,
    {
        self.entries
            .iter()
            .find(|entry| entry.key().borrow() == key)
            .map(Entry::value)
    }
}

/// The common implementation of entries of map-like contexts, typically
/// used by [`MapContext`].
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct MapEntry<K, KB, V, VB>
where
    K: Borrow<KB> + Debug + Send + Sync + 'static,
    KB: Debug + Display + Eq + Hash + ?Sized + Send + Sync + 'static,
    V: Borrow<VB> + Debug + Send + Sync + 'static,
    VB: Debug + ?Sized + Send + Sync + 'static,
{
    key: K,
    value: V,
    _phantom: PhantomData<(Box<KB>, Box<VB>)>,
}

impl<K, KB, V, VB, Q, R> From<(Q, R)> for MapEntry<K, KB, V, VB>
where
    K: Borrow<KB> + Debug + Send + Sync + 'static,
    KB: Debug + Display + Eq + Hash + ?Sized + Send + Sync + 'static,
    V: Borrow<VB> + Debug + Send + Sync + 'static,
    VB: Debug + ?Sized + Send + Sync + 'static,
    Q: Into<<Self as Entry>::Key>,
    R: Into<<Self as Entry>::Value>,
{
    fn from((key, value): (Q, R)) -> Self {
        Self::new(key.into(), value.into())
    }
}

impl<K, KB, V, VB> Entry for MapEntry<K, KB, V, VB>
where
    K: Borrow<KB> + Debug + Send + Sync + 'static,
    KB: Debug + Display + Eq + Hash + ?Sized + Send + Sync + 'static,
    V: Borrow<VB> + Debug + Send + Sync + 'static,
    VB: Debug + ?Sized + Send + Sync + 'static,
{
    type Key = K;

    type KeyBorrowed = KB;

    type Value = V;

    type ValueBorrowed = VB;

    fn new<Q, R>(key: Q, value: R) -> Self
    where
        Q: Into<Self::Key>,
        R: Into<Self::Value>,
    {
        Self {
            key: key.into(),
            value: value.into(),
            _phantom: Default::default(),
        }
    }

    fn key(&self) -> &Self::KeyBorrowed {
        self.key.borrow()
    }

    fn value(&self) -> &Self::ValueBorrowed {
        self.value.borrow()
    }
}

#[cfg(test)]
mod tests {
    use crate::context::Iter;
    use crate::converter::DebugConverter;

    use super::*;

    type TestEntry = MapEntry<String, str, String, str>;
    type TestContext = MapContext<TestEntry, DebugConverter>;

    #[test]
    fn string_entry_getter_succeeds() {
        let entry = TestEntry::new("key", "1");
        assert_eq!("key", entry.key());
        assert_eq!("1", entry.value());
    }

    #[test]
    fn string_map_context_operation_succeeds() {
        let mut context = TestContext::new();
        context.insert("key1", "1");
        context.insert_with::<DebugConverter, _, _>("key2", 2);
        context.insert_with::<DebugConverter, _, _>("key3", "3");
        assert_eq!(context.get("key1").unwrap(), "1");
        assert_eq!(context.get("key2").unwrap(), "2");
        assert_eq!(context.get("key3").unwrap(), "\"3\"");
    }

    #[test]
    fn string_map_context_iter_from_succeeds() {
        let context = TestContext::from(vec![
            TestEntry::new("key1", "1"),
            TestEntry::new("key2", "2"),
        ]);
        let mut iter = context.iter();
        assert_eq!(Some(&TestEntry::new("key1", "1")), iter.next());
        assert_eq!(Some(&TestEntry::new("key2", "2")), iter.next());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn string_map_context_iter_concat_succeeds() {
        let context1 = TestContext::from(vec![
            TestEntry::new("key1", "1"),
            TestEntry::new("key2", "2"),
        ]);
        let context2 = TestContext::from(vec![
            TestEntry::new("key3", "3"),
            TestEntry::new("key4", "4"),
        ]);
        let mut iter = context1.iter().compose(context2.iter());
        assert_eq!(Some(&TestEntry::new("key1", "1")), iter.next());
        assert_eq!(Some(&TestEntry::new("key2", "2")), iter.next());
        assert_eq!(Some(&TestEntry::new("key3", "3")), iter.next());
        assert_eq!(Some(&TestEntry::new("key4", "4")), iter.next());
        assert_eq!(None, iter.next());
    }
}