Skip to content

Commit 90fa670

Browse files
books: hyperactor-book: references (#398)
Summary: Pull Request resolved: #398 new section detailing the hyperactor reference types Reviewed By: mariusae Differential Revision: D77613398 fbshipit-source-id: 97cfbff249dd6bc814b9efb196073dbfb7f0775d
1 parent 48a0714 commit 90fa670

File tree

12 files changed

+506
-0
lines changed

12 files changed

+506
-0
lines changed

books/hyperactor-book/src/SUMMARY.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@
88
- [`#[derive(Named)]`](macros/named.md)
99
- [`#[export]`](macros/export.md)
1010
- [`#[forward]`](macros/forward.md)
11+
- [References](references/index.md)
12+
- [Syntax](references/syntax.md)
13+
- [WorldId](references/world_id.md)
14+
- [ProcId](references/proc_id.md)
15+
- [ActorId](references/actor_id.md)
16+
- [PortId](references/port_id.md)
17+
- [GangId](references/gang_id.md)
18+
- [Reference](references/reference.md)
19+
<!-- - [Typed References](references/typed_refs.md) -->
20+
<!-- - [Gangs](references/gangs.md) -->
21+
<!-- - [Bindings](references/bindings.md) -->
1122
- [Mailboxes and Routers](mailboxes/index.md)
1223
- [Ports](mailboxes/ports.md)
1324
- [MailboxSender](mailboxes/mailbox_sender.md)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# `ActorId`
2+
3+
An `ActorId` uniquely identifies an actor within a proc. It combines the proc the actor lives on, a string name, and a numeric pid (process-local instance index).
4+
5+
```rust
6+
#[derive(
7+
Debug,
8+
Serialize,
9+
Deserialize,
10+
Clone,
11+
PartialEq,
12+
Eq,
13+
PartialOrd,
14+
Hash,
15+
Ord,
16+
Named
17+
)]
18+
pub struct ActorId(pub ProcId, pub String, pub usize);
19+
```
20+
- The first field is the actor's `ProcId`.
21+
- The second is the actor's name (used for grouping and logging).
22+
- The third is the pid, which distinguishes multiple instances with the same name.
23+
24+
### Construction
25+
26+
Construct an actor ID directly:
27+
```rust
28+
use hyperactor::reference::{ActorId, ProcId, WorldId};
29+
30+
let proc = ProcId(WorldId("training".into()), 0);
31+
let actor = ActorId(proc, "worker".into(), 1);
32+
```
33+
34+
Or with the `id!` macro:
35+
```rust
36+
use hyperactor::id;
37+
38+
let actor = id!(training[0].worker[1]);
39+
// Equivalent to ActorId(ProcId(WorldId("training".into()), 0), "worker".into(), 1)
40+
```
41+
To refer to the root actor (the canonical instance), use:
42+
```rust
43+
let root = ActorId::root(proc, "worker".into());
44+
// Equivalent to ActorId(proc, "worker".into(), 0)
45+
```
46+
47+
### Methods
48+
49+
```rust
50+
impl ActorId {
51+
pub fn proc_id(&self) -> &ProcId;
52+
pub fn name(&self) -> &str;
53+
pub fn pid(&self) -> usize;
54+
pub fn world_name(&self) -> &str;
55+
pub fn rank(&self) -> usize;
56+
pub fn child_id(&self, pid: usize) -> Self;
57+
pub fn port_id(&self, port: u64) -> PortId;
58+
pub fn root(proc: ProcId, name: String) -> Self;
59+
}
60+
```
61+
62+
- `.proc_id()` returns the ProcId that owns this actor.
63+
- `.name()` returns the logical name of the actor (e.g., "worker").
64+
- `.pid()` returns the actor's instance ID.
65+
- `.world_name()` returns the name of the actor’s world.
66+
- `.rank()` returns the proc rank (i.e., index) this actor runs on.
67+
- `.child_id(pid)` creates a new `ActorId` with the same name and proc but a different pid.
68+
- `.port_id(port)` returns a `PortId` representing a port on this actor.
69+
- `.root(proc, name)` constructs a new root actor (`pid = 0`) in the given proc.
70+
71+
### Traits
72+
73+
`ActorId` implements:
74+
75+
- `Display` — formats as `world[rank].name[pid]`
76+
- `FromStr` — parses strings like `"training[0].logger[1]"`
77+
- `Clone`, `Eq`, `Ord`, `Hash` — useful in maps, sets, and registries
78+
- `Named` — enables type-based routing, port lookup, and reflection
79+
80+
## Semantics
81+
82+
- The `name` groups actors logically within a proc (e.g., `"worker"`, `"trainer"`).
83+
- The `pid` distinguishes physical instances:
84+
- `pid = 0` represents the **root** actor instance.
85+
- `pid > 0` typically corresponds to **child actors** spawned by the root.
86+
- Most routing and API surfaces operate on root actors by default.
87+
- Port creation is always rooted in an `ActorId`, via `.port_id(...)`.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Bindings
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# `GangId`
2+
3+
A `GangId` identifies a logical group of actors with the same name across all procs in a world. It serves as a convenient shorthand for referring to all root instances of a given actor name.
4+
```rust
5+
#[derive(
6+
Debug,
7+
Serialize,
8+
Deserialize,
9+
Clone,
10+
PartialEq,
11+
Eq,
12+
PartialOrd,
13+
Hash,
14+
Ord,
15+
Named
16+
)]
17+
pub struct GangId(pub WorldId, pub String);
18+
```
19+
- The first field is the WorldId.
20+
- The second field is the shared actor name.
21+
22+
A `GangId` is conceptually like saying: “the actor named X on every proc in world W.”
23+
24+
## Construction
25+
26+
```rust
27+
use hyperactor::reference::{GangId, WorldId};
28+
29+
let gang = GangId(WorldId("training".into()), "logger".into());
30+
```
31+
32+
Or using the id! macro:
33+
```rust
34+
use hyperactor::id;
35+
36+
let gang = id!(training.logger);
37+
// Equivalent to GangId(WorldId("training".into()), "logger".into())
38+
```
39+
40+
## Methods
41+
42+
```rust
43+
impl GangId {
44+
pub fn world_id(&self) -> &WorldId;
45+
pub fn name(&self) -> &str;
46+
pub fn actor_id(&self, rank: usize) -> ActorId;
47+
pub fn expand(&self, world_size: usize) -> impl Iterator<Item = ActorId> + '_;
48+
}
49+
```
50+
- `.world_id()` returns the world this gang is defined in.
51+
- `.name()` returns the shared actor name (e.g., "logger").
52+
- `.actor_id(rank)` returns the root actor on that proc.
53+
- `.expand(world_size)` yields all root ActorIds from rank `0..world_size`.
54+
55+
## Semantics
56+
57+
- Gangs are always composed of root actors (`pid = 0`) with a common name.
58+
- Gang references are useful for broadcasting, coordination, or actor discovery.
59+
- They are lightweight and purely name-based; no state is attached to a `GangId`.
60+
61+
## Traits
62+
63+
`GangId` implements:
64+
- `Display` — formatted as world.actor
65+
- `FromStr` — parses from strings like "training.logger"
66+
- `Ord`, `Eq`, `Hash` — usable in maps, registries, and routing
67+
- `Named` — enables type registration and metadata lookup
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Gangs
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# References
2+
3+
This section documents the reference system used throughout hyperactor to identify and communicate with distributed entities.
4+
5+
References are lightweight, serializable identifiers for **worlds**, **procs**, **actors** **ports**, and **gangs**. They are the backbone of addressing and routing in the runtime. Whether you're sending a message, spawning an actor, or broadcasting to a group, references are how you name things.
6+
7+
The reference system is:
8+
9+
- **Uniform**: All references follow a shared syntax and structure.
10+
- **Parsable**: References can be round-tripped from strings and manipulated programmatically.
11+
- **Typed**: While the `Reference` enum is typeless and dynamic, typed references like `ActorRef<A>` and `PortRef<M>` allow safe interaction in APIs.
12+
- **Orderable**: References implement a total order, enabling prefix-based routing and sorted maps.
13+
14+
In this section, we’ll cover:
15+
16+
- The [syntax](syntax.md) and string format of references
17+
- The core reference types:
18+
- [`WorldId`](world_id.md)
19+
- [`ProcId`](proc_id.md)
20+
- [`ActorId`](actor_id.md)
21+
- [`PortId`](port_id.md)
22+
- [`GangId`](gang_id.md)
23+
- 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 -->
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# `PortId`
2+
3+
A `PortId` identifies a specific port on a particular actor. Ports are the entry points through which messages are delivered to an actor, and each `PortId` is globally unique.
4+
5+
```rust
6+
#[derive(
7+
Debug,
8+
Serialize,
9+
Deserialize,
10+
Clone,
11+
PartialEq,
12+
Eq,
13+
PartialOrd,
14+
Hash,
15+
Ord,
16+
Named
17+
)]
18+
pub struct PortId(pub ActorId, pub u64);
19+
```
20+
- The first field is the owning `ActorId`.
21+
- The second field is the port number (`u64`), typically derived from the message type’s registered port.
22+
23+
## Construction
24+
25+
```rust
26+
use hyperactor::reference::{PortId, ActorId};
27+
28+
let port = PortId(actor, 42);
29+
```
30+
Or via the `id!` macro:
31+
```rust
32+
use hyperactor::id;
33+
34+
let port = id!(training[0].logger[1][42]);
35+
// Equivalent to PortId(ActorId(...), 42)
36+
```
37+
You can also construct a PortId from an `ActorId` using `.port_id(...)`:
38+
```rust
39+
let port = actor.port_id(42);
40+
```
41+
42+
## Methods
43+
44+
```rust
45+
impl PortId {
46+
pub fn actor_id(&self) -> &ActorId;
47+
pub fn index(&self) -> u64;
48+
pub fn into_actor_id(self) -> ActorId;
49+
}
50+
```
51+
- `.actor_id()` returns the owning actor.
52+
- `.index()` returns the port number.
53+
- `.into_actor_id()` discards the port index and yields the owning actor ID.
54+
55+
## Traits
56+
57+
`PortId` implements:
58+
- `Display` — formatted as `world[rank].actor[pid][port]`
59+
- `FromStr` — parses from strings like `"training[0].logger[1][42]"`
60+
- `Ord`, `Eq`, `Hash` — usable as map keys or for dispatch
61+
- `Named` — supports reflection and typed messaging
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# `ProcId`
2+
3+
A `ProcId` identifies a single runtime instance within a world. All actors exist within a proc, and message routing between actors is scoped by the proc’s identity.
4+
```rust
5+
#[derive(
6+
Debug,
7+
Serialize,
8+
Deserialize,
9+
Clone,
10+
PartialEq,
11+
Eq,
12+
PartialOrd,
13+
Hash,
14+
Ord,
15+
Named
16+
)]
17+
pub struct ProcId(pub WorldId, pub usize);
18+
```
19+
20+
## Construction
21+
22+
You can construct a `ProcId` directly:
23+
```rust
24+
use hyperactor::reference::{WorldId, ProcId};
25+
26+
let proc = ProcId(WorldId("training".into()), 0);
27+
```
28+
Or statically using the `id!` macro:
29+
```rust
30+
use hyperactor::id;
31+
32+
let proc = id!(training[0]); // Equivalent to ProcId(WorldId("training".into()), 0)
33+
```
34+
35+
## Methods
36+
37+
```rust
38+
impl ProcId {
39+
pub fn world_id(&self) -> &WorldId;
40+
pub fn world_name(&self) -> &str;
41+
pub fn rank(&self) -> usize;
42+
pub fn actor_id(&self, name: impl Into<String>, pid: usize) -> ActorId;
43+
}
44+
```
45+
- `.world_id()` gives the `WorldId` this proc belongs to.
46+
- `.rank()` returns the proc’s index.
47+
- `.actor_id(name, pid)` constructs an `ActorId` for an actor hosted on this proc.
48+
49+
# Notes
50+
51+
Ranks greater than or equal to `1 << (usize::BITS - 1)` are considered user-space procs. These are typically created with `WorldId::random_user_proc()` and are not assigned by the system.
52+
53+
## Traits
54+
55+
ProcId implements:
56+
- `Display` — formatted as `world[rank]`
57+
- `FromStr` — parses from strings like "training[0]"
58+
- `Ord`, `Eq`, `Hash` — usable in maps and sorted structures
59+
- `Named` — enables port lookup and type reflection

0 commit comments

Comments
 (0)