ratio-interner 0.1.1

Ratio's value interner library.
Documentation
//! # Keyed collection handling
//!
//! Traits and implementations for the handling of collections of keys.
//!
//! ## License
//!
//! This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
//! If a copy of the MPL was not distributed with this file,
//! You can obtain one at <https://mozilla.org/MPL/2.0/>.
//!
//! **Code examples both in the docstrings and rendered documentation are free to use.**

use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::Hash;
use std::marker::PhantomData;

use crate::interner::Interner;

/// Collection storage for collections of interned values where keys supplied to this instance
/// return some collection of interned values, which may be a set of interned keys, a map of
/// interned keys to values or even a plain option.
///
/// Feel free to make an alias of this struct with more specific documentation and constructors.
///
/// Generics:
///
/// - CollectionMap: forward lookup of keys to collections of interned keys.
/// - ReverseLookup: reverse lookup type from interned keys to a set of keys for the collection map.
/// - ReverseSet: type of set to use for the reverse lookup results.
/// - Interner: internal supporting value interner from IK keys to IV values.
/// - K: external key type.
/// - C: the collection type that should support the basic KeyCollection behavior, but may be
///   extended using MapCollection or other collection traits.
/// - IK: interned key type.
/// - IV: interned value type.
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(
    feature = "serde",
    derive(serde::Serialize, serde::Deserialize),
    serde(default, rename_all = "camelCase")
)]
pub struct CollectionStore<CollectionMap, ReverseLookup, ReverseSet, Interner, K, C, IK, IV>
where
    CollectionMap: MapCollection<Key = K, Value = C>,
    ReverseLookup: MapCollection<Key = IK, Value = ReverseSet>,
    ReverseSet: KeyCollection<K> + FlatCollection<K>,
    Interner: crate::interner::Interner<IK, IV>,
    K: Copy,
    C: KeyCollection<IK>,
    IK: Copy,
    IV: Clone,
{
    /// Keys mapping to collections of inner keys.
    pub collections: CollectionMap,

    /// Reverse lookup from interned keys to collection keys where they were used in.
    pub reverse: ReverseLookup,

    /// Value interner for collectable values.
    pub inner: Interner,

    /// Inner value type marker.
    _interned_value: PhantomData<IV>,
}

impl<CollectionMap, ReverseLookup, ReverseSet, Inner, K, C, IK, IV> CollectionInterner<K, C, IK, IV>
    for CollectionStore<CollectionMap, ReverseLookup, ReverseSet, Inner, K, C, IK, IV>
where
    CollectionMap: MapCollection<Key = K, Value = C>,
    ReverseLookup: MapCollection<Key = IK, Value = ReverseSet>,
    ReverseSet: KeyCollection<K> + FlatCollection<K>,
    Inner: Interner<IK, IV>,
    K: Copy,
    C: KeyCollection<IK> + Clone,
    IK: Copy,
    IV: Clone,
{
    fn get(&self, key: K) -> Option<&C> {
        self.collections.collection_value(&key)
    }

    fn get_mut(&mut self, key: K) -> Option<&mut C> {
        self.collections.collection_value_mut(&key)
    }

    fn with_inner(&self, inner: IK) -> impl Iterator<Item = K> {
        self.reverse
            .collection_value(&inner)
            .into_iter()
            .flat_map(|cols| cols.collection_keys())
    }

    fn with_inner_value(&self, inner: &IV) -> impl Iterator<Item = K> {
        self.interner()
            .get_key(inner)
            .map(|inner| self.with_inner(inner))
            .into_iter()
            .flatten()
    }

    fn contains(&self, key: K) -> bool {
        self.collections.collection_contains(&key)
    }

    fn interner(&self) -> &impl Interner<IK, IV> {
        &self.inner
    }

    fn interner_mut(&mut self) -> &mut impl Interner<IK, IV> {
        &mut self.inner
    }

    fn is_empty(&self) -> bool {
        self.collections.collection_is_empty()
    }

    fn keys(&self) -> impl Iterator<Item = K> {
        self.collections.collection_keys()
    }

    fn len(&self) -> usize {
        self.collections.collection_len()
    }

    fn remove(&mut self, key: K) -> bool {
        match self.collections.remove_collection_value(&key) {
            Some(coll) => {
                coll.collection_keys().for_each(|inner_key| {
                    self.reverse
                        .collection_value_mut(&inner_key)
                        .map(|lookup| lookup.remove_collection_key(&key));
                });
                true
            }
            None => false,
        }
    }
}

