Remove slab from scheduler

This commit is contained in:
Denis Kolodin 2018-05-12 22:24:21 +03:00
parent 51141e9202
commit c5ca223d27
4 changed files with 24 additions and 86 deletions

View File

@ -18,7 +18,6 @@ http = "0.1"
serde = "1"
serde_json = "1"
stdweb = "0.4"
slab = "0.4"
toml = { version = "0.4", optional = true }
serde_yaml = { version = "0.7", optional = true }
rmp-serde = { version = "0.13.7", optional = true }

View File

@ -12,7 +12,7 @@ use stdweb::web::{Element, EventListenerHandle, INode, Node};
use stdweb::web::html_element::SelectElement;
use virtual_dom::{Listener, VDiff, VNode};
use callback::Callback;
use scheduler::{Scheduler, RunnableIndex, Runnable, WillDestroy};
use scheduler::{Scheduler, Runnable, WillDestroy, Shared, BoxedRunnable};
/// This type indicates that component should be rendered again.
pub type ShouldRender = bool;
@ -114,15 +114,15 @@ impl<'a, CTX: 'static, COMP: Component<CTX>> Env<'a, CTX, COMP> {
/// Holds a reference to a scope, could put a message into the queue
/// of the scope and activate processing (try borrow and call routine).
pub struct Activator<CTX, COMP: Component<CTX>> {
index: Rc<RefCell<Option<RunnableIndex>>>,
runnable: Shared<Option<Shared<BoxedRunnable<CTX>>>>,
scheduler: Scheduler<CTX>,
queue: Rc<RefCell<VecDeque<ComponentUpdate<CTX, COMP>>>>,
queue: Shared<VecDeque<ComponentUpdate<CTX, COMP>>>,
}
impl<CTX, COMP: Component<CTX>> Clone for Activator<CTX, COMP> {
fn clone(&self) -> Self {
Activator {
index: self.index.clone(),
runnable: self.runnable.clone(),
scheduler: self.scheduler.clone(),
queue: self.queue.clone(),
}
@ -136,10 +136,10 @@ impl<CTX, COMP: Component<CTX>> Activator<CTX, COMP> {
self.queue.try_borrow_mut()
.expect("internal message routing accident")
.push_back(update);
let idx = self.index.borrow().as_ref()
let runnable = self.runnable.borrow().as_ref()
.cloned()
.expect("index was not set");
self.scheduler.put_and_try_run(idx);
.expect("runnable was not set");
self.scheduler.put_and_try_run(runnable);
}
/// Send message to a component.
@ -169,9 +169,9 @@ where
COMP: Component<CTX> + Renderable<CTX, COMP>,
{
pub(crate) fn new(scheduler: Scheduler<CTX>) -> Self {
let index = Rc::new(RefCell::new(None));
let runnable = Rc::new(RefCell::new(None));
let queue = Rc::new(RefCell::new(VecDeque::new()));
let env = Activator { index, scheduler, queue };
let env = Activator { runnable, scheduler, queue };
Scope { env }
}
@ -198,8 +198,9 @@ where
init_props,
};
let mut activator = self.env.clone();
let idx = activator.scheduler.register(runnable);
*activator.index.borrow_mut() = Some(idx);
let runnable = Box::new(runnable) as BoxedRunnable<CTX>;
let runnable = Rc::new(RefCell::new(runnable));
*activator.runnable.borrow_mut() = Some(runnable);
activator.send(ComponentUpdate::Create);
activator
}

View File

@ -57,7 +57,6 @@ extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate stdweb;
extern crate slab;
#[cfg(feature = "toml")]
extern crate toml;
#[cfg(feature = "yaml")]

View File

@ -3,10 +3,6 @@
use std::collections::VecDeque;
use std::rc::Rc;
use std::cell::RefCell;
use slab::Slab;
/// Id of a runnable instance.
pub(crate) type RunnableIndex = usize;
/// The flag that means the routine should be destroyed.
pub(crate) type WillDestroy = bool;
@ -20,48 +16,19 @@ pub(crate) trait Runnable<CTX> {
fn run<'a>(&mut self, context: &'a mut CTX) -> WillDestroy;
}
/// The `Pool` which keep a sequence of runnables to start next.
struct Pool<CTX> {
slab: Slab<Rc<RefCell<BoxedRunnable<CTX>>>>,
sequence: VecDeque<RunnableIndex>,
}
impl<CTX> Pool<CTX> {
/// Put a runnable and return a unique id.
fn register(&mut self, runnable: BoxedRunnable<CTX>) -> RunnableIndex {
let runnable = Rc::new(RefCell::new(runnable));
self.slab.insert(runnable)
}
fn unregister(&mut self, index: RunnableIndex) -> BoxedRunnable<CTX> {
let runnable = self.slab.remove(index);
Rc::try_unwrap(runnable).ok()
.expect("runnable was locked")
.into_inner()
}
fn put(&mut self, index: RunnableIndex) {
self.sequence.push_back(index);
}
fn next(&mut self) -> Option<(RunnableIndex, Rc<RefCell<BoxedRunnable<CTX>>>)> {
self.sequence.pop_front().and_then(|idx| {
self.slab.get(idx).cloned().map(|runnable| (idx, runnable))
})
}
}
pub(crate) type Shared<T> = Rc<RefCell<T>>;
/// This is a global scheduler suitable to schedule and run any tasks.
pub struct Scheduler<CTX> {
context: Rc<RefCell<CTX>>,
pool: Rc<RefCell<Pool<CTX>>>,
context: Shared<CTX>,
sequence: Shared<VecDeque<Shared<BoxedRunnable<CTX>>>>,
}
impl<CTX> Clone for Scheduler<CTX> {
fn clone(&self) -> Self {
Scheduler {
context: self.context.clone(),
pool: self.pool.clone(),
sequence: self.sequence.clone(),
}
}
}
@ -69,53 +36,25 @@ impl<CTX> Clone for Scheduler<CTX> {
impl<CTX> Scheduler<CTX> {
/// Creates a new scheduler with a context.
pub fn new(context: CTX) -> Self {
let pool = Pool {
slab: Slab::new(),
sequence: VecDeque::new(),
};
let sequence = VecDeque::new();
Scheduler {
context: Rc::new(RefCell::new(context)),
pool: Rc::new(RefCell::new(pool)),
sequence: Rc::new(RefCell::new(sequence)),
}
}
pub(crate) fn register<T>(&mut self, runnable: T) -> RunnableIndex
where
T: Runnable<CTX> + 'static,
{
let runnable: BoxedRunnable<CTX> = Box::new(runnable);
self.pool.try_borrow_mut()
.expect("can't borrow slab to register a runnable")
.register(runnable)
}
pub(crate) fn put_and_try_run(&mut self, index: RunnableIndex) {
self.pool.borrow_mut().put(index);
// Context lock also means the loop is runnging
let mut unreg = Vec::new();
pub(crate) fn put_and_try_run(&mut self, runnable: Shared<BoxedRunnable<CTX>>) {
self.sequence.borrow_mut().push_back(runnable);
// Context lock also means the loop is running
if let Ok(ref mut context) = self.context.try_borrow_mut() {
loop {
let do_next = self.pool.borrow_mut().next();
if let Some((idx, routine)) = do_next {
let will_destroy = routine.borrow_mut().run(context);
if will_destroy {
// TODO Filter deque (remove items with this id)
// because they must not be called and after
// the routine removed new call won't added with this id
// even if callback still exists
unreg.push(idx);
}
let do_next = self.sequence.borrow_mut().pop_front();
if let Some(routine) = do_next {
routine.borrow_mut().run(context);
} else {
break;
}
}
}
// Remove unnecessary routines only when loop finished completely,
// because they could call each other
for idx in unreg.into_iter() {
self.pool.try_borrow_mut()
.expect("can't borrow slab to unregister a runnable")
.unregister(idx);
}
}
}