feat: #[actor] macro, named registry, and Handler<M>/Recipient<M> API#149
feat: #[actor] macro, named registry, and Handler<M>/Recipient<M> API#149ElFantasma wants to merge 3 commits intomainfrom
Conversation
… API Introduces a unified API redesign addressing #144, #145, and #129: - Handler<M> trait with per-message typed results (RPITIT, not object-safe) - Receiver<M>/Recipient<M> for type-erased cross-actor messaging - #[actor] proc macro that generates Handler<M> impls from #[handler] methods - Any-based named registry (register/whereis/unregister) - messages! declarative macro for defining message structs - Context<A> replaces ActorRef<A> in handler signatures - New examples: chat_room (Recipient), service_discovery (registry) - All existing examples migrated to new API
🤖 Codex Code ReviewReview Summary Findings (Ordered by Severity)
Medium / API Footguns
General Observations
If you want, I can sketch a concrete patch for the cancellation-aware receive loop and the threads Automated review by OpenAI Codex · custom prompt |
Greptile OverviewGreptile SummaryThis PR introduces a comprehensive API redesign for the spawned actor framework, replacing the monolithic message handling pattern with a typed, per-message Key Changes:
Migration Quality: Architecture: Confidence Score: 5/5
|
| Filename | Overview |
|---|---|
| macros/src/lib.rs | Implements #[actor] proc macro for generating Handler trait implementations from #[handler] methods |
| concurrency/src/registry.rs | New global registry using Any-based type erasure for named actor discovery; has good test coverage |
| concurrency/src/message.rs | Defines core Message trait and messages! macro for typed message declarations with associated result types |
| concurrency/src/tasks/actor.rs | Major refactor: replaced monolithic message handling with Handler trait, added Recipient type for type-erased messaging, improved panic handling |
| concurrency/src/threads/actor.rs | Parallel refactor for sync handlers; mirrors tasks module design with synchronous Handler trait |
| examples/chat_room/src/main.rs | New example demonstrating Recipient solving circular dependency between Room and User actors |
| examples/service_discovery/src/main.rs | New example demonstrating registry-based named actor discovery with register/whereis/unregister |
| examples/bank/src/server.rs | Successfully migrated to Handler trait pattern; each message type has individual handler implementation |
Sequence Diagram
sequenceDiagram
participant User as User Actor
participant Room as ChatRoom Actor
participant Recipient as Recipient<M>
participant Handler as Handler<M>
Note over User,Room: Actor Initialization
User->>Room: room.recipient::<Say>()
Room-->>User: Recipient<Say>
Note over User,Room: Cross-Actor Messaging via Recipient
User->>Recipient: send(Say { from, text })
Recipient->>Room: Envelope<Say>
Room->>Handler: handle(Say, ctx)
Handler-->>Room: ()
Note over Room: Broadcast to Members
loop For each member
Room->>Recipient: member.send(Deliver)
Recipient->>User: Envelope<Deliver>
User->>Handler: handle(Deliver, ctx)
Handler-->>User: ()
end
Note over User,Room: Registry-Based Discovery
User->>Registry: register("room", recipient)
Registry-->>User: Ok(())
User->>Registry: whereis::<Recipient<M>>("room")
Registry-->>User: Some(recipient)
| let msg_ty = match method.sig.inputs.iter().nth(1) { | ||
| Some(FnArg::Typed(pat_type)) => { | ||
| if let Pat::Ident(pat_ident) = &*pat_type.pat { | ||
| if pat_ident.ident == "_" || pat_ident.ident.to_string().starts_with('_') { | ||
| // Still use the type | ||
| } | ||
| } | ||
| &*pat_type.ty | ||
| } | ||
| _ => { | ||
| return syn::Error::new_spanned( | ||
| &method.sig, | ||
| "#[handler] method must have signature: fn(&mut self, msg: M, ctx: &Context<Self>) -> R", | ||
| ) | ||
| .to_compile_error() | ||
| .into(); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Consider validating that the 3rd parameter is ctx: &Context<Self>. Currently, if a user writes a handler with the wrong context type or missing context parameter, they'll get a confusing compiler error instead of a clear macro error.
Prompt To Fix With AI
This is a comment left during a code review.
Path: macros/src/lib.rs
Line: 52:69
Comment:
Consider validating that the 3rd parameter is `ctx: &Context<Self>`. Currently, if a user writes a handler with the wrong context type or missing context parameter, they'll get a confusing compiler error instead of a clear macro error.
How can I resolve this? If you propose a fix, please make it concise.
Summary
Unified API redesign addressing #144, #145, and #129:
Handler<M>trait (Improve type safety for request/reply message handling #144): Per-message typed results via RPITIT. Each message type gets its own handler impl withM::Resultreturn type. Replaces the monolithichandle_request/handle_messagepattern.Recipient<M>(Circular dependency problem with bidirectional actor communication #145): Type-erased cross-actor messaging viaReceiver<M>(object-safe) +Recipient<M> = Arc<dyn Receiver<M>>. Actors reference each other by message type, not concrete type — breaks circular dependencies.register/whereis/unregisterwithAny-based global store, keyed by name. Decouples actor discovery from type knowledge.#[actor]proc macro: GeneratesHandler<M>impls from#[handler]-annotated methods. Supports both async (tasks) and sync (threads).messages!macro: Declarative macro for defining message structs with associated result types.Context<A>: ReplacesActorRef<A>in handler signatures. Providessend(),request(),stop().New crates
spawned-macros— proc-macro crate with#[actor]+#[handler]New examples
chat_room— demonstratesRecipient<M>breaking circular deps between Room and Userservice_discovery— demonstratesregister/whereisfor named actor discoveryMigration
All existing examples migrated to the new API.
Test plan
cargo build --workspace— 17 crates compilecargo test --workspace— 34 tests passcargo run -p bank— typed Handler returns workcargo run -p chat_room— Recipient cross-actor messaging workscargo run -p service_discovery— registry register/whereis worksCloses #144, closes #145, closes #129