diff --git a/README.md b/README.md
index c090b8ff..4b7358eb 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# ractor
-
+
*Pronounced ract-er*
@@ -64,7 +64,7 @@ Install `ractor` by adding the following to your Cargo.toml dependencies.
ractor = "0.9"
```
-The minimum supported Rust version (MSRV) of `ractor` is `1.64`
+The minimum supported Rust version (MSRV) of `ractor` is `1.64`. However to utilize the native `async fn` support in traits and not rely on the `async-trait` crate's desugaring functionliaty, you need to be on Rust version `>= 1.75`. The stabilization of `async fn` in traits [was recently added](https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html).
## Features
@@ -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
@@ -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;
diff --git a/ractor/Cargo.toml b/ractor/Cargo.toml
index ff3bc1a8..fef352ee 100644
--- a/ractor/Cargo.toml
+++ b/ractor/Cargo.toml
@@ -19,19 +19,20 @@ cluster = []
tokio_runtime = ["tokio/time", "tokio/rt", "tokio/macros", "tokio/tracing"]
# default = ["async-std"]
-default = ["tokio_runtime"]
+default = ["tokio_runtime", "async-trait"]
[dependencies]
## Required dependencies
-async-trait = "0.1"
dashmap = "5"
futures = "0.3"
once_cell = "1"
rand = "0.8"
+## Configurable dependencies
# Tracing feature requires --cfg=tokio_unstable
-tokio = { version = "1", features = ["sync"] }
async-std = { version = "1", features = ["attributes"], optional = true }
+async-trait = { version = "0.1", optional = true }
+tokio = { version = "1", features = ["sync"] }
tracing = { version = "0.1", features = ["attributes"] }
[dev-dependencies]
diff --git a/ractor/benches/actor.rs b/ractor/benches/actor.rs
index 1860a42f..9ecbe1fa 100644
--- a/ractor/benches/actor.rs
+++ b/ractor/benches/actor.rs
@@ -17,7 +17,7 @@ struct BenchActorMessage;
#[cfg(feature = "cluster")]
impl Message for BenchActorMessage {}
-#[async_trait::async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for BenchActor {
type Msg = BenchActorMessage;
@@ -247,7 +247,7 @@ fn process_messages(c: &mut Criterion) {
num_msgs: u64,
}
- #[async_trait::async_trait]
+ #[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for MessagingActor {
type Msg = BenchActorMessage;
diff --git a/ractor/examples/counter.rs b/ractor/examples/counter.rs
index c8803aa2..6a537932 100644
--- a/ractor/examples/counter.rs
+++ b/ractor/examples/counter.rs
@@ -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;
@@ -31,7 +31,7 @@ enum CounterMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for CounterMessage {}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for Counter {
type Msg = CounterMessage;
diff --git a/ractor/examples/monte_carlo.rs b/ractor/examples/monte_carlo.rs
index f8578f34..afaa1fcb 100644
--- a/ractor/examples/monte_carlo.rs
+++ b/ractor/examples/monte_carlo.rs
@@ -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 ================== //
@@ -62,7 +62,7 @@ struct GameMessage(ActorRef);
#[cfg(feature = "cluster")]
impl ractor::Message for GameMessage {}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for Game {
type Msg = GameMessage;
@@ -139,7 +139,7 @@ impl GameManagerState {
}
}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for GameManager {
type Msg = GameManagerMessage;
diff --git a/ractor/examples/output_port.rs b/ractor/examples/output_port.rs
index 9df8b999..38c2bd76 100644
--- a/ractor/examples/output_port.rs
+++ b/ractor/examples/output_port.rs
@@ -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 {
@@ -31,7 +31,7 @@ impl ractor::Message for Output {}
struct Publisher;
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for Publisher {
type Msg = PublisherMessage;
@@ -70,7 +70,7 @@ enum SubscriberMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for SubscriberMessage {}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for Subscriber {
type Msg = SubscriberMessage;
diff --git a/ractor/examples/philosophers.rs b/ractor/examples/philosophers.rs
index 6da054f2..6e0f7df9 100644
--- a/ractor/examples/philosophers.rs
+++ b/ractor/examples/philosophers.rs
@@ -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 ============================ //
@@ -113,7 +111,7 @@ impl Fork {
}
}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for Fork {
type Msg = ForkMessage;
type State = ForkState;
@@ -326,7 +324,7 @@ impl Philosopher {
}
}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for Philosopher {
type Msg = PhilosopherMessage;
type State = PhilosopherState;
diff --git a/ractor/examples/ping_pong.rs b/ractor/examples/ping_pong.rs
index c4c5e9a9..338b7040 100644
--- a/ractor/examples/ping_pong.rs
+++ b/ractor/examples/ping_pong.rs
@@ -14,7 +14,7 @@
extern crate ractor;
-use ractor::{async_trait, cast, Actor, ActorProcessingErr, ActorRef};
+use ractor::{cast, Actor, ActorProcessingErr, ActorRef};
pub struct PingPong;
@@ -42,7 +42,7 @@ impl Message {
}
}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for PingPong {
type Msg = Message;
diff --git a/ractor/examples/supervisor.rs b/ractor/examples/supervisor.rs
index fdc9e557..c6671d8f 100644
--- a/ractor/examples/supervisor.rs
+++ b/ractor/examples/supervisor.rs
@@ -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;
@@ -97,7 +97,7 @@ enum LeafActorMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for LeafActorMessage {}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for LeafActor {
type Msg = LeafActorMessage;
type State = LeafActorState;
@@ -160,7 +160,7 @@ enum MidLevelActorMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for MidLevelActorMessage {}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for MidLevelActor {
type Msg = MidLevelActorMessage;
type State = MidLevelActorState;
@@ -240,7 +240,7 @@ enum RootActorMessage {
#[cfg(feature = "cluster")]
impl ractor::Message for RootActorMessage {}
-#[async_trait]
+#[cfg_attr(feature = "async-trait", ractor::async_trait)]
impl Actor for RootActor {
type Msg = RootActorMessage;
type State = RootActorState;
diff --git a/ractor/src/actor/mod.rs b/ractor/src/actor/mod.rs
index 1fc553bb..d2f542b8 100644
--- a/ractor/src/actor/mod.rs
+++ b/ractor/src/actor/mod.rs
@@ -50,6 +50,8 @@
//! 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.
+#[cfg(not(feature = "async-trait"))]
+use std::future::Future;
use std::panic::AssertUnwindSafe;
use futures::TryFutureExt;
@@ -105,7 +107,7 @@ pub(crate) fn get_panic_string(e: Box) -> 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]
+#[cfg_attr(feature = "async-trait", crate::async_trait)]
pub trait Actor: Sized + Sync + Send + 'static {
/// The message type for this actor
type Msg: Message;
@@ -130,6 +132,27 @@ pub trait Actor: Sized + Sync + Send + 'static {
/// be necessary to construct the initial state
///
/// Returns an initial [Actor::State] to bootstrap the actor
+ #[cfg(not(feature = "async-trait"))]
+ fn pre_start(
+ &self,
+ myself: ActorRef,
+ args: Self::Arguments,
+ ) -> impl Future