use ::std::cell::RefCell;
use ::std::collections::HashSet;
use ::std::fmt;
use ::std::hash;
use ::std::rc::Rc;
use ::std::sync::atomic::AtomicUsize;
use ::std::sync::atomic::Ordering::Relaxed;
use ::lazy_static::lazy_static;
use crate::name::{AnonName, GivenName, InputName, Name};
use ustr::Ustr;
lazy_static! {
static ref COUNTER: AtomicUsize = AtomicUsize::new(0);
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RootScope {
root_data: Rc<RootScopeData>,
}
struct RootScopeData {
nr: usize,
scopes: RefCell<Vec<ScopeData>>,
}
impl fmt::Debug for RootScopeData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RootScopeData {{ ")?;
write!(f, "nr: {}, ", self.nr)?;
write!(f, "scopes: {}, ", self.scopes.borrow().len())?;
write!(f, " }}")
}
}
impl RootScope {
pub fn new_root() -> Scope {
let root = RootScope {
root_data: Rc::new(RootScopeData {
nr: COUNTER.fetch_add(1, Relaxed),
scopes: RefCell::new(vec![]),
}),
};
root.root_data.scopes.borrow_mut().push(ScopeData {
parent: None,
children: vec![],
given_names: HashSet::new(),
anon_names: vec![],
});
Scope {
root,
index: 0,
}
}
fn add_scope(&self, scope_data: ScopeData) -> Scope {
let mut scopes = self.root_data.scopes.borrow_mut();
scopes.push(scope_data);
Scope {
root: self.clone(),
index: scopes.len() - 1,
}
}
fn scope_data_at<T>(&self, index: usize, accessor: impl FnOnce(&mut ScopeData) -> T) -> T {
accessor(&mut self.root_data.scopes.borrow_mut()[index])
}
}
impl PartialEq for RootScopeData {
fn eq(&self, other: &Self) -> bool {
self.nr == other.nr
}
}
impl Eq for RootScopeData {}
impl hash::Hash for RootScopeData {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.nr.hash(state)
}
}
#[derive(Debug, Clone)]
pub struct Scope {
root: RootScope,
index: usize,
}
#[derive(Debug)]
pub struct ScopeData {
parent: Option<usize>,
children: Vec<usize>,
given_names: HashSet<GivenName>,
anon_names: Vec<AnonName>,
}
impl PartialEq for Scope {
fn eq(&self, other: &Self) -> bool {
self.index == other.index && self.root == other.root
}
}
impl Eq for Scope {}
impl hash::Hash for Scope {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.root.hash(state);
self.index.hash(state)
}
}
#[derive(Debug)]
pub struct ScopeChildrenIterator {
scope: Scope,
child_nr: usize,
}
impl Iterator for ScopeChildrenIterator {
type Item = Scope;
fn next(&mut self) -> Option<Self::Item> {
let child_index = self.scope.root.scope_data_at(self.scope.index, |data| {
data.children.get(self.child_nr).cloned()
});
match child_index {
Some(child_index) => {
let scope = Scope {
root: self.scope.root.clone(),
index: child_index,
};
self.child_nr += 1;
Some(scope)
}
None => None,
}
}
}
#[derive(Debug)]
pub struct AlreadyExists();
impl Scope {
pub fn children(&self) -> ScopeChildrenIterator {
ScopeChildrenIterator {
scope: self.clone(),
child_nr: 0,
}
}
pub fn add_child(&self) -> Self {
let child_scope = {
self.root.add_scope(ScopeData {
parent: Some(self.index),
children: vec![],
given_names: HashSet::new(),
anon_names: vec![],
})
};
self.root
.scope_data_at(self.index, |data| data.children.push(child_scope.index));
child_scope
}
pub fn add_named(&self, name: &str) -> Result<Name, AlreadyExists> {
let given_name = GivenName {
name: Ustr::from(name),
};
let is_new = self.root.scope_data_at(self.index, |data| {
data.given_names.insert(given_name.clone())
});
if !is_new {
return Err(AlreadyExists());
}
Ok(Name {
scope: (*self).clone(),
data: InputName::Given(given_name),
})
}
pub fn add_prefixed(&self, prefix: &str) -> Name {
let anon_name = AnonName {
name: Ustr::from(prefix),
};
self.root
.scope_data_at(self.index, |data| data.anon_names.push(anon_name.clone()));
Name {
scope: (*self).clone(),
data: InputName::Anonymous(anon_name),
}
}
pub fn add_anonymous(&self) -> Name {
self.add_prefixed("")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_root() {
let root = RootScope::new_root();
root.add_child();
let child2 = root.add_child();
child2.add_child();
child2.add_child();
}
#[test]
fn add_named_unique() {
let root = RootScope::new_root();
root.add_named("hello").unwrap();
root.add_named("bye").unwrap();
let child1 = root.add_child();
child1.add_named("nihao").unwrap();
}
#[test]
fn add_named_duplicate() {
let root = RootScope::new_root();
root.add_named("hello").unwrap();
let child1 = root.add_child();
child1.add_named("hello").unwrap();
child1.add_named("hello").unwrap_err();
}
}