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