Rule execution now runs, no tests tho
This commit is contained in:
@@ -1,21 +1,31 @@
|
||||
use std::ops::{Add, Index};
|
||||
use std::{ops::{Add, Index}, rc::Rc, fmt::Debug};
|
||||
|
||||
use hashbrown::{HashMap, hash_map::IntoIter};
|
||||
use mappable_rc::Mrc;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use crate::expression::Expr;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Entry {
|
||||
Vec(Rc<Vec<Expr>>),
|
||||
Scalar(Rc<Expr>),
|
||||
Name(Rc<String>),
|
||||
NameOpt(Option<Rc<String>>)
|
||||
}
|
||||
|
||||
/// A bucket of indexed expression fragments. Addition may fail if there's a conflict.
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct State(HashMap<String, Mrc<Vec<Expr>>>);
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub struct State(HashMap<String, Entry>);
|
||||
|
||||
/// Clone without also cloning arbitrarily heavy Expr objects.
|
||||
/// Key is expected to be a very short string with an allocator overhead close to zero.
|
||||
impl Clone for State {
|
||||
impl Clone for Entry {
|
||||
fn clone(&self) -> Self {
|
||||
Self(HashMap::from_iter(
|
||||
self.0.iter().map(|(k, v)| (k.clone(), Mrc::clone(v)))
|
||||
))
|
||||
match self {
|
||||
Self::Name(n) => Self::Name(Rc::clone(n)),
|
||||
Self::Scalar(x) => Self::Scalar(Rc::clone(x)),
|
||||
Self::Vec(v) => Self::Vec(Rc::clone(v)),
|
||||
Self::NameOpt(o) => Self::NameOpt(o.as_ref().map(Rc::clone))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,24 +33,65 @@ impl State {
|
||||
pub fn new() -> Self {
|
||||
Self(HashMap::new())
|
||||
}
|
||||
/// Insert a new element, return None on conflict, clone only on success
|
||||
pub fn insert<S>(mut self, k: &S, v: &[Expr]) -> Option<State>
|
||||
pub fn insert_vec<S>(mut self, k: &S, v: &[Expr]) -> Option<Self>
|
||||
where S: AsRef<str> + ToString + ?Sized + Debug {
|
||||
eprintln!("{:?} + {k:?}-{v:?}", self.0);
|
||||
if let Some(old) = self.0.get(k.as_ref()) {
|
||||
if let Entry::Vec(val) = old {
|
||||
if val.as_slice() != v {return None}
|
||||
} else {return None}
|
||||
} else {
|
||||
self.0.insert(k.to_string(), Entry::Vec(Rc::new(v.to_vec())));
|
||||
}
|
||||
Some(self)
|
||||
}
|
||||
pub fn insert_scalar<S>(mut self, k: &S, v: &Expr) -> Option<Self>
|
||||
where S: AsRef<str> + ToString + ?Sized {
|
||||
if let Some(old) = self.0.get(k.as_ref()) {
|
||||
if old.as_ref() != v {return None}
|
||||
if let Entry::Scalar(val) = old {
|
||||
if val.as_ref() != v {return None}
|
||||
} else {return None}
|
||||
} else {
|
||||
self.0.insert(k.to_string(), Mrc::new(v.to_vec()));
|
||||
self.0.insert(k.to_string(), Entry::Scalar(Rc::new(v.to_owned())));
|
||||
}
|
||||
return Some(self)
|
||||
Some(self)
|
||||
}
|
||||
pub fn insert_name<S1, S2>(mut self, k: &S1, v: &S2) -> Option<Self>
|
||||
where
|
||||
S1: AsRef<str> + ToString + ?Sized,
|
||||
S2: AsRef<str> + ToString + ?Sized
|
||||
{
|
||||
if let Some(old) = self.0.get(k.as_ref()) {
|
||||
if let Entry::Name(val) = old {
|
||||
if val.as_str() != v.as_ref() {return None}
|
||||
} else {return None}
|
||||
} else {
|
||||
self.0.insert(k.to_string(), Entry::Name(Rc::new(v.to_string())));
|
||||
}
|
||||
Some(self)
|
||||
}
|
||||
pub fn insert_name_opt<S1, S2>(mut self, k: &S1, v: Option<&S2>) -> Option<Self>
|
||||
where
|
||||
S1: AsRef<str> + ToString + ?Sized,
|
||||
S2: AsRef<str> + ToString + ?Sized
|
||||
{
|
||||
if let Some(old) = self.0.get(k.as_ref()) {
|
||||
if let Entry::NameOpt(val) = old {
|
||||
if val.as_ref().map(|s| s.as_ref().as_str()) != v.map(|s| s.as_ref()) {return None}
|
||||
} else {return None}
|
||||
} else {
|
||||
self.0.insert(k.to_string(), Entry::NameOpt(v.map(|s| Rc::new(s.to_string()))));
|
||||
}
|
||||
Some(self)
|
||||
}
|
||||
/// Insert a new entry, return None on conflict
|
||||
pub fn insert_pair(mut self, (k, v): (String, Mrc<Vec<Expr>>)) -> Option<State> {
|
||||
pub fn insert_pair(mut self, (k, v): (String, Entry)) -> Option<State> {
|
||||
if let Some(old) = self.0.get(&k) {
|
||||
if old != &v {return None}
|
||||
} else {
|
||||
self.0.insert(k, v);
|
||||
}
|
||||
return Some(self)
|
||||
Some(self)
|
||||
}
|
||||
/// Returns `true` if the state contains no data
|
||||
pub fn empty(&self) -> bool {
|
||||
@@ -58,7 +109,7 @@ impl Add for State {
|
||||
for pair in rhs.0 {
|
||||
self = self.insert_pair(pair)?
|
||||
}
|
||||
return Some(self);
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,20 +121,20 @@ impl Add<Option<State>> for State {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Index<&S> for State where S: AsRef<str> {
|
||||
type Output = Vec<Expr>;
|
||||
impl<S> Index<S> for State where S: AsRef<str> {
|
||||
type Output = Entry;
|
||||
|
||||
fn index(&self, index: &S) -> &Self::Output {
|
||||
fn index(&self, index: S) -> &Self::Output {
|
||||
return &self.0[index.as_ref()]
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for State {
|
||||
type Item = (String, Mrc<Vec<Expr>>);
|
||||
type Item = (String, Entry);
|
||||
|
||||
type IntoIter = IntoIter<String, Mrc<Vec<Expr>>>;
|
||||
type IntoIter = hashbrown::hash_map::IntoIter<String, Entry>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user