aufbau 0.3.1

Generalized prefix parsing for a class of context-dependent languages
use std::cell::RefCell;
use std::collections::HashMap;
use std::hash::Hash;
use std::rc::Rc;

use crate::engine::parse::arena::{BOT, EvidenceId, TOP};

pub struct EvidenceStore<E: Hash + Eq + Clone> {
    values: Rc<RefCell<Vec<E>>>,
    index: Rc<RefCell<HashMap<E, EvidenceId>>>,
}

impl<E: Hash + Eq + Clone> Clone for EvidenceStore<E> {
    fn clone(&self) -> Self {
        Self {
            values: Rc::clone(&self.values),
            index: Rc::clone(&self.index),
        }
    }
}

impl<E: Hash + Eq + Clone> EvidenceStore<E> {
    pub fn new(top: E, bottom: E) -> Self {
        let store = Self {
            values: Rc::new(RefCell::new(Vec::new())),
            index: Rc::new(RefCell::new(HashMap::new())),
        };
        let top_id = store.intern(top);
        debug_assert_eq!(top_id, TOP, "top evidence must intern at TOP=0");
        let bot_id = store.intern(bottom);
        debug_assert_eq!(bot_id, BOT, "bottom evidence must intern at BOT=1");
        store
    }

    pub fn intern(&self, value: E) -> EvidenceId {
        if let Some(&id) = self.index.borrow().get(&value) {
            return id;
        }
        let mut values = self.values.borrow_mut();
        let id = values.len();
        values.push(value.clone());
        drop(values);
        self.index.borrow_mut().insert(value, id);
        id
    }

    #[must_use]
    pub fn get(&self, id: EvidenceId) -> Option<E> {
        self.values.borrow().get(id).cloned()
    }
}