Skip to content

Commit baec2f4

Browse files
books: hyperactor-book: typed refs (#425)
Summary: Pull Request resolved: #425 finish off references section with "typed references" sub-section Reviewed By: mariusae Differential Revision: D77744864 fbshipit-source-id: 0dc46aab71df39ebb3a7e0fe0b84064593e01d7c
1 parent 4226f74 commit baec2f4

File tree

4 files changed

+107
-9
lines changed

4 files changed

+107
-9
lines changed

books/hyperactor-book/src/SUMMARY.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@
99
- [PortId](references/port_id.md)
1010
- [GangId](references/gang_id.md)
1111
- [Reference](references/reference.md)
12-
<!-- - [Typed References](references/typed_refs.md) -->
13-
<!-- - [Gangs](references/gangs.md) -->
14-
<!-- - [Bindings](references/bindings.md) -->
12+
- [Typed References](references/typed_refs.md)
1513
- [Mailboxes and Routers](mailboxes/index.md)
1614
- [Ports](mailboxes/ports.md)
1715
- [MailboxSender](mailboxes/mailbox_sender.md)

books/hyperactor-book/src/actors/handler.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Each message type that an actor can handle must be declared by implementing this
77
```rust
88
#[async_trait]
99
pub trait Handler<M>: Actor {
10-
async fn handle(&mut self, this: &Context<Self>, message: M) -> Result<(), anyhow::Error>;
10+
async fn handle(&mut self, cx: &Context<Self>, message: M) -> Result<(), anyhow::Error>;
1111
}
1212
```
1313

@@ -32,7 +32,7 @@ This is a marker implementation indicating that all actors can receive `Signal`.
3232
impl<A: Actor> Handler<Signal> for A {
3333
async fn handle(
3434
&mut self,
35-
_this: &Context<Self>,
35+
_cx: &Context<Self>,
3636
_message: Signal,
3737
) -> Result<(), anyhow::Error> {
3838
unimplemented!("signal handler should not be called directly")
@@ -51,7 +51,7 @@ where
5151
{
5252
async fn handle(
5353
&mut self,
54-
this: &Context<Self>,
54+
cx: &Context<Self>,
5555
msg: IndexedErasedUnbound<M>,
5656
) -> anyhow::Result<()> {
5757
let message = msg.downcast()?.bind()?;

books/hyperactor-book/src/references/index.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,4 @@ In this section, we’ll cover:
2121
- [`PortId`](port_id.md)
2222
- [`GangId`](gang_id.md)
2323
- The [Reference](reference.md), which unifies all reference variants
24-
<!-- - [Typed references](typed_refs.md) used in APIs: `ActorRef<A>`, `PortRef<M>`, and `OncePortRef<M>` -->
25-
<!-- - The semantics of [gangs](gangs.md), which represent replicated actors across ranks -->
26-
<!-- - How references participate in [bindings](bindings.md) and serialization -->
24+
- [Typed references](typed_refs.md) used in APIs: `ActorRef<A>`, `PortRef<M>`, and `OncePortRef<M>`
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,103 @@
11
# Typed References
2+
3+
Typed references are strongly typed wrappers over raw identifiers like `ActorId` and `PortId`. These types are used throughout hyperactor’s APIs; as parameters in messages, return values from `bind()` methods, and elements in routing decisions. They make distributed communication safe, expressive, and statically checked.
4+
5+
## Overview
6+
7+
There are three main typed reference types:
8+
9+
- [`ActorRef<A>`](#actorrefa): A typed reference to an actor implementing the `RemoteActor` trait.
10+
- [`PortRef<M>`](#portrefm): A reference to a reusable mailbox port for messages of type `M`.
11+
- [`OncePortRef<M>`](#onceportrefm): A reference to a one-shot port for receiving a single response of type `M`.
12+
13+
These types are used as parameters in messages, return values from bindings, and components of the routing system.
14+
15+
---
16+
17+
## `ActorRef<A>`
18+
19+
`ActorRef<A>` is a typed reference to an actor of type `A`. It provides a way to identify and address remote actors that implement `RemoteActor`.
20+
21+
```rust
22+
let actor_ref: ActorRef<MyActor> = ActorRef::attest(actor_id);
23+
```
24+
25+
Unlike `ActorHandle<A>`, an `ActorRef` is just a reference — it doesn’t guarantee that the actor is currently running. It's primarily used for routing and type-safe messaging across `Proc`s.
26+
27+
### Definition
28+
```rust
29+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
30+
pub struct ActorRef<A: RemoteActor> {
31+
actor_id: ActorId,
32+
phantom: PhantomData<A>,
33+
}
34+
```
35+
This type is a thin wrapper around an `ActorId`, with a phantom type `A` to track which actor it refers to. It ensures you can only send messages supported by the actor's declared `RemoteHandles`.
36+
37+
## `PortRef<M>`
38+
39+
`PortRef<M>` refers to a mailbox port for messages of type `M`.
40+
```rust
41+
let (port, mut receiver) = actor.open_port::<MyMessage>();
42+
let port_ref: PortRef<MyMessage> = port.bind();
43+
```
44+
45+
This allows the port to be sent across the network or passed into other messages. On the receiving end, `PortRef` can be used to deliver messages of the expected type.
46+
47+
### Definition
48+
49+
```rust
50+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
51+
pub struct PortRef<M: Message> {
52+
port_id: PortId,
53+
phantom: PhantomData<M>,
54+
}
55+
```
56+
As with `ActorRef`, this is a typed wrapper around a raw identifier (`PortId`), carrying a phantom type for safety. It ensures that only messages of type `M` can be sent through this reference.
57+
58+
## `OncePortRef<M>`
59+
60+
A `OncePortRef<M>` is like a `PortRef`, but designed for exactly one response. Once used, it cannot be reused or cloned.
61+
```rust
62+
let (once_port, receiver) = actor.open_once_port::<MyMessage>();
63+
let once_ref = once_port.bind();
64+
```
65+
These are commonly used for request/response interactions, where a single reply is expected.
66+
67+
### Definition
68+
69+
```rust
70+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
71+
pub struct OncePortRef<M: Message> {
72+
port_id: PortId,
73+
phantom: PhantomData<M>,
74+
}
75+
```
76+
Just like `PortRef`, this wraps a `PortId` with a phantom message type `M` for type safety. Internally, the system enforces one-time delivery semantics, ensuring the port is closed after receiving a single message.
77+
78+
## `GangRef<A>`
79+
80+
A `GangRef<A>` is a typed reference to a gang of actors, all of which implement the same `RemoteActor` type `A`.
81+
```rust
82+
let gang_ref: GangRef<MyActor> = GangId::new(...).into();
83+
```
84+
You can extract an `ActorRef<A>` for a specific rank in the gang:
85+
```rust
86+
let actor = gang_ref.rank(0); // ActorRef<MyActor>
87+
```
88+
This allows you to route messages to specific members of a replicated actor group, or to iterate over the gang for broadcasting, synchronization, or indexing.
89+
90+
### Definition
91+
```rust
92+
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Hash, Ord)]
93+
pub struct GangRef<A: RemoteActor> {
94+
gang_id: GangId,
95+
phantom: PhantomData<A>,
96+
}
97+
```
98+
99+
#### Methods
100+
- `gang_ref.rank(rank: usize) -> ActorRef<A>`
101+
Returns a typed actor reference for the actor at the given rank in the gang. The method doesn’t validate the rank, so correctness is up to the caller.
102+
- `gang_ref.gang_id() -> &GangId`
103+
Returns the underlying, untyped gang identifier.

0 commit comments

Comments
 (0)