1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
use std::error::Error as StdError;
use libuv_sys2::{self as ffi, uv_async_t};
use crate::{Error, Handle};
type Callback = Box<dyn FnMut() -> Result<(), Box<dyn StdError>> + 'static>;
/// Binding to libuv's [Async handle][1] used to trigger the execution of a
/// callback in the Neovim thread.
///
/// [1]: http://docs.libuv.org/en/v1.x/async.html
#[derive(Clone)]
pub struct AsyncHandle {
handle: Handle<uv_async_t, Callback>,
}
unsafe impl Send for AsyncHandle {}
unsafe impl Sync for AsyncHandle {}
impl AsyncHandle {
/// Registers a new callback on the Neovim event loop, returning an
/// [`AsyncHandle`] which can be used to execute the callback from any
/// thread. The callback will always be executed on the main thread.
pub fn new<E, Cb>(mut callback: Cb) -> Result<Self, Error>
where
E: StdError + 'static,
Cb: FnMut() -> Result<(), E> + 'static,
{
let mut handle = Handle::new(|uv_loop, handle| unsafe {
ffi::uv_async_init(
uv_loop,
handle.as_mut_ptr(),
Some(async_cb as _),
)
})?;
let callback: Callback = Box::new(move || {
// Type erase the callback by boxing its error.
callback().map_err(|err| Box::new(err) as Box<dyn StdError>)
});
unsafe { handle.set_data(callback) };
Ok(Self { handle })
}
/// Wakes up the Neovim event loop and executes the callback associated to
/// this handle. It is safe to call this function from any thread. The
/// callback will be called on the main thread.
///
/// NOTE: [libuv] will coalesce calls to [`AsyncHandle::send`], that is,
/// not every call to it will yield an execution of the callback. For
/// example: if [`AsyncHandle::send`] is called 5 times in a row before the
/// callback is called, the callback will only be called once. If
/// [`AsyncHandle::send`] is called again after the callback was called, it
/// will be called again.
///
/// [libuv]: https://libuv.org/
pub fn send(&self) -> Result<(), Error> {
let retv =
unsafe { ffi::uv_async_send(self.handle.as_ptr() as *mut _) };
if retv < 0 {
return Err(Error::AsyncTrigger);
}
Ok(())
}
}
extern "C" fn async_cb(ptr: *mut uv_async_t) {
let handle: Handle<_, Callback> = unsafe { Handle::from_raw(ptr) };
let callback = unsafe { handle.get_data() };
if !callback.is_null() {
let callback = unsafe { &mut *callback };
if let Err(_err) = callback() {
// TODO: what now?
}
}
}