/// Collection storage of interned key-value pairs.
/// I.e. this stores collections that consist of these interned values such as sets, options, or
/// even maps that use the interned keys to associate values with those keys.
pub trait CollectionInterner<K: Copy, C: Clone + KeyCollection<IK>, IK: Copy, IV: Clone> {
    /// Reference to an inner value interner.
    fn interner(&self) -> &impl Interner<IK, IV>;

    /// Mutable reference to an inner value interner.
    fn interner_mut(&mut self) -> &mut impl Interner<IK, IV>;

    /// Number of stored collections.
    fn len(&self) -> usize;

    /// Whether any collections are stored.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Iterate over all known keys to collections.
    fn keys(&self) -> impl Iterator<Item = K>;

    /// Reference to a stored collection.
    fn get(&self, key: K) -> Option<&C>;

    /// Mutable reference to a stored collection.
    fn get_mut(&mut self, key: K) -> Option<&mut C>;

    /// Keys to collections that have this interned key.
    fn with_inner(&self, inner: IK) -> impl Iterator<Item = K>;

    /// Keys to collections that have this interned value.
    fn with_inner_value(&self, inner: &IV) -> impl Iterator<Item = K>;

    /// Whether a collection is stored for this key.
    fn contains(&self, key: K) -> bool;

    /// Remove a stored collection.
    fn remove(&mut self, key: K) -> bool;
}

/// Behavior for a collection of interned keys.
/// I.e. some interner has stored key-value pairs, and this represents a collection of keys.
pub trait KeyCollection<K> {
    /// Keys corresponding to all interned values in this collection.
    fn collection_keys(&self) -> impl Iterator<Item = K>;

    // Whether this collection contains this key.
    fn collection_contains(&self, key: &K) -> bool;

    /// Number of items in this collection.
    fn collection_len(&self) -> usize;

    /// Whether this collection is empty.
    fn collection_is_empty(&self) -> bool {
        self.collection_len() == 0
    }
}
impl<K: Clone + PartialEq> KeyCollection<K> for Option<K> {
    fn collection_keys(&self) -> impl Iterator<Item = K> {
        self.iter().cloned()
    }
    fn collection_contains(&self, key: &K) -> bool {
        self.as_ref() == Some(key)
    }
    fn collection_len(&self) -> usize {
        match self {
            Some(_) => 1,
            None => 0,
        }
    }
    fn collection_is_empty(&self) -> bool {
        self.is_none()
    }
}
impl<K: Clone + PartialEq + Ord> KeyCollection<K> for BTreeSet<K> {
    fn collection_keys(&self) -> impl Iterator<Item = K> {
        self.iter().cloned()
    }
    fn collection_contains(&self, key: &K) -> bool {
        self.contains(key)
    }
    fn collection_len(&self) -> usize {
        self.len()
    }
}
impl<K: Clone + Ord, IV> KeyCollection<K> for BTreeMap<K, IV> {
    fn collection_keys(&self) -> impl Iterator<Item = K> {
        self.keys().cloned()
    }
    fn collection_contains(&self, key: &K) -> bool {
        BTreeMap::contains_key(self, key)
    }
    fn collection_len(&self) -> usize {
        self.len()
    }
}
impl<K: Clone + Hash + Eq> KeyCollection<K> for HashSet<K> {
    fn collection_keys(&self) -> impl Iterator<Item = K> {
        self.iter().cloned()
    }
    fn collection_contains(&self, key: &K) -> bool {
        self.contains(key)
    }
    fn collection_len(&self) -> usize {
        self.len()
    }
}
impl<K: Clone + Hash + Eq, IV> KeyCollection<K> for HashMap<K, IV> {
    fn collection_keys(&self) -> impl Iterator<Item = K> {
        self.keys().cloned()
    }
    fn collection_contains(&self, key: &K) -> bool {
        self.contains_key(key)
    }
    fn collection_len(&self) -> usize {
        self.len()
    }
}

