Approach A: Recipient<M> + actor_api! pattern#152
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
…rait # Conflicts: # Cargo.lock # Cargo.toml # concurrency/src/message.rs # concurrency/src/tasks/mod.rs # concurrency/src/threads/mod.rs # examples/bank/src/main.rs # examples/bank/src/messages.rs # examples/bank/src/server.rs # examples/bank_threads/src/main.rs # examples/bank_threads/src/messages.rs # examples/bank_threads/src/server.rs # examples/blocking_genserver/main.rs # examples/busy_genserver_warning/main.rs # examples/chat_room/Cargo.toml # examples/chat_room/src/main.rs # examples/chat_room/src/room.rs # examples/chat_room/src/user.rs # examples/name_server/src/main.rs # examples/name_server/src/messages.rs # examples/name_server/src/server.rs # examples/service_discovery/Cargo.toml # examples/service_discovery/src/main.rs # examples/signal_test/src/main.rs # examples/signal_test_threads/src/main.rs # examples/updater/src/main.rs # examples/updater/src/messages.rs # examples/updater/src/server.rs # examples/updater_threads/src/main.rs # examples/updater_threads/src/messages.rs
🤖 Kimi Code ReviewThis PR represents a major API redesign for the spawned actor framework. The changes are substantial and well-structured, addressing critical issues #144 and #145 through a new Handler + Recipient approach. Key Improvements✅ Type Safety (#144): The new ✅ Circular Dependencies (#145): ✅ Ergonomic APIs: The ✅ Registry Support: New global registry for named actors with type-safe discovery. Code Quality Issues1. Potential Race Condition in Registry (registry.rs:91)pub fn registered() -> Vec<String> {
let store = global_store().read().unwrap_or_else(|p| p.into_inner());
store.keys().cloned().collect()
}Issue: The 2. Missing Error Handling in Macro (macros/src/lib.rs:112)The 3. Context Clone in Timer Functions (tasks/time.rs:12, threads/time.rs:3)Both 4. Inconsistent Naming
5. Documentation Gaps
Performance Considerations✅ Good: The envelope pattern with TestingThe extensive test suite (34+ tests) provides good coverage for:
Migration PathThe examples show a clean migration from the old enum-based API to the new Handler approach. The breaking changes are well-justified by the improvements in type safety and expressiveness. SummaryThis is a high-quality PR that successfully addresses the fundamental API issues. The implementation is solid, though minor improvements could be made in error handling and documentation. The new API is significantly more ergonomic and type-safe than the previous version. Automated review by Kimi (Moonshot AI) · custom prompt |
🤖 Codex Code ReviewFindings
Notes
Possible next steps
Automated review by OpenAI Codex · custom prompt |
Greptile SummaryThis PR implements a major architectural refactor to adopt the "Approach A" pattern ( Key architectural changes:
Pattern benefits:
Test coverage: All 34 tests passing, examples verified working Confidence Score: 4/5
|
| Filename | Overview |
|---|---|
| concurrency/src/message.rs | added new Message trait and macro infrastructure for defining messages (messages!, send_messages!, request_messages!, actor_api!) |
| concurrency/src/registry.rs | added global actor registry with register, whereis, unregister, and registered functions using type-erased storage |
| concurrency/src/tasks/actor.rs | major refactor to Recipient<M> pattern with Handler<M> trait, envelope-based type erasure, simplified Actor trait with started/stopped lifecycle hooks |
| concurrency/src/threads/actor.rs | parallel refactor to tasks version, implementing same Recipient<M> pattern for sync (threads-based) actors |
| macros/src/lib.rs | added #[actor] proc macro that generates Handler<M> implementations from #[send_handler] and #[request_handler] annotated methods |
| examples/chat_room/src/room.rs | rewrote to use Recipient<Deliver> for type-erased member references, actor_api! for API trait generation |
| examples/chat_room/src/user.rs | rewrote to use ctx.recipient::<Deliver>() and actor_api! pattern, one-way dependency on room module |
| examples/ping_pong/src/producer.rs | rewrote to hold Recipient<Ping> instead of typed actor reference |
| concurrency/src/error.rs | simplified error types, removed unused variants, renamed Server to ActorStopped |
Class Diagram
%%{init: {'theme': 'neutral'}}%%
classDiagram
class Message {
<<trait>>
+type Result
}
class Actor {
<<trait>>
+started(ctx)
+stopped(ctx)
}
class Handler~M~ {
<<trait>>
+handle(msg, ctx) Result
}
class ActorRef~A~ {
-sender
-cancellation_token
-completion_rx
+send(msg)
+request(msg)
+recipient() Recipient~M~
+context() Context~A~
}
class Context~A~ {
-sender
-cancellation_token
+send(msg)
+request(msg)
+recipient() Recipient~M~
+stop()
}
class Receiver~M~ {
<<trait>>
+send(msg)
+request_raw(msg)
}
class Recipient~M~ {
<<type alias>>
Arc~dyn Receiver~M~~
}
class Envelope~A~ {
<<trait>>
+handle(actor, ctx)
}
class MessageEnvelope~M~ {
-msg: M
-tx: Option~Sender~
+handle(actor, ctx)
}
Actor <|.. Handler~M~
Handler~M~ ..> Message
Envelope~A~ <|.. MessageEnvelope~M~
ActorRef~A~ ..|> Receiver~M~
Context~A~ ..|> Receiver~M~
Receiver~M~ <.. Recipient~M~
ActorRef~A~ --> Context~A~
MessageEnvelope~M~ ..> Handler~M~
Last reviewed commit: 7693d45
Summary
Recipient<M>+actor_api!for type erasureResponse<T>and protocol trait patterns — cross-boundary communication usesRecipient<M>exclusivelyShared infrastructure from
feat/actor-macro-registry:Handler<M>,#[actor]proc macro,send_messages!/request_messages!,Receiver<M>/Recipient<M>, named registry,actor_api!macro.Key pattern: Actors that need to communicate across boundaries pass
Recipient<M>(type-erased message inbox). One-way dependency is acceptable (e.g. user.rs imports from room.rs).Test plan
cargo test -p spawned-concurrency— 34 tests passingcargo run -p chat_roomcargo run -p chat_room_threadscargo run -p ping_pongcargo run -p ping_pong_threadscargo run -p bankcargo run -p service_discoverygit grep "Response<" -- concurrency/→ 0 resultsgit grep "protocol_impl"→ 0 results