wext 0.7.2

web-sys extension traits, convenience functions and types
Documentation
use std::ops::DerefMut as _;

pub trait RcRefCellCallbackExt<T> {
    fn strong_await_queue<F, C>(&self, future: F, callback: C)
    where
        F: std::future::Future + 'static,
        C: FnMut(&mut T, F::Output) + 'static;
    fn strong_queue<C>(&self, callback: C)
    where
        C: FnMut(&mut T) + 'static;
}

impl<T: 'static> RcRefCellCallbackExt<T> for std::rc::Rc<std::cell::RefCell<T>> {
    fn strong_await_queue<F, C>(&self, future: F, mut callback: C)
    where
        F: std::future::Future + 'static,
        C: FnMut(&mut T, F::Output) + 'static,
    {
        let strong = self.clone();
        wasm_bindgen_futures::spawn_local(async move {
            let output = future.await;
            rc_ref_cell_try_run(&strong, |r| callback(r, output))
        })
    }

    fn strong_queue<C>(&self, mut callback: C)
    where
        C: FnMut(&mut T) + 'static,
    {
        self.strong_await_queue(async {}, move |r, ()| callback(r))
    }
}

pub trait WeakRcRefCellCallbackExt<T> {
    fn await_queue<F, C>(&self, future: F, callback: C)
    where
        F: std::future::Future + 'static,
        C: FnMut(&mut T, F::Output) + 'static;
    fn queue<C>(&self, callback: C)
    where
        C: FnMut(&mut T) + 'static;
    fn callback<C>(&self, callback: C) -> Box<dyn Fn()>
    where
        C: FnMut(&mut T) + 'static;
}

impl<T: 'static> WeakRcRefCellCallbackExt<T> for std::rc::Rc<std::cell::RefCell<T>> {
    fn await_queue<F, C>(&self, future: F, callback: C)
    where
        F: std::future::Future + 'static,
        C: FnMut(&mut T, F::Output) + 'static,
    {
        std::rc::Rc::downgrade(self).await_queue(future, callback)
    }

    fn queue<C>(&self, callback: C)
    where
        C: FnMut(&mut T) + 'static,
    {
        std::rc::Rc::downgrade(self).queue(callback)
    }

    fn callback<C>(&self, callback: C) -> Box<dyn Fn()>
    where
        C: FnMut(&mut T) + 'static,
    {
        std::rc::Rc::downgrade(self).callback(callback)
    }
}

impl<T: 'static> WeakRcRefCellCallbackExt<T> for std::rc::Weak<std::cell::RefCell<T>> {
    fn await_queue<F, C>(&self, future: F, mut callback: C)
    where
        F: std::future::Future + 'static,
        C: FnMut(&mut T, F::Output) + 'static,
    {
        let weak = self.clone();
        wasm_bindgen_futures::spawn_local(async move {
            let output = future.await;
            weak_ref_cell_try_run(&weak, move |r| callback(r, output))
        })
    }

    fn queue<C>(&self, mut callback: C)
    where
        C: FnMut(&mut T) + 'static,
    {
        self.await_queue(async {}, move |r, ()| callback(r))
    }

    fn callback<C>(&self, callback: C) -> Box<dyn Fn()>
    where
        C: FnMut(&mut T) + 'static,
    {
        let weak = self.clone();
        let callback = std::rc::Rc::new(std::cell::RefCell::new(callback));
        Box::new(move || {
            let callback = callback.clone();
            weak.queue(move |this| try_run_ref_cell_fn(this, &callback))
        })
    }
}

fn try_run_ref_cell_fn<T, F: FnMut(&mut T) + 'static>(this: &mut T, f: &std::rc::Rc<std::cell::RefCell<F>>) {
    match f.try_borrow_mut() {
        Ok(mut guard) => guard(this),
        Err(_) => log::warn!("already borrowed callback triggered (maybe due to a leak or panic)"),
    }
}

fn weak_ref_cell_try_run<T>(weak_ref_cell: &std::rc::Weak<std::cell::RefCell<T>>, callback: impl FnOnce(&mut T)) {
    match weak_ref_cell.upgrade() {
        None => log::warn!("callback triggered with dropped receiver"),
        Some(strong) => rc_ref_cell_try_run(&strong, callback),
    }
}
fn rc_ref_cell_try_run<T>(rc_ref_cell: &std::rc::Rc<std::cell::RefCell<T>>, callback: impl FnOnce(&mut T)) {
    match rc_ref_cell.try_borrow_mut() {
        Ok(mut guard) => callback(guard.deref_mut()),
        Err(_) => log::warn!("callback triggered with already borrowed receiver (maybe due to a leak or panic)"),
    }
}