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}