2018-02-25 06:58:20 -05:00
|
|
|
use std;
|
2018-03-15 06:54:18 -04:00
|
|
|
use discard::Discard;
|
2018-02-25 06:58:20 -05:00
|
|
|
|
|
|
|
|
|
|
|
// TODO replace this with FnOnce later
|
2018-03-15 06:54:18 -04:00
|
|
|
trait IInsertCallback {
|
2019-06-11 09:29:46 -04:00
|
|
|
fn call(self: Box<Self>, callbacks: &mut Callbacks);
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
impl<F: FnOnce(&mut Callbacks)> IInsertCallback for F {
|
2018-02-25 06:58:20 -05:00
|
|
|
#[inline]
|
2018-03-15 06:54:18 -04:00
|
|
|
fn call(self: Box<Self>, callbacks: &mut Callbacks) {
|
|
|
|
self(callbacks);
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
// TODO a bit gross
|
|
|
|
trait IRemove {
|
|
|
|
fn remove(self: Box<Self>);
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
impl<A: Discard> IRemove for A {
|
2018-02-25 06:58:20 -05:00
|
|
|
#[inline]
|
2018-03-15 06:54:18 -04:00
|
|
|
fn remove(self: Box<Self>) {
|
|
|
|
self.discard();
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-15 18:49:29 -04:00
|
|
|
pub(crate) struct InsertCallback(Box<dyn IInsertCallback>);
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
// TODO is there a more efficient way of doing this ?
|
2019-06-15 18:49:29 -04:00
|
|
|
pub(crate) struct RemoveCallback(Box<dyn IRemove>);
|
2018-02-25 06:58:20 -05:00
|
|
|
|
|
|
|
impl std::fmt::Debug for InsertCallback {
|
|
|
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
write!(formatter, "InsertCallback")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for RemoveCallback {
|
|
|
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
write!(formatter, "RemoveCallback")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) struct Callbacks {
|
|
|
|
pub(crate) after_insert: Vec<InsertCallback>,
|
|
|
|
pub(crate) after_remove: Vec<RemoveCallback>,
|
2018-03-15 06:54:18 -04:00
|
|
|
trigger_remove: bool,
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Callbacks {
|
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn new() -> Self {
|
2018-02-25 06:58:20 -05:00
|
|
|
Self {
|
|
|
|
after_insert: vec![],
|
|
|
|
after_remove: vec![],
|
|
|
|
trigger_remove: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn after_insert<A: FnOnce(&mut Callbacks) + 'static>(&mut self, callback: A) {
|
2018-02-25 06:58:20 -05:00
|
|
|
self.after_insert.push(InsertCallback(Box::new(callback)));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn after_remove<A: Discard + 'static>(&mut self, value: A) {
|
2018-03-15 06:54:18 -04:00
|
|
|
self.after_remove.push(RemoveCallback(Box::new(value)));
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO runtime checks to make sure this isn't called multiple times ?
|
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn trigger_after_insert(&mut self) {
|
2019-06-15 18:49:29 -04:00
|
|
|
if !self.after_insert.is_empty() {
|
|
|
|
let mut callbacks = Callbacks::new();
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2019-06-15 18:49:29 -04:00
|
|
|
// TODO verify that this is correct
|
|
|
|
// TODO is this the most efficient way to accomplish this ?
|
|
|
|
std::mem::swap(&mut callbacks.after_remove, &mut self.after_remove);
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2019-06-15 18:49:29 -04:00
|
|
|
for f in self.after_insert.drain(..) {
|
|
|
|
f.0.call(&mut callbacks);
|
|
|
|
}
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2019-06-15 18:49:29 -04:00
|
|
|
// TODO verify that this is correct
|
|
|
|
self.after_insert = vec![];
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2019-06-15 18:49:29 -04:00
|
|
|
// TODO figure out a better way of verifying this
|
|
|
|
assert_eq!(callbacks.after_insert.len(), 0);
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2019-06-15 18:49:29 -04:00
|
|
|
// TODO verify that this is correct
|
|
|
|
// TODO what if `callbacks` is leaked ?
|
|
|
|
std::mem::swap(&mut callbacks.after_remove, &mut self.after_remove);
|
|
|
|
}
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn trigger_after_remove(&mut self) {
|
|
|
|
for f in self.after_remove.drain(..) {
|
2018-03-15 06:54:18 -04:00
|
|
|
f.0.remove();
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn leak(&mut self) {
|
2018-03-15 06:54:18 -04:00
|
|
|
self.trigger_remove = false;
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
|
|
|
|
// TODO use DiscardOnDrop instead
|
2018-02-25 06:58:20 -05:00
|
|
|
impl Drop for Callbacks {
|
|
|
|
#[inline]
|
|
|
|
fn drop(&mut self) {
|
|
|
|
if self.trigger_remove {
|
|
|
|
self.trigger_after_remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-15 06:54:18 -04:00
|
|
|
|
|
|
|
impl Discard for Callbacks {
|
|
|
|
#[inline]
|
|
|
|
fn discard(mut self) {
|
|
|
|
self.trigger_after_remove();
|
|
|
|
}
|
|
|
|
}
|