Skip to content

Commit

Permalink
Remove the need for the async_trait crate by leveraging the native …
Browse files Browse the repository at this point in the history
…`async fn`s support now in Rust as of v0.75

    https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html
  • Loading branch information
slawlor committed Feb 18, 2024
1 parent 9a73feb commit f06c4b2
Show file tree
Hide file tree
Showing 36 changed files with 45 additions and 158 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ Install `ractor` by adding the following to your Cargo.toml dependencies.

```toml
[dependencies]
ractor = "0.9"
ractor = "0.10"
```

The minimum supported Rust version (MSRV) of `ractor` is `1.64`
The minimum supported Rust version (MSRV) of `ractor` is `1.75`. This is to account for the stabilization of `async fn` in traits that [was recently added](https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html). If you want prior support, version 0.9 supports `async fn`s with the `async_trait` crate.

## Features

Expand All @@ -81,7 +81,7 @@ never be executed in parallel. Following the actor model leads to microservices
An example `ping-pong` actor might be the following

```rust
use ractor::{async_trait, cast, Actor, ActorProcessingErr, ActorRef};
use ractor::{cast, Actor, ActorProcessingErr, ActorRef};

/// [PingPong] is a basic actor that will print
/// ping..pong.. repeatedly until some exit
Expand Down Expand Up @@ -114,7 +114,6 @@ impl Message {
}

// the implementation of our actor's "logic"
#[async_trait]
impl Actor for PingPong {
// An actor has a message type
type Msg = Message;
Expand Down
3 changes: 1 addition & 2 deletions ractor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repository = "https://github.com/slawlor/ractor"
readme = "../README.md"
homepage = "https://github.com/slawlor/ractor"
categories = ["actor", "erlang"]
rust-version = "1.64"
rust-version = "1.75"

[features]
### Other features
Expand All @@ -23,7 +23,6 @@ default = ["tokio_runtime"]

[dependencies]
## Required dependencies
async-trait = "0.1"
dashmap = "5"
futures = "0.3"
once_cell = "1"
Expand Down
2 changes: 0 additions & 2 deletions ractor/benches/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ struct BenchActorMessage;
#[cfg(feature = "cluster")]
impl Message for BenchActorMessage {}

#[async_trait::async_trait]
impl Actor for BenchActor {
type Msg = BenchActorMessage;

Expand Down Expand Up @@ -247,7 +246,6 @@ fn process_messages(c: &mut Criterion) {
num_msgs: u64,
}

#[async_trait::async_trait]
impl Actor for MessagingActor {
type Msg = BenchActorMessage;

Expand Down
3 changes: 1 addition & 2 deletions ractor/examples/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
extern crate ractor;

use ractor::{async_trait, call_t, Actor, ActorProcessingErr, ActorRef, RpcReplyPort};
use ractor::{call_t, Actor, ActorProcessingErr, ActorRef, RpcReplyPort};

struct Counter;

Expand All @@ -31,7 +31,6 @@ enum CounterMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for CounterMessage {}

#[async_trait]
impl Actor for Counter {
type Msg = CounterMessage;

Expand Down
4 changes: 1 addition & 3 deletions ractor/examples/monte_carlo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use std::collections::HashMap;

use ractor::{async_trait, cast, Actor, ActorId, ActorProcessingErr, ActorRef};
use ractor::{cast, Actor, ActorId, ActorProcessingErr, ActorRef};
use rand::{thread_rng, Rng};

// ================== Player Actor ================== //
Expand Down Expand Up @@ -62,7 +62,6 @@ struct GameMessage(ActorRef<GameManagerMessage>);
#[cfg(feature = "cluster")]
impl ractor::Message for GameMessage {}

#[async_trait]
impl Actor for Game {
type Msg = GameMessage;

Expand Down Expand Up @@ -139,7 +138,6 @@ impl GameManagerState {
}
}

#[async_trait]
impl Actor for GameManager {
type Msg = GameManagerMessage;

Expand Down
4 changes: 1 addition & 3 deletions ractor/examples/output_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extern crate ractor;

use std::sync::Arc;

use ractor::{async_trait, Actor, ActorProcessingErr, ActorRef, OutputPort};
use ractor::{Actor, ActorProcessingErr, ActorRef, OutputPort};
use tokio::time::{timeout, Duration};

enum PublisherMessage {
Expand All @@ -31,7 +31,6 @@ impl ractor::Message for Output {}

struct Publisher;

#[async_trait]
impl Actor for Publisher {
type Msg = PublisherMessage;

Expand Down Expand Up @@ -70,7 +69,6 @@ enum SubscriberMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for SubscriberMessage {}

#[async_trait]
impl Actor for Subscriber {
type Msg = SubscriberMessage;

Expand Down
6 changes: 1 addition & 5 deletions ractor/examples/philosophers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
use std::collections::{HashMap, VecDeque};

use ractor::{
async_trait, cast, Actor, ActorId, ActorName, ActorProcessingErr, ActorRef, RpcReplyPort,
};
use ractor::{cast, Actor, ActorId, ActorName, ActorProcessingErr, ActorRef, RpcReplyPort};
use tokio::time::{Duration, Instant};

// ============================ Fork Actor ============================ //
Expand Down Expand Up @@ -113,7 +111,6 @@ impl Fork {
}
}

#[async_trait]
impl Actor for Fork {
type Msg = ForkMessage;
type State = ForkState;
Expand Down Expand Up @@ -326,7 +323,6 @@ impl Philosopher {
}
}

#[async_trait]
impl Actor for Philosopher {
type Msg = PhilosopherMessage;
type State = PhilosopherState;
Expand Down
3 changes: 1 addition & 2 deletions ractor/examples/ping_pong.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
extern crate ractor;

use ractor::{async_trait, cast, Actor, ActorProcessingErr, ActorRef};
use ractor::{cast, Actor, ActorProcessingErr, ActorRef};

pub struct PingPong;

Expand Down Expand Up @@ -42,7 +42,6 @@ impl Message {
}
}

#[async_trait]
impl Actor for PingPong {
type Msg = Message;

Expand Down
5 changes: 1 addition & 4 deletions ractor/examples/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! cargo run --example supervisor
//! ```
use ractor::{async_trait, Actor, ActorProcessingErr, ActorRef, RpcReplyPort, SupervisionEvent};
use ractor::{Actor, ActorProcessingErr, ActorRef, RpcReplyPort, SupervisionEvent};

