π¦ priact π¦
A lightweight and ergonomic Actor implementation for Rust, built on tokio, featuring explicit message prioritization via a BinaryHeap. This is based on the Actor concept from Swift.
β¨ Features
- Actor Model Implementation: Provides a robust foundation for building concurrent, stateful components that safely manage mutable data.
- Data Race Prevention: Ensures serial processing of messages, eliminating data races on the actor's internal state.
- Asynchronous Messaging: Leverages
tokio::mpscchannels for efficient, non-blocking communication with actors. - Message Prioritization: Messages can be assigned
Low,Medium(the default), orHighpriority, allowing critical operations to be processed ahead of others. - Ergonomic
define_actor!Macro: Simplifies actor definition by automatically generating message enums andhandlelogic, reducing boilerplate. - Built on
tokio: Seamlessly integrates with thetokioasynchronous runtime.
π‘ Why priact?
While Rust's ownership system makes data races less common, managing mutable state across asynchronous tasks can still be challenging. The Actor Model provides a clear pattern for this, and priact offers:
- Simplicity: A focused, opinionated implementation of the core Actor Model, without the overhead of a full framework if you only need the actor primitive.
- Safety: Guarantees that your actor's internal state is accessed by only one task at a time.
- Control: The unique message prioritization feature gives you fine-grained control over message processing order, crucial for real-time systems, performance-sensitive applications, or managing resource contention.
- Developer Experience: The
define_actor!macro makes defining actors straightforward and enjoyable.
π Getting Started
Add priact to your Cargo.toml:
[]
= "0.1.0" # Check crates.io for the latest version
= { = "1", = ["full"] } # Or specific features you need
= "0.1" # Required by the Actor trait
Basic Usage
Define your actor and its messages using the define_actor! macro:
use ;
use oneshot;
// Define your actor's state and its methods
define_actor!
async
π Under the Hood
- mpsc Receiver Task
Listens on a Tokio mpsc channel and pushes messages into aBinaryHeap<PrioritizedWrapper>. - Processor Task
Pops highest-priority message, calls your typedhandleon the actor, and repeats. - Shutdown
- Explicit: A
Shutdownvariant returnsfalsefromhandle, tearing down both tasks. - Implicit: Dropping all
Senderhandles drains the queue then stops.
- Explicit: A
π API Reference
define_actor!: Macro for defining actors and their messages.spawn_actor<A>(actor: A) -> mpsc::Sender<A::Msg>: Spawns an actor into atokiotask and returns a sender for its messages.Actortrait: Defines the behavior of an actor, requiring aMsgtype and ahandlemethod.Prioritizedtrait: Needs to be implemented by your message enum to specify priority.Priorityenum:Low,Medium,High.
For detailed API documentation, please refer to docs.rs.
π€ Contributing
Thank you to @lucretiel and @ipetkov for help with the macro!
Contributions are welcome! Feel free to open issues or submit pull requests.
π License
This project is licensed under the MIT License.