use std::collections::HashMap;
use std::sync::{Arc, Mutex};
pub struct ParoApp<State> {
callbacks: HashMap<String, (u128, Arc<Mutex<dyn FnMut(&mut State, String) + Send + 'static>>)>,
iteration: u128,
pub state: State,
}
impl <State> ParoApp<State> {
pub fn new(state: State) -> ParoApp<State> {
ParoApp::<State> {
callbacks: HashMap::new(),
iteration: 0,
state: state,
}
}
pub fn insert(&mut self, id: String, callback: Arc<Mutex<dyn FnMut(&mut State, String) + Send + 'static>>) -> () {
if self.callbacks.contains_key(&id) {
panic!("[paro] callback ids must be unique, '{}' is not", &id);
}
self.callbacks.insert(id, (self.iteration, callback));
}
pub fn iterate(&mut self) -> () {
self.iteration += 1;
let keys_to_drop: Vec<String> = {self.callbacks.iter()
.filter(|(_key, (callback_iteration, _callback))| self.iteration - callback_iteration > 100)
.map(|(key, _value)| key.to_owned())
.collect()};
for key in &keys_to_drop {
self.callbacks.remove(key);
}
println!("paro iterate dropped {} old callbacks and now contains {}", keys_to_drop.len(), self.callbacks.len());
}
pub fn call(&mut self, id: String) -> Result<(), String> {
let split = id.split_once("__PARO__")
.expect("expected __PARO__ as part of the message");
let id = split.0;
let value = split.1.to_owned();
match self.callbacks.get(id) {
Some((_, callback)) => {
println!("before lock");
let mut locked = { callback.lock().unwrap() };
println!("after lock");
let result = Ok(locked(&mut self.state, value));
println!("after call");
return result;
},
None => Err(format!("[paro] callback '{}' not found", &id))
}
}
}
#[macro_export]
macro_rules! event {
($paroApp:expr, $closure:tt)=>{
{
let callback_id = uuid::Uuid::new_v4().to_string();
{
$paroApp.lock().unwrap().insert(
callback_id.clone(),
Arc::new(Mutex::new(($closure)))
);
}
let javascript_call = format!{"window.__PARO__.emitEvent(\"{}\", event)", &callback_id};
javascript_call
}
}
}