use any_cache::{Cache, HashCache};
use notify::{self, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
use std::collections::{HashMap, HashSet};
use std::fmt::{self, Display};
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::sync::mpsc::{channel, Receiver};
use std::time::Duration;
use crate::key::{Key, PrivateKey};
use crate::res::Res;
pub trait Load<C, K, Method = ()>: 'static + Sized
where K: Key,
Method: ?Sized {
type Error: Display + 'static;
fn load(
key: K,
storage: &mut Storage<C, K>,
ctx: &mut C,
) -> Result<Loaded<Self, K>, Self::Error>;
fn reload(
&self,
key: K,
storage: &mut Storage<C, K>,
ctx: &mut C,
) -> Result<Self, Self::Error> {
Self::load(key, storage, ctx).map(|lr| lr.res)
}
}
pub struct Loaded<T, K> {
pub res: T,
pub deps: Vec<K>,
}
impl<T, K> Loaded<T, K> {
pub fn without_dep(res: T) -> Self {
Loaded {
res,
deps: Vec::new(),
}
}
pub fn with_deps(res: T, deps: Vec<K>) -> Self {
Loaded { res, deps }
}
}
impl<T, K> From<T> for Loaded<T, K> {
fn from(res: T) -> Self {
Loaded::without_dep(res)
}
}
struct ResMetaData<C, K> {
on_reload: Box<dyn Fn(&mut Storage<C, K>, &mut C) -> Result<(), Box<dyn Display>>>,
}
impl<C, K> ResMetaData<C, K> {
fn new<F>(f: F) -> Self
where F: 'static + Fn(&mut Storage<C, K>, &mut C) -> Result<(), Box<dyn Display>> {
ResMetaData {
on_reload: Box::new(f),
}
}
}
pub struct Storage<C, K> {
canon_root: PathBuf,
cache: HashCache,
deps: HashMap<K, Vec<K>>,
metadata: HashMap<K, ResMetaData<C, K>>,
}
impl<C, K> Storage<C, K> where K: Key {
fn new(canon_root: PathBuf) -> Self{
Storage {
canon_root,
cache: HashCache::new(),
deps: HashMap::new(),
metadata: HashMap::new(),
}
}
pub fn root(&self) -> &Path {
&self.canon_root
}
fn inject<T, M>(
&mut self,
key: K,
resource: T,
deps: Vec<K>,
) -> Result<Res<T>, StoreError<K>>
where T: Load<C, K, M> {
if self.metadata.contains_key(&key) {
return Err(StoreError::AlreadyRegisteredKey(key.clone()));
}
let res = Res::new(resource);
let res_ = res.clone();
let key_ = key.clone();
let metadata = ResMetaData::new(move |storage, ctx| {
let reloaded = <T as Load<C, K, M>>::reload(&res_.borrow(), key_.clone(), storage, ctx);
match reloaded {
Ok(r) => {
*res_.borrow_mut() = r;
Ok(())
}
Err(e) => Err(Box::new(e)),
}
});
self.metadata.insert(key.clone(), metadata);
let root = &self.canon_root;
for dep in deps {
self
.deps
.entry(dep.clone().prepare_key(root))
.or_insert(Vec::new())
.push(key.clone());
}
let pkey = PrivateKey::new(key);
self.cache.save(pkey, res.clone());
Ok(res)
}
pub fn get<T>(&mut self, key: &K, ctx: &mut C) -> Result<Res<T>, StoreErrorOr<T, C, K>>
where T: Load<C, K> {
self.get_by(key, ctx, ())
}
pub fn get_by<T, M>(
&mut self,
key: &K,
ctx: &mut C,
_: M,
) -> Result<Res<T>, StoreErrorOr<T, C, K, M>>
where T: Load<C, K, M> {
let key = key.clone().prepare_key(self.root());
let pkey = PrivateKey::<K, T>::new(key);
let x: Option<Res<T>> = self.cache.get(&pkey).cloned();
let key = pkey.0;
match x {
Some(resource) => Ok(resource),
None => {
let loaded =
<T as Load<C, K, M>>::load(key.clone(), self, ctx).map_err(StoreErrorOr::ResError)?;
self
.inject::<T, M>(key, loaded.res, loaded.deps)
.map_err(StoreErrorOr::StoreError)
}
}
}
pub fn get_proxied<T, P>(
&mut self,
key: &K,
proxy: P,
ctx: &mut C,
) -> Result<Res<T>, StoreError<K>>
where T: Load<C, K>,
P: FnOnce() -> T {
self
.get(key, ctx)
.or_else(|_| self.inject::<T, ()>(key.clone().into(), proxy(), Vec::new()))
}
pub fn get_proxied_by<T, M, P>(
&mut self,
key: &K,
proxy: P,
ctx: &mut C,
method: M,
) -> Result<Res<T>, StoreError<K>>
where T: Load<C, K, M>,
P: FnOnce() -> T {
self
.get_by(key, ctx, method)
.or_else(|_| self.inject::<T, M>(key.clone().into(), proxy(), Vec::new()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum StoreError<K> {
RootDoesNotExist(PathBuf),
AlreadyRegisteredKey(K),
}
impl<K> Display for StoreError<K> where K: Display {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
StoreError::RootDoesNotExist(ref path) => write!(f, "root {} doesn’t exist", path.display()),
StoreError::AlreadyRegisteredKey(ref dk) => write!(f, "already registered key: {}", dk),
}
}
}
pub enum StoreErrorOr<T, C, K, M = ()> where T: Load<C, K, M>, K: Key {
StoreError(StoreError<K>),
ResError(T::Error),
}
impl<T, C, K, M> Clone for StoreErrorOr<T, C, K, M>
where T: Load<C, K, M>,
T::Error: Clone,
K: Key {
fn clone(&self) -> Self {
match *self {
StoreErrorOr::StoreError(ref e) => StoreErrorOr::StoreError(e.clone()),
StoreErrorOr::ResError(ref e) => StoreErrorOr::ResError(e.clone()),
}
}
}
impl<T, C, K, M> Eq for StoreErrorOr<T, C, K, M>
where T: Load<C, K, M>,
T::Error: Eq,
K: Key {
}
impl<T, C, K, M> PartialEq for StoreErrorOr<T, C, K, M>
where T: Load<C, K, M>,
T::Error: PartialEq,
K: Key {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&StoreErrorOr::StoreError(ref a), &StoreErrorOr::StoreError(ref b)) => a == b,
(&StoreErrorOr::ResError(ref a), &StoreErrorOr::ResError(ref b)) => a == b,
_ => false,
}
}
}
impl<T, C, K, M> fmt::Debug for StoreErrorOr<T, C, K, M>
where T: Load<C, K, M>,
T::Error: fmt::Debug,
K: Key + fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
StoreErrorOr::StoreError(ref e) => f.debug_tuple("StoreError").field(e).finish(),
StoreErrorOr::ResError(ref e) => f.debug_tuple("ResError").field(e).finish(),
}
}
}
impl<T, C, K, M> Display for StoreErrorOr<T, C, K, M>
where T: Load<C, K, M>,
T::Error: fmt::Debug,
K: Key + Display {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
StoreErrorOr::StoreError(ref e) => e.fmt(f),
StoreErrorOr::ResError(ref e) => e.fmt(f),
}
}
}
struct Synchronizer<C, K> {
dirties: HashSet<K>,
#[allow(dead_code)]
watcher: RecommendedWatcher,
watcher_rx: Receiver<DebouncedEvent>,
discovery: Discovery<C, K>
}
impl<C, K> Synchronizer<C, K> where K: Key {
fn new(
watcher: RecommendedWatcher,
watcher_rx: Receiver<DebouncedEvent>,
discovery: Discovery<C, K>
) -> Self {
Synchronizer {
dirties: HashSet::new(),
watcher,
watcher_rx,
discovery
}
}
fn dequeue_fs_events(&mut self, storage: &mut Storage<C, K>, ctx: &mut C) where K: for<'a> From<&'a Path> {
for event in self.watcher_rx.try_iter() {
match event {
DebouncedEvent::Write(ref path) | DebouncedEvent::Create(ref path) => {
let key = path.as_path().into();
if storage.metadata.contains_key(&key) {
self.dirties.insert(key);
} else {
self.discovery.discover(path, storage, ctx);
}
}
_ => (),
}
}
}
fn reload_dirties(&mut self, storage: &mut Storage<C, K>, ctx: &mut C) {
self.dirties.retain(|dep_key| {
if let Some(metadata) = storage.metadata.remove(&dep_key) {
if (metadata.on_reload)(storage, ctx).is_ok() {
if let Some(deps) = storage.deps.get(&dep_key).cloned() {
for dep in deps {
if let Some(obs_metadata) = storage.metadata.remove(&dep) {
let _ = (obs_metadata.on_reload)(storage, ctx);
storage.metadata.insert(dep, obs_metadata);
}
}
}
}
storage.metadata.insert(dep_key.clone(), metadata);
}
false
});
}
fn sync(&mut self, storage: &mut Storage<C, K>, ctx: &mut C) where K: for<'a> From<&'a Path> {
self.dequeue_fs_events(storage, ctx);
self.reload_dirties(storage, ctx);
}
}
pub struct Store<C, K> {
storage: Storage<C, K>,
synchronizer: Synchronizer<C, K>,
}
impl<C, K> Store<C, K> where K: Key {
pub fn new(opt: StoreOpt<C, K>) -> Result<Self, StoreError<K>> {
let root = &opt.root;
let canon_root = root
.canonicalize()
.map_err(|_| StoreError::RootDoesNotExist(root.to_owned()))?;
let (wsx, wrx) = channel();
let mut watcher = notify::watcher(wsx, opt.debounce_duration).unwrap();
let _ = watcher.watch(&canon_root, RecursiveMode::Recursive);
let storage = Storage::new(canon_root);
let synchronizer = Synchronizer::new(watcher, wrx, opt.discovery);
let store = Store {
storage,
synchronizer,
};
Ok(store)
}
pub fn sync(&mut self, ctx: &mut C) where K: for<'a> From<&'a Path> {
self.synchronizer.sync(&mut self.storage, ctx);
}
}
impl<C, K> Deref for Store<C, K> {
type Target = Storage<C, K>;
fn deref(&self) -> &Self::Target {
&self.storage
}
}
impl<C, K> DerefMut for Store<C, K> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.storage
}
}
pub struct StoreOpt<C, K> {
root: PathBuf,
debounce_duration: Duration,
discovery: Discovery<C, K>
}
impl<C, K> Default for StoreOpt<C, K> {
fn default() -> Self {
StoreOpt {
root: PathBuf::from("."),
debounce_duration: Duration::from_millis(50),
discovery: Discovery::default()
}
}
}
impl<C, K> StoreOpt<C, K> {
#[inline]
pub fn set_debounce_duration(self, duration: Duration) -> Self {
StoreOpt {
debounce_duration: duration,
..self
}
}
#[inline]
pub fn debounce_duration(&self) -> Duration {
self.debounce_duration
}
#[inline]
pub fn set_root<P>(self, root: P) -> Self
where P: AsRef<Path> {
StoreOpt {
root: root.as_ref().to_owned(),
..self
}
}
#[inline]
pub fn root(&self) -> &Path {
&self.root
}
#[inline]
pub fn set_discovery(self, discovery: Discovery<C, K>) -> Self {
StoreOpt {
discovery,
..self
}
}
#[inline]
pub fn discovery(&self) -> &Discovery<C, K> {
&self.discovery
}
}
pub struct Discovery<C, K> {
closure: Box<dyn FnMut(&Path, &mut Storage<C, K>, &mut C)>,
}
impl<C, K> Discovery<C, K> {
pub fn new<F>(f: F) -> Self where F: 'static + FnMut(&Path, &mut Storage<C, K>, &mut C) {
Discovery {
closure: Box::new(f)
}
}
fn discover(&mut self, path: &Path, storage: &mut Storage<C, K>, ctx: &mut C) {
(self.closure)(path, storage, ctx)
}
}
impl<C, K> Default for Discovery<C, K> {
fn default() -> Self {
Discovery::new(|_, _, _| {})
}
}