michie 0.1.0

An attribute macro that adds memoization to a function (pronounced /'mikɪ/)
Documentation
use michie::memoized;
use std::{hash::Hash, marker::PhantomData};

#[test]
fn fn0() {
    #[memoized(key_expr = b)]
    fn f(_a: bool, b: usize) -> usize {
        b + 4
    }
    assert_eq!(f(false, 2), 6);
}

#[test]
fn generic_in_impl() {
    struct GenericStruct<T> {
        a: T,
    }

    impl<T> GenericStruct<T>
    where
        T: 'static + Clone + Sync + Eq + Hash,
    {
        #[memoized(key_expr = (self.a.clone(), b.clone()))]
        fn f<U>(&self, b: U) -> (T, U)
        where
            U: 'static + Clone + Sync + Eq + Hash,
        {
            (self.a.clone(), b)
        }
    }
    let concrete_struct = GenericStruct { a: false };
    assert_eq!(concrete_struct.f(4), (false, 4));
    assert_eq!(concrete_struct.f("foo"), (false, "foo"));
}

#[test]
fn trait_implementation_fn() {
    #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    struct Struct;
    impl core::ops::Add for Struct {
        type Output = Self;
        #[memoized(key_expr = (self.clone(), rhs))]
        fn add(self, rhs: Self) -> Self::Output {
            self
        }
    }
    assert_eq!(Struct + Struct, Struct)
}

#[test]
fn errors() {
    let t = trybuild::TestCases::new();
    t.compile_fail("tests/compile_fail/*.rs");
}

#[test]
fn store_as_path() {
    #[memoized(key_expr = b, store_type = ::std::collections::HashMap)]
    fn f2(_a: bool, b: usize) -> usize {
        b + 4
    }
    assert_eq!(f2(false, 2), 6);
}

#[test]
fn store_type_default_from_impl() {
    struct Store<K, V> {
        k: PhantomData<K>,
        v: PhantomData<V>,
    }
    impl<K, V> Store<K, V> {
        fn default() -> Self {
            Self {
                k: PhantomData,
                v: PhantomData,
            }
        }
        fn insert(&mut self, _key: K, _value: V) {}
        fn get(&self, _key: &K) -> Option<&V> {
            None
        }
    }
    #[memoized(key_expr = input, store_type = Store)]
    fn f(input: usize) -> usize {
        input
    }
    assert_eq!(f(2), 2);
}

#[test]
fn store_type_default_from_trait() {
    struct Store<K, V> {
        k: PhantomData<K>,
        v: PhantomData<V>,
    }
    impl<K, V> Default for Store<K, V> {
        fn default() -> Self {
            Self {
                k: PhantomData,
                v: PhantomData,
            }
        }
    }
    impl<K, V> Store<K, V> {
        fn insert(&mut self, _key: K, _value: V) {}
        fn get(&self, _key: &K) -> Option<&V> {
            None
        }
    }
    #[memoized(key_expr = input, store_type = Store)]
    fn f(input: usize) -> usize {
        input
    }
    assert_eq!(f(2), 2);
}

#[test]
fn store_init() {
    struct Store<K, V> {
        k: PhantomData<K>,
        v: PhantomData<V>,
    }
    impl<K, V> Store<K, V> {
        fn new() -> Self {
            Self {
                k: PhantomData,
                v: PhantomData,
            }
        }
        fn insert(&mut self, _key: K, _value: V) {}
        fn get(&self, _key: &K) -> Option<&V> {
            None
        }
    }
    impl<K, V> Default for Store<K, V> {
        fn default() -> Self {
            panic!("`store_init` is expected to be used")
        }
    }
    #[memoized(key_expr = input, store_type = Store, store_init = Store::new())]
    fn f(input: usize) -> usize {
        input
    }
    assert_eq!(f(2), 2);
}

#[test]
fn store_init_concrete() {
    struct Store<K, V> {
        k: PhantomData<K>,
        v: PhantomData<V>,
    }
    impl<K, V> Store<K, V> {
        fn new() -> Self {
            Self {
                k: PhantomData,
                v: PhantomData,
            }
        }
        fn insert(&mut self, _key: K, _value: V) {}
        fn get(&self, _key: &K) -> Option<&V> {
            None
        }
    }
    #[memoized(key_expr = input, store_type = Store, store_init = Store::<usize, usize>::new())]
    fn f(input: usize) -> usize {
        input
    }
    assert_eq!(f(2), 2);
}

#[test]
fn store_init_bound() {
    struct Store<K, V> {
        k: PhantomData<K>,
        v: PhantomData<V>,
    }
    impl<K, V> Store<K, V> {
        fn new() -> Self
        where
            K: Default,
        {
            Self {
                k: PhantomData,
                v: PhantomData,
            }
        }
        fn insert(&mut self, _key: K, _value: V) {}
        fn get(&self, _key: &K) -> Option<&V> {
            None
        }
    }
    #[memoized(key_expr = input, store_type = Store, store_init = Store::new())]
    fn f(input: usize) -> usize {
        input
    }
    assert_eq!(f(2), 2);
}