1//! Calloop, a Callback-based Event Loop
2//!
3//! This crate provides an [`EventLoop`] type, which is a small abstraction
4//! over a polling system. The main difference between this crate
5//! and other traditional rust event loops is that it is based on callbacks:
6//! you can register several event sources, each being associated with a callback
7//! closure that will be invoked whenever the associated event source generates
8//! events.
9//!
10//! The main target use of this event loop is thus for apps that expect to spend
11//! most of their time waiting for events and wishes to do so in a cheap and convenient
12//! way. It is not meant for large scale high performance IO.
13//!
14//! ## How to use it
15//!
16//! Below is a quick usage example of calloop. For a more in-depth tutorial, see
17//! the [calloop book](https://smithay.github.io/calloop).
18//!
19//! For simple uses, you can just add event sources with callbacks to the event
20//! loop. For example, here's a runnable program that exits after five seconds:
21//!
22//! ```no_run
23//! use calloop::{timer::{Timer, TimeoutAction}, EventLoop, LoopSignal};
24//!
25//! fn main() {
26//! // Create the event loop. The loop is parameterised by the kind of shared
27//! // data you want the callbacks to use. In this case, we want to be able to
28//! // stop the loop when the timer fires, so we provide the loop with a
29//! // LoopSignal, which has the ability to stop the loop from within events. We
30//! // just annotate the type here; the actual data is provided later in the
31//! // run() call.
32//! let mut event_loop: EventLoop<LoopSignal> =
33//! EventLoop::try_new().expect("Failed to initialize the event loop!");
34//!
35//! // Retrieve a handle. It is used to insert new sources into the event loop
36//! // It can be cloned, allowing you to insert sources from within source
37//! // callbacks.
38//! let handle = event_loop.handle();
39//!
40//! // Create our event source, a timer, that will expire in 2 seconds
41//! let source = Timer::from_duration(std::time::Duration::from_secs(2));
42//!
43//! // Inserting an event source takes this general form. It can also be done
44//! // from within the callback of another event source.
45//! handle
46//! .insert_source(
47//! // a type which implements the EventSource trait
48//! source,
49//! // a callback that is invoked whenever this source generates an event
50//! |event, _metadata, shared_data| {
51//! // This callback is given 3 values:
52//! // - the event generated by the source (in our case, timer events are the Instant
53//! // representing the deadline for which it has fired)
54//! // - &mut access to some metadata, specific to the event source (in our case, a
55//! // timer handle)
56//! // - &mut access to the global shared data that was passed to EventLoop::run or
57//! // EventLoop::dispatch (in our case, a LoopSignal object to stop the loop)
58//! //
59//! // The return type is just () because nothing uses it. Some
60//! // sources will expect a Result of some kind instead.
61//! println!("Timeout for {:?} expired!", event);
62//! // notify the event loop to stop running using the signal in the shared data
63//! // (see below)
64//! shared_data.stop();
65//! // The timer event source requires us to return a TimeoutAction to
66//! // specify if the timer should be rescheduled. In our case we just drop it.
67//! TimeoutAction::Drop
68//! },
69//! )
70//! .expect("Failed to insert event source!");
71//!
72//! // Create the shared data for our loop.
73//! let mut shared_data = event_loop.get_signal();
74//!
75//! // Actually run the event loop. This will dispatch received events to their
76//! // callbacks, waiting at most 20ms for new events between each invocation of
77//! // the provided callback (pass None for the timeout argument if you want to
78//! // wait indefinitely between events).
79//! //
80//! // This is where we pass the *value* of the shared data, as a mutable
81//! // reference that will be forwarded to all your callbacks, allowing them to
82//! // share some state
83//! event_loop
84//! .run(
85//! std::time::Duration::from_millis(20),
86//! &mut shared_data,
87//! |_shared_data| {
88//! // Finally, this is where you can insert the processing you need
89//! // to do do between each waiting event eg. drawing logic if
90//! // you're doing a GUI app.
91//! },
92//! )
93//! .expect("Error during event loop!");
94//! }
95//! ```
96//!
97//! ## Event source types
98//!
99//! The event loop is backed by an OS provided polling selector (epoll on Linux).
100//!
101//! This crate also provide some adapters for common event sources such as:
102//!
103//! - [MPSC channels](channel)
104//! - [Timers](timer)
105//! - [unix signals](signals) on Linux
106//!
107//! As well as generic objects backed by file descriptors.
108//!
109//! It is also possible to insert "idle" callbacks. These callbacks represent computations that
110//! need to be done at some point, but are not as urgent as processing the events. These callbacks
111//! are stored and then executed during [`EventLoop::dispatch`](EventLoop#method.dispatch), once all
112//! events from the sources have been processed.
113//!
114//! ## Async/Await compatibility
115//!
116//! `calloop` can be used with futures, both as an executor and for monitoring Async IO.
117//!
118//! Activating the `executor` cargo feature will add the [`futures`] module, which provides
119//! a future executor that can be inserted into an [`EventLoop`] as yet another [`EventSource`].
120//!
121//! IO objects can be made Async-aware via the [`LoopHandle::adapt_io`](LoopHandle#method.adapt_io)
122//! method. Waking up the futures using these objects is handled by the associated [`EventLoop`]
123//! directly.
124//!
125//! ## Custom event sources
126//!
127//! You can create custom event sources can will be inserted in the event loop by
128//! implementing the [`EventSource`] trait. This can be done either directly from the file
129//! descriptors of your source of interest, or by wrapping an other event source and further
130//! processing its events. An [`EventSource`] can register more than one file descriptor and
131//! aggregate them.
132//!
133//! ## Platforms support
134//!
135//! Currently, calloop is tested on Linux, FreeBSD and macOS.
136//!
137//! The following platforms are also enabled at compile time but not tested: Android, NetBSD,
138//! OpenBSD, DragonFlyBSD.
139//!
140//! Those platforms *should* work based on the fact that they have the same polling mechanism as
141//! tested platforms, but some subtle bugs might still occur.
142
143#![warn(missing_docs, missing_debug_implementations)]
144#![allow(clippy::needless_doctest_main)]
145#![cfg_attr(docsrs, feature(doc_cfg))]
146#![cfg_attr(feature = "nightly_coverage", feature(coverage_attribute))]
147
148mod sys;
149
150pub use sys::{Interest, Mode, Poll, Readiness, Token, TokenFactory};
151
152pub use self::loop_logic::{EventLoop, LoopHandle, LoopSignal, RegistrationToken};
153pub use self::sources::*;
154
155pub mod error;
156pub use error::{Error, InsertError, Result};
157
158pub mod io;
159mod list;
160mod loop_logic;
161mod macros;
162mod sources;
163mod token;
164