zhc_utils 0.4.0

Shared utilities for the ZHC compiler
Documentation
use std::fmt::Debug;
use std::ops::Index;

use crate::Dumpable;

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Domain<T>(T);
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct CoDomain<T>(T);

pub struct BiMap<D, C>(Vec<(Domain<D>, CoDomain<C>)>);

impl<D, C> BiMap<D, C>
where
    D: PartialEq,
    C: PartialEq,
{
    pub fn new() -> Self {
        BiMap(Vec::new())
    }

    pub fn insert(&mut self, dom: D, codom: C) {
        for (existing_dom, existing_codom) in &self.0 {
            if existing_dom.0 == dom {
                panic!("Domain value already mapped");
            }
            if existing_codom.0 == codom {
                panic!("CoDomain value already mapped");
            }
        }
        self.0.push((Domain(dom), CoDomain(codom)));
    }

    pub fn get_dom(&self, dom: &D) -> Option<&C> {
        self.0.iter().find(|(d, _)| &d.0 == dom).map(|(_, c)| &c.0)
    }

    pub fn get_dom_mut(&mut self, dom: &D) -> Option<&mut C> {
        self.0
            .iter_mut()
            .find(|(d, _)| &d.0 == dom)
            .map(|(_, c)| &mut c.0)
    }

    pub fn has_dom(&self, dom: &D) -> bool {
        self.get_dom(dom).is_some()
    }

    pub fn get_codom(&self, codom: &C) -> Option<&D> {
        self.0
            .iter()
            .find(|(_, c)| &c.0 == codom)
            .map(|(d, _)| &d.0)
    }

    pub fn get_codom_mut(&mut self, codom: &C) -> Option<&mut D> {
        self.0
            .iter_mut()
            .find(|(_, c)| &c.0 == codom)
            .map(|(d, _)| &mut d.0)
    }

    pub fn has_codom(&self, codom: &C) -> bool {
        self.get_codom(codom).is_some()
    }

    pub fn into_iter(self) -> impl Iterator<Item = (D, C)> {
        self.0.into_iter().map(|(d, c)| (d.0, c.0))
    }

    pub fn iter(&self) -> impl Iterator<Item = (&D, &C)> {
        self.0.iter().map(|(d, c)| (&d.0, &c.0))
    }
}

impl<D, C> Index<Domain<&D>> for BiMap<D, C>
where
    D: PartialEq,
    C: PartialEq,
{
    type Output = C;

    fn index(&self, index: Domain<&D>) -> &Self::Output {
        self.get_dom(index.0)
            .expect("Domain key not found in BiMap")
    }
}

impl<D, C> Index<CoDomain<&C>> for BiMap<D, C>
where
    D: PartialEq,
    C: PartialEq,
{
    type Output = D;

    fn index(&self, index: CoDomain<&C>) -> &Self::Output {
        self.get_codom(index.0)
            .expect("CoDomain key not found in BiMap")
    }
}

impl<D: Dumpable + PartialEq, C: Dumpable + PartialEq> Dumpable for BiMap<D, C> {
    fn dump_to_string(&self) -> String {
        let mut result = String::from("{ ");
        for (dom, codom) in self.iter() {
            result.push_str(&format!(
                "  {:?} <-> {:?}, ",
                dom.dump_to_string(),
                codom.dump_to_string()
            ));
        }
        result.push_str("}");
        result
    }
}