Skip to content

Commit 49fa1ef

Browse files
committed
Finish documentation of the async module
1 parent fc39b5b commit 49fa1ef

File tree

1 file changed

+39
-13
lines changed

1 file changed

+39
-13
lines changed

src/async.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,49 @@
11
//! # Async Actors
22
//!
3-
//! `tonari-actor` lets you freely combine sync (blocking) and `async` actors within one system.
3+
//! `tonari-actor` lets you freely combine sync (blocking) and async actors within one system.
44
//!
55
//! While sync actors implement the [`Actor`](crate::Actor) trait and are spawned using the
66
//! [`System::spawn()`], [`System::prepare()`] and [`System::prepare_fn()`] family of methods,
7-
//! `async` actors implement [`AsyncActor`] and are spawned using [`System::spawn_async()`],
7+
//! async actors implement [`AsyncActor`] and are spawned using [`System::spawn_async()`],
88
//! [`System::prepare_async()`] and [`System::prepare_async_fn()`].
99
//!
10-
//! Sync and `async` actors share the same [`Addr`] and [`Recipient`](crate::Recipient) types.
10+
//! Sync and async actors share the same [`Addr`] and [`Recipient`](crate::Recipient) types.
1111
//!
12-
//! `async` actors share the same paradigm as sync actors: each one gets its own OS-level thread.
13-
//! More specifically a single-threaded async runtime is spawned for every `async` actor.
12+
//! Async actors share the same paradigm as sync actors: each one gets its own OS-level thread.
13+
//! More specifically a single-threaded async runtime is spawned for every async actor.
1414
//!
15-
//! `tonari-actor` currently uses the [`tokio`] ecosystem, more specifically its [`LocalRuntime`][^tokio].
15+
//! `tonari-actor` currently uses the [`tokio`][^tokio] ecosystem, more specifically its
16+
//! [`LocalRuntime`]. It allows spawning futures that are _not_ [`Send`], which means you
17+
//! can use [`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html) and
18+
//! [`RefCell`](https://doc.rust-lang.org/std/cell/struct.RefCell.html) instead of
19+
//! [`Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) and mutexes in your futures.
20+
//! It also allows the [`AsyncActor`] trait (and the implementors) to use the `async fn` syntax.
1621
//!
17-
//! TODO explain tokio feature flags and that downstreams may need to enable more.
22+
//! Tokio's [`LocalRuntime`] is currently [gated behind the `tokio_unstable` _Rust
23+
//! flag_](https://docs.rs/tokio/latest/tokio/index.html#unstable-features). Note that this isn't
24+
//! a cargo feature flag (that would go to `Cargo.toml`); it goes to `.cargo/config.toml` or
25+
//! `RUSTFLAGS`, which override the former. It needs to be specified in our leaf project/workspace
26+
//! (it doesn't propagate from `tonari-actor`). Stabilization of [`LocalRuntime`] is tracked in
27+
//! [tokio-rs/tokio#7558](https://github.com/tokio-rs/tokio/issues/7558).
1828
//!
19-
//! TODO lacking feature: block on
29+
//! With [`AsyncActor::handle()`] being an `async fn`, you gain an access to the wide async library
30+
//! ecosystem (currently those compatible with [`tokio`]), and you can employ concurrency (still
31+
//! within the single thread) when processing each message by using one of future combinators.
2032
//!
21-
//! [^tokio]: TODO explain that any runtime is sufficient (no dependency on tokio-specific features)
22-
//! we only need to spawn _some_ runtime in the actor loop. tokio was just a pragmatic choice.
23-
//! we could add support for alternative ones, even runtime-configurable.
33+
//! But the incoming messages are still processed sequentially (the actor framework won't start
34+
//! multiple concurrent [`AsyncActor::handle()`] futures of a given actor). If you want to process
35+
//! the _messages_ concurrently, spawn an async task and return from the `handle()` method.
36+
//!
37+
//! Async tasks can be spawned using [`tokio::task::spawn_local()`], or [`tokio::spawn()`] if the
38+
//! [`Send`] bound of the latter doesn't limit you.
39+
//!
40+
//! Note that an async equivalent of [`crate::SpawnBuilderWithAddress::run_and_block()`] is not
41+
//! currently implemented (contributions welcome).
42+
//!
43+
//! [^tokio]: on logical level, `tonari-actor` isn't tied to any specific async runtime (it doesn't
44+
//! do any runtime-specific operations like I/O or timers), it just needs to spawn _some_ async
45+
//! runtime in the actor loop. Tokio was just a pragmatic choice that many crates in the
46+
//! ecosystem use. We could add support for alternative ones, even runtime-configurable.
2447
2548
use crate::{
2649
ActorError, Addr, BareContext, Capacity, Control, Priority, RegistryEntry, System,
@@ -32,8 +55,8 @@ use std::{any::type_name, fmt, future, thread};
3255
use tokio::runtime::LocalRuntime;
3356

3457
/// The actor trait - async variant.
35-
// Ad. the #[allow]: using `async` fn in a trait doesn't allow us to specify `Send` (or other)
36-
// bounds, but we don't really need any bounds, because TODO - we use single-threaded runtime
58+
// Ad. the #[allow]: using `async fn` in a trait doesn't allow us to specify `Send` (or other)
59+
// bounds, but we don't really need any bounds, because we use [`LocalRuntime`].
3760
#[allow(async_fn_in_trait)]
3861
pub trait AsyncActor {
3962
/// The expected type of a message to be received.
@@ -270,6 +293,9 @@ impl System {
270293
// 1. If multiple futures in the combinator are ready, it should return the one with
271294
// higher priority (control > high > normal);
272295
// 2. Otherwise it would wait for the first message to be ready and return that.
296+
//
297+
// Tokio's `select` macro documentation contains nice survey of ecosystem alternatives:
298+
// https://docs.rs/tokio/latest/tokio/macro.select.html#racing-futures
273299
let received = select_biased!(
274300
control = control_stream.next() => {
275301
Received::Control(control.expect("We keep control_tx alive through addr."))

0 commit comments

Comments
 (0)