use std::cell::RefCell;
use std::{
collections::{HashMap, HashSet},
fmt::{Debug, Formatter},
hash::Hash,
};
use crate::completeness::{Completeness, UncheckedCompleteness};
use crate::storage::Storage;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Scope(pub(crate) usize);
impl Debug for Scope {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "#{}", self.0)
}
}
#[derive(Debug)]
pub struct InnerScopeGraph<'sg, LABEL, DATA> {
pub(crate) storage: &'sg Storage,
#[allow(clippy::type_complexity)]
pub(crate) edges: RefCell<Vec<&'sg RefCell<HashMap<LABEL, HashSet<Scope>>>>>, pub(crate) data: RefCell<Vec<&'sg DATA>>,
}
impl<'sg, LABEL, DATA> InnerScopeGraph<'sg, LABEL, DATA> {
fn new(storage: &'sg Storage) -> Self {
Self {
storage,
edges: RefCell::new(Vec::new()),
data: RefCell::new(Vec::new()),
}
}
pub(super) fn add_scope(&self, data: DATA) -> Scope {
let id = self.data.borrow().len();
self.data.borrow_mut().push(self.storage.0.alloc(data));
self.edges.borrow_mut().push(
self.storage
.0
.alloc(RefCell::new(HashMap::with_capacity(0))),
);
Scope(id)
}
fn get_data(&self, scope: Scope) -> &'sg DATA {
self.data.borrow()[scope.0]
}
}
impl<'sg, LABEL: Hash + Eq, DATA> InnerScopeGraph<'sg, LABEL, DATA> {
pub(crate) fn add_edge(&self, src: Scope, lbl: LABEL, dst: Scope) {
self.edges.borrow()[src.0]
.borrow_mut()
.entry(lbl)
.or_default()
.insert(dst);
}
pub(crate) fn get_edges(&self, scope: Scope, lbl: LABEL) -> Vec<Scope> {
self.edges.borrow()[scope.0]
.borrow()
.get(&lbl)
.into_iter()
.flatten()
.copied()
.collect()
}
}
#[derive(Debug)]
pub struct ScopeGraph<'storage, LABEL, DATA, CMPL> {
pub(super) inner_scope_graph: InnerScopeGraph<'storage, LABEL, DATA>,
pub(super) completeness: CMPL,
}
impl<'storage, LABEL, DATA, CMPL> ScopeGraph<'storage, LABEL, DATA, CMPL> {
pub fn new(storage: &'storage Storage, completeness: CMPL) -> Self {
ScopeGraph {
inner_scope_graph: InnerScopeGraph::new(storage),
completeness,
}
}
}
impl<'sg, LABEL, DATA> ScopeGraph<'sg, LABEL, DATA, UncheckedCompleteness> {
pub unsafe fn raw(storage: &'sg Storage) -> Self {
Self::new(storage, UncheckedCompleteness::new())
}
}
impl<'sg, LABEL, DATA, CMPL> ScopeGraph<'sg, LABEL, DATA, CMPL>
where
CMPL: Completeness<LABEL, DATA>,
{
pub fn add_scope(&self, data: DATA) -> Scope {
let scope = self.inner_scope_graph.add_scope(data);
self.completeness
.cmpl_new_scope(&self.inner_scope_graph, scope);
scope
}
pub fn add_edge(&self, src: Scope, lbl: LABEL, dst: Scope) -> CMPL::NewEdgeResult {
self.completeness
.cmpl_new_edge(&self.inner_scope_graph, src, lbl, dst)
}
pub fn get_data(&self, scope: Scope) -> &DATA {
self.inner_scope_graph.get_data(scope)
}
pub fn get_edges(&self, src: Scope, lbl: LABEL) -> CMPL::GetEdgesResult<'_> {
self.completeness
.cmpl_get_edges(&self.inner_scope_graph, src, lbl)
}
pub fn add_decl(&self, src: Scope, lbl: LABEL, data: DATA) -> CMPL::NewEdgeResult {
let s_data = self.inner_scope_graph.add_scope(data);
self.completeness
.cmpl_new_complete_scope(&self.inner_scope_graph, s_data);
self.add_edge(src, lbl, s_data)
}
}
impl<'sg, LABEL, DATA, CMPL> ScopeGraph<'sg, LABEL, DATA, CMPL>
where
DATA: Default,
CMPL: Completeness<LABEL, DATA>,
{
pub fn add_scope_default(&self) -> Scope {
self.add_scope(DATA::default())
}
}