use tokio::time::Duration;

Expand Down Expand Up @@ -97,7 +97,6 @@ enum LeafActorMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for LeafActorMessage {}

#[async_trait]
impl Actor for LeafActor {
type Msg = LeafActorMessage;
type State = LeafActorState;
Expand Down Expand Up @@ -160,7 +159,6 @@ enum MidLevelActorMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for MidLevelActorMessage {}

#[async_trait]
impl Actor for MidLevelActor {
type Msg = MidLevelActorMessage;
type State = MidLevelActorState;
Expand Down Expand Up @@ -240,7 +238,6 @@ enum RootActorMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for RootActorMessage {}

#[async_trait]
impl Actor for RootActor {
type Msg = RootActorMessage;
type State = RootActorState;
Expand Down
60 changes: 31 additions & 29 deletions ractor/src/actor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
//! log to `stderr` for tracing. You can additionally setup a [panic hook](https://doc.rust-lang.org/std/panic/fn.set_hook.html)
//! to do things like capturing backtraces on the unwinding panic.
use std::future::Future;
use std::panic::AssertUnwindSafe;

use futures::TryFutureExt;
Expand Down Expand Up @@ -105,7 +106,6 @@ pub(crate) fn get_panic_string(e: Box<dyn std::any::Any + Send>) -> ActorProcess
/// patterns. Panics are also captured from the inner functions and wrapped into an Error
/// type, however should an [Err(_)] result from any of these functions the **actor will
/// terminate** and cleanup.
#[async_trait::async_trait]
pub trait Actor: Sized + Sync + Send + 'static {
/// The message type for this actor
type Msg: Message;
Expand All @@ -130,11 +130,11 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// be necessary to construct the initial state
///
/// Returns an initial [Actor::State] to bootstrap the actor
async fn pre_start(
fn pre_start(
&self,
myself: ActorRef<Self::Msg>,
args: Self::Arguments,
) -> Result<Self::State, ActorProcessingErr>;
) -> impl Future<Output = Result<Self::State, ActorProcessingErr>> + Send;

/// Invoked after an actor has started.
///
Expand All @@ -146,12 +146,12 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// * `myself` - A handle to the [ActorCell] representing this actor
/// * `state` - A mutable reference to the internal actor's state
#[allow(unused_variables)]
async fn post_start(
fn post_start(
&self,
myself: ActorRef<Self::Msg>,
state: &mut Self::State,
) -> Result<(), ActorProcessingErr> {
Ok(())
) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
async { Ok(()) }
}

/// Invoked after an actor has been stopped to perform final cleanup. In the
Expand All @@ -163,12 +163,12 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// * `myself` - A handle to the [ActorCell] representing this actor
/// * `state` - A mutable reference to the internal actor's last known state
#[allow(unused_variables)]
async fn post_stop(
fn post_stop(
&self,
myself: ActorRef<Self::Msg>,
state: &mut Self::State,
) -> Result<(), ActorProcessingErr> {
Ok(())
) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
async { Ok(()) }
}

/// Handle the incoming message from the event processing loop. Unhandled panickes will be
Expand All @@ -178,13 +178,13 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// * `message` - The message to process
/// * `state` - A mutable reference to the internal actor's state
#[allow(unused_variables)]
async fn handle(
fn handle(
&self,
myself: ActorRef<Self::Msg>,
message: Self::Msg,
state: &mut Self::State,
) -> Result<(), ActorProcessingErr> {
Ok(())
) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
async { Ok(()) }
}

/// Handle the remote incoming message from the event processing loop. Unhandled panickes will be
Expand All @@ -195,13 +195,13 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// * `state` - A mutable reference to the internal actor's state
#[allow(unused_variables)]
#[cfg(feature = "cluster")]
async fn handle_serialized(
fn handle_serialized(
&self,
myself: ActorRef<Self::Msg>,
message: crate::message::SerializedMessage,
state: &mut Self::State,
) -> Result<(), ActorProcessingErr> {
Ok(())
) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
async { Ok(()) }
}

/// Handle the incoming supervision event. Unhandled panicks will captured and
Expand All @@ -212,20 +212,22 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// * `message` - The message to process
/// * `state` - A mutable reference to the internal actor's state
#[allow(unused_variables)]
async fn handle_supervisor_evt(
fn handle_supervisor_evt(
&self,
myself: ActorRef<Self::Msg>,
message: SupervisionEvent,
state: &mut Self::State,
) -> Result<(), ActorProcessingErr> {
match message {
SupervisionEvent::ActorTerminated(who, _, _)
| SupervisionEvent::ActorPanicked(who, _) => {
myself.stop(None);
) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
async move {
match message {
SupervisionEvent::ActorTerminated(who, _, _)
| SupervisionEvent::ActorPanicked(who, _) => {
myself.stop(None);
}
_ => {}
}
_ => {}
Ok(())
}
Ok(())
}

/// Spawn an actor of this type, which is unsupervised, automatically starting
Expand All @@ -238,12 +240,12 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// Returns a [Ok((ActorRef, JoinHandle<()>))] upon successful start, denoting the actor reference
/// along with the join handle which will complete when the actor terminates. Returns [Err(SpawnErr)] if
/// the actor failed to start
async fn spawn(
fn spawn(
name: Option<ActorName>,
handler: Self,
startup_args: Self::Arguments,
) -> Result<(ActorRef<Self::Msg>, JoinHandle<()>), SpawnErr> {
ActorRuntime::<Self>::spawn(name, handler, startup_args).await
) -> impl Future<Output = Result<(ActorRef<Self::Msg>, JoinHandle<()>), SpawnErr>> + Send {
ActorRuntime::<Self>::spawn(name, handler, startup_args)
}

/// Spawn an actor of this type with a supervisor, automatically starting the actor
Expand All @@ -257,13 +259,13 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// Returns a [Ok((ActorRef, JoinHandle<()>))] upon successful start, denoting the actor reference
/// along with the join handle which will complete when the actor terminates. Returns [Err(SpawnErr)] if
/// the actor failed to start
async fn spawn_linked(
fn spawn_linked(
name: Option<ActorName>,
handler: Self,
startup_args: Self::Arguments,
supervisor: ActorCell,
) -> Result<(ActorRef<Self::Msg>, JoinHandle<()>), SpawnErr> {
ActorRuntime::<Self>::spawn_linked(name, handler, startup_args, supervisor).await
) -> impl Future<Output = Result<(ActorRef<Self::Msg>, JoinHandle<()>), SpawnErr>> + Send {
ActorRuntime::<Self>::spawn_linked(name, handler, startup_args, supervisor)
}
}

Expand Down
Loading

0 comments on commit f06c4b2

Please sign in to comment.