moogle 0.4.4

data structures for relational code
use crate::id::IdLike;
use crate::methods::{EvictSet, ViewSet};

use std::collections::BTreeMap;

#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub(crate) struct ToOne<K: IdLike, V: IdLike>(pub(crate) BTreeMap<K, V>);

impl<K: IdLike, V: IdLike> ToOne<K, V> {
    pub fn keys<'a>(&'a self) -> impl 'a+DoubleEndedIterator<Item=K> { 
        self.0.keys().map(|k| *k) 
    }
    pub fn iter<'a>(&'a self) -> impl 'a+DoubleEndedIterator<Item=(K, V)> { 
        self.0.iter().map(|(k, v)| (*k, *v) ) 
    }
    pub fn values<'a>(&'a self) -> impl 'a+DoubleEndedIterator<Item=V> { 
        self.0.values().map(|v| *v ) 
    }
}

impl<'a, K: IdLike, V: IdLike> ToOne<K, V> {
    pub fn new() -> Self { ToOne(BTreeMap::new()) }

    pub fn insert(&mut self, key: K, value: V, on_evict: impl FnOnce(K, V)) -> Option<V> { 
        match self.0.get_mut(&key) {
            Some(x) => {
                if *x == value {
                    // skip on-evict callback, as we would just immediately put the value back into the opposed data structure
                    // but to caller, pretend we evicted
                    return Some(value)
                }

                let mut old = value;
                std::mem::swap(x, &mut old);
                on_evict(key, old);
                Some(old)
            }
            None => {
                self.0.insert(key, value);
                None
            }
        }
    }

    pub fn expunge(&mut self, key: K, on_evict: impl FnOnce(K, V)) -> Option<V> { 
        let value = self.0.remove(&key);
        match value {
            Some(x) => { on_evict(key, x); Some(x) }
            None => None
        }
    }

    pub fn remove(&mut self, key: K, value: V, on_evict: impl FnOnce(K, V)) -> Option<V> {
        if self.0.get(&key) == Some(&value) {
            on_evict(key, value);
            self.0.remove(&key)
        } else {
            None
        }
    }

    pub fn get(&self, key: K) -> VOne<'a, K, V> { VOne(self.0.get(&key).map(|x| *x), ::std::marker::PhantomData) }
    pub fn contains_key(&self, key: K) -> bool { self.0.contains_key(&key) }
    pub fn len(&self) -> usize { self.0.len() }
}

pub(crate) struct VOne<'a, K: IdLike, V: IdLike>(Option<V>, ::std::marker::PhantomData<&'a *const K>);
pub(crate) struct MOne<'a, K: IdLike, V: IdLike>(K, &'a mut ToOne<K, V>);  

impl <'a, K: IdLike, V: IdLike> VOne<'a, K, V> {
    pub fn as_option(&self) -> Option<V> { self.0 }
}

impl<'a, K: IdLike, V: IdLike> EvictSet<'a, K, V> for MOne<'a, K, V> {
    fn insert(&mut self, v: V, on_evict: impl FnOnce(K, V)) -> Option<V> { 
        self.1.insert(self.0, v, on_evict)
    }

    fn remove(&mut self, v: V, on_evict: impl FnOnce(K, V)) -> Option<V> { 
        self.1.remove(self.0, v, on_evict)
    }
}

impl<'a, K: IdLike, V: IdLike> ViewSet<'a, V> for VOne<'a, K, V> {
    type Iter = impl 'a+DoubleEndedIterator<Item=V>;

    fn contains(&self, v: V) -> bool {
        match self.0 {
            None => false,
            Some(x) => x == v,
        }
    }

    fn len(&self) -> usize { 
        match self.0 {
            None => 0,
            Some(_) => 1,
        }
    }

    fn iter(&'a self) -> Self::Iter { 
        self.0.iter().map(|v| *v)
    }
}

impl<'a, K: IdLike, V: IdLike> ViewSet<'a, V> for MOne<'a, K, V> {
    type Iter = impl 'a+DoubleEndedIterator<Item=V>;

    fn contains(&self, v: V) -> bool { 
        match self.1.0.get(&self.0) {
            None => false,
            Some(x) => *x == v,
        }
    }

    fn len(&self) -> usize { 
        match self.1.0.get(&self.0) {
            None => 0,
            Some(_) => 1,
        }
    }

    fn iter(&'a self) -> Self::Iter { 
        self.1.0.get(&self.0).map(|x| *x).into_iter()
    }
}

// == Standard traits ==
impl<A: IdLike, B: IdLike> IntoIterator for ToOne<A, B> {
    type Item = (A, B);

    type IntoIter = impl DoubleEndedIterator<Item=(A, B)>;

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