redid the parser, patched up the project too.
This commit is contained in:
@@ -1,71 +1,68 @@
|
||||
use std::hash::Hash;
|
||||
use std::{hash::Hash, cell::RefCell};
|
||||
use hashbrown::HashMap;
|
||||
use mappable_rc::Mrc;
|
||||
|
||||
/// Cache the return values of an effectless closure in a hashmap
|
||||
/// Inspired by the closure_cacher crate.
|
||||
pub struct Cache<I, O, F> {
|
||||
store: HashMap<I, O>,
|
||||
closure: F
|
||||
pub struct Cache<I, O: 'static> where O: Clone {
|
||||
store: RefCell<HashMap<I, Mrc<O>>>,
|
||||
closure: RefCell<Box<dyn FnMut (I) -> O + 'static>>
|
||||
}
|
||||
|
||||
impl<I: 'static, O, F> Cache<I, O, F> where
|
||||
I: Eq + Hash,
|
||||
F: FnMut(I) -> O
|
||||
impl<I, O> Cache<I, O> where
|
||||
I: Eq + Hash + Clone,
|
||||
O: Clone
|
||||
{
|
||||
pub fn new(closure: F) -> Self {
|
||||
Self { store: HashMap::new(), closure }
|
||||
}
|
||||
/// Produce and cache a result by copying I if necessary
|
||||
pub fn by_copy(&mut self, i: &I) -> &O where I: Copy {
|
||||
let closure = &mut self.closure;
|
||||
self.store.raw_entry_mut().from_key(i)
|
||||
.or_insert_with(|| (*i, closure(*i))).1
|
||||
pub fn new<F: 'static>(closure: F) -> Self where F: FnMut(I) -> O {
|
||||
Self {
|
||||
store: RefCell::new(HashMap::new()),
|
||||
closure: RefCell::new(Box::new(closure))
|
||||
}
|
||||
}
|
||||
|
||||
/// Produce and cache a result by cloning I if necessary
|
||||
pub fn by_clone(&mut self, i: &I) -> &O where I: Clone {
|
||||
let closure = &mut self.closure;
|
||||
self.store.raw_entry_mut().from_key(i)
|
||||
.or_insert_with(|| (i.clone(), closure(i.clone()))).1
|
||||
pub fn find(&self, i: &I) -> Mrc<O> {
|
||||
let mut closure = self.closure.borrow_mut();
|
||||
let mut store = self.store.borrow_mut();
|
||||
Mrc::clone(store.raw_entry_mut().from_key(i)
|
||||
.or_insert_with(|| (i.clone(), Mrc::new(closure(i.clone())))).1)
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
/// Return the result if it has already been computed
|
||||
pub fn known(&self, i: &I) -> Option<&O> {
|
||||
self.store.get(i)
|
||||
pub fn known(&self, i: &I) -> Option<Mrc<O>> {
|
||||
let store = self.store.borrow();
|
||||
store.get(i).map(Mrc::clone)
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
/// Forget the output for the given input
|
||||
pub fn drop(&mut self, i: &I) -> bool {
|
||||
self.store.remove(i).is_some()
|
||||
pub fn drop(&self, i: &I) -> bool {
|
||||
self.store.borrow_mut().remove(i).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: 'static, O, E, F> Cache<I, Result<O, E>, F> where
|
||||
I: Eq + Hash,
|
||||
E: Clone,
|
||||
F: FnMut(I) -> Result<O, E>
|
||||
impl<I, O, E> Cache<I, Result<O, E>> where
|
||||
I: Eq + Hash + Clone,
|
||||
O: Clone,
|
||||
E: Clone
|
||||
{
|
||||
/// Sink the ref from a Result into the Ok value, such that copying only occurs on the sad path
|
||||
/// but the return value can be short-circuited
|
||||
pub fn by_copy_fallible(&mut self, i: &I) -> Result<&O, E> where I: Copy {
|
||||
self.by_clone(i).as_ref().map_err(|e| e.clone())
|
||||
}
|
||||
/// Sink the ref from a Result into the Ok value, such that cloning only occurs on the sad path
|
||||
/// but the return value can be short-circuited
|
||||
pub fn by_clone_fallible(&mut self, i: &I) -> Result<&O, E> where I: Clone {
|
||||
self.by_clone(i).as_ref().map_err(|e| e.clone())
|
||||
pub fn try_find(&self, i: &I) -> Result<Mrc<O>, E> {
|
||||
let ent = self.find(i);
|
||||
Mrc::try_map(ent, |t| t.as_ref().ok())
|
||||
.map_err(|res| Result::as_ref(&res).err().unwrap().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: 'static, O, F> Cache<I, Option<O>, F> where
|
||||
I: Eq + Hash,
|
||||
F: FnMut(I) -> Option<O>
|
||||
impl<I, O> Cache<I, Option<O>> where
|
||||
I: Eq + Hash + Clone,
|
||||
O: Clone
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
/// Sink the ref from an Option into the Some value such that the return value can be
|
||||
/// short-circuited
|
||||
pub fn by_copy_fallible(&mut self, i: &I) -> Option<&O> where I: Copy {
|
||||
self.by_copy(i).as_ref()
|
||||
}
|
||||
/// Sink the ref from an Option into the Some value such that the return value can be
|
||||
/// short-circuited
|
||||
pub fn by_clone_fallible(&mut self, i: &I) -> Option<&O> where I: Clone {
|
||||
self.by_clone(i).as_ref()
|
||||
pub fn try_find(&self, i: &I) -> Option<Mrc<O>> where I: Clone {
|
||||
let ent = self.find(i);
|
||||
Mrc::try_map(ent, |o| o.as_ref()).ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
mod cache;
|
||||
mod substack;
|
||||
mod result_iter_collect;
|
||||
pub use cache::Cache;
|
||||
pub use substack::Substack;
|
||||
pub use result_iter_collect::result_iter_collect;
|
||||
|
||||
pub fn as_modpath(path: &Vec<String>) -> String {
|
||||
path.join("::")
|
||||
}
|
||||
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
|
||||
19
src/utils/result_iter_collect.rs
Normal file
19
src/utils/result_iter_collect.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
pub fn result_iter_collect<T, E>(i: &mut dyn Iterator<Item = Result<T, E>>)
|
||||
-> (Vec<Option<T>>, Vec<Option<E>>) {
|
||||
i.fold((Vec::new(), Vec::new()), |(mut succ, mut err), mut next| {
|
||||
match next {
|
||||
Ok(res) => succ.push(Some(res)),
|
||||
Err(e) => err.push(Some(e))
|
||||
}
|
||||
(succ, err)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn recoverable_iter_collect<T, E>(i: &mut dyn Iterator<Item=(Option<T>, Vec<E>)>)
|
||||
-> (Vec<Option<T>>, Vec<E>) {
|
||||
i.fold((Vec::new(), Vec::new()), |(mut succ, mut err), (res, mut errv)| {
|
||||
succ.push(res);
|
||||
err.append(&mut errv);
|
||||
(succ, err)
|
||||
})
|
||||
}
|
||||
@@ -9,7 +9,9 @@ pub struct Substack<'a, T> {
|
||||
}
|
||||
|
||||
impl<'a, T> Substack<'a, T> {
|
||||
#[allow(dead_code)]
|
||||
pub fn item(&self) -> &T { &self.item }
|
||||
#[allow(dead_code)]
|
||||
pub fn prev(&self) -> Option<&'a Substack<'a, T>> { self.prev }
|
||||
|
||||
pub fn new(item: T) -> Self {
|
||||
|
||||
Reference in New Issue
Block a user