/// Behavior for a collection of interned keys without sub-values.
/// Examples are plain values, options, and sets.
pub trait FlatCollection<K: Clone>: KeyCollection<K> {
    /// Insert an inner key into this collection.
    fn insert_collection_key(&mut self, key: K) -> Option<K>;

    /// Remove an inner key from this collection.
    fn remove_collection_key(&mut self, key: &K) -> Option<K>;
}
impl<K: Clone + PartialEq> FlatCollection<K> for Option<K> {
    fn insert_collection_key(&mut self, key: K) -> Option<K> {
        self.replace(key)
    }
    fn remove_collection_key(&mut self, key: &K) -> Option<K> {
        if self.as_ref() == Some(key) {
            self.take()
        } else {
            None
        }
    }
}
impl<IK: Clone + Clone + Ord> FlatCollection<IK> for BTreeSet<IK> {
    fn insert_collection_key(&mut self, key: IK) -> Option<IK> {
        if self.insert(key.clone()) {
            None
        } else {
            Some(key)
        }
    }
    fn remove_collection_key(&mut self, key: &IK) -> Option<IK> {
        if self.remove(key) {
            Some(key.clone())
        } else {
            None
        }
    }
}
impl<IK: Clone + Hash + Eq> FlatCollection<IK> for HashSet<IK> {
    fn insert_collection_key(&mut self, key: IK) -> Option<IK> {
        if self.insert(key.clone()) {
            None
        } else {
            Some(key)
        }
    }
    fn remove_collection_key(&mut self, key: &IK) -> Option<IK> {
        if self.remove(key) {
            Some(key.clone())
        } else {
            None
        }
    }
}

/// Map-like collection behavior for interned keys that can have associated values as if it were
/// a map type like a BTreeMap, HashMap or something similar.
pub trait MapCollection: KeyCollection<Self::Key> {
    type Key: Clone;
    type Value;
    /// Retrieve a reference to an item from the map.
    fn collection_value(&self, key: &Self::Key) -> Option<&Self::Value>;

    /// Retrieve a mutable reference to an item from the map.
    fn collection_value_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value>;

    /// Insert an value for a key.
    fn insert_collection_value(
        &mut self,
        key: Self::Key,
        value: Self::Value,
    ) -> Option<Self::Value>;

    /// Remove a value.
    fn remove_collection_value(&mut self, key: &Self::Key) -> Option<Self::Value>;
}
impl<K: Clone + Ord, V> MapCollection for BTreeMap<K, V> {
    type Key = K;
    type Value = V;
    fn collection_value(&self, key: &K) -> Option<&V> {
        self.get(key)
    }
    fn collection_value_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value> {
        self.get_mut(key)
    }
    fn insert_collection_value(&mut self, key: K, value: V) -> Option<V> {
        self.insert(key, value)
    }
    fn remove_collection_value(&mut self, key: &K) -> Option<V> {
        self.remove(key)
    }
}
impl<K: Clone + Hash + Eq, V> MapCollection for HashMap<K, V> {
    type Key = K;
    type Value = V;
    fn collection_value(&self, key: &K) -> Option<&V> {
        self.get(key)
    }
    fn collection_value_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value> {
        self.get_mut(key)
    }
    fn insert_collection_value(&mut self, key: K, value: V) -> Option<V> {
        self.insert(key, value)
    }
    fn remove_collection_value(&mut self, key: &K) -> Option<V> {
        self.remove(key)
    }
}