1use hyperactor::Actor;
12use hyperactor::ActorAddr;
13use hyperactor::Context;
14use hyperactor::RemoteHandles;
15use hyperactor::RemoteMessage;
16use hyperactor::actor::Referable;
17use hyperactor::id::Uid;
18use hyperactor_config::Flattrs;
19use ndslice::Extent;
20use ndslice::Point;
21use ndslice::Region;
22use ndslice::Shape;
23use ndslice::Slice;
24use ndslice::selection::Selection;
25use ndslice::selection::routing::RoutingFrame;
26use serde::Deserialize;
27use serde::Serialize;
28use typeuri::Named;
29use uuid::Uuid;
30
31use crate::ValueMesh;
32use crate::comm::CommMeshConfig;
33use crate::mesh_id::ActorMeshId;
34
35pub(crate) trait CastEnvelope {
38 fn dest_port(&self) -> &DestinationPort;
39 fn headers(&self) -> &Flattrs;
40 fn sender(&self) -> &ActorAddr;
41 fn cast_point(&self, config: &CommMeshConfig) -> anyhow::Result<Point>;
42 fn data(&self) -> &wirevalue::Any<wirevalue::encoding::Multipart>;
43 fn data_mut(&mut self) -> &mut wirevalue::Any<wirevalue::encoding::Multipart>;
44}
45
46#[derive(Serialize, Deserialize, Debug, Clone)]
51pub struct Uslice {
52 pub slice: Slice,
54 pub selection: Selection,
56}
57
58#[derive(Debug, Serialize, Deserialize, Clone, Named)]
60pub struct CastMessageEnvelope {
61 actor_mesh_id: ActorMeshId,
63 headers: Flattrs,
65 sender: ActorAddr,
67 dest_port: DestinationPort,
70 data: wirevalue::Any<wirevalue::encoding::Multipart>,
72 shape: Shape,
74}
75wirevalue::register_type!(CastMessageEnvelope);
76
77impl CastEnvelope for CastMessageEnvelope {
78 fn sender(&self) -> &ActorAddr {
79 &self.sender
80 }
81
82 fn headers(&self) -> &Flattrs {
83 &self.headers
84 }
85
86 fn dest_port(&self) -> &DestinationPort {
87 &self.dest_port
88 }
89
90 fn data(&self) -> &wirevalue::Any<wirevalue::encoding::Multipart> {
91 &self.data
92 }
93
94 fn data_mut(&mut self) -> &mut wirevalue::Any<wirevalue::encoding::Multipart> {
95 &mut self.data
96 }
97
98 fn cast_point(&self, config: &CommMeshConfig) -> anyhow::Result<Point> {
99 let rank_on_root_mesh = config.self_rank();
100 let cast_rank = self.relative_rank(rank_on_root_mesh)?;
101 let cast_shape = self.shape();
102 let cast_point = cast_shape
103 .extent()
104 .point_of_rank(cast_rank)
105 .expect("rank out of bounds");
106 Ok(cast_point)
107 }
108}
109
110impl CastMessageEnvelope {
111 pub fn new<A, M>(
113 actor_mesh_id: ActorMeshId,
114 sender: ActorAddr,
115 shape: Shape,
116 headers: Flattrs,
117 message: M,
118 ) -> Result<Self, anyhow::Error>
119 where
120 A: Referable + RemoteHandles<M>,
121 M: RemoteMessage,
122 {
123 let actor_uid = actor_mesh_id.uid().clone();
124 let data = wirevalue::Any::<wirevalue::encoding::Multipart>::serialize(&message)?;
125 Ok(Self {
126 actor_mesh_id,
127 headers,
128 sender,
129 dest_port: DestinationPort::new::<A, M>(actor_uid),
130 data,
131 shape,
132 })
133 }
134
135 pub fn from_serialized(
139 actor_mesh_id: ActorMeshId,
140 sender: ActorAddr,
141 dest_port: DestinationPort,
142 shape: Shape,
143 headers: Flattrs,
144 data: wirevalue::Any<wirevalue::encoding::Multipart>,
145 ) -> Self {
146 Self {
147 actor_mesh_id,
148 sender,
149 headers,
150 dest_port,
151 data,
152 shape,
153 }
154 }
155
156 pub(crate) fn shape(&self) -> &Shape {
157 &self.shape
158 }
159
160 pub(crate) fn relative_rank(&self, rank_on_root_mesh: usize) -> anyhow::Result<usize> {
163 let shape = self.shape();
164 let coords = shape.slice().coordinates(rank_on_root_mesh).map_err(|e| {
165 anyhow::anyhow!(
166 "fail to calculate coords for root rank {} due to error: {}; shape is {:?}",
167 rank_on_root_mesh,
168 e,
169 shape,
170 )
171 })?;
172 let extent =
173 Extent::new(shape.labels().to_vec(), shape.slice().sizes().to_vec()).map_err(|e| {
174 anyhow::anyhow!(
175 "fail to calculate extent for root rank {} due to error: {}; shape is {}",
176 rank_on_root_mesh,
177 e,
178 shape,
179 )
180 })?;
181 let point = extent.point(coords).map_err(|e| {
182 anyhow::anyhow!(
183 "fail to calculate point for root rank {} due to error: {}; extent is {}, shape is {}",
184 rank_on_root_mesh,
185 e,
186 extent,
187 shape,
188 )
189 })?;
190 Ok(point.rank())
191 }
192
193 pub(crate) fn stream_key(&self) -> (ActorMeshId, ActorAddr) {
197 (self.actor_mesh_id.clone(), self.sender.clone())
198 }
199}
200
201#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Named)]
207pub struct DestinationPort {
208 actor_uid: Uid,
210 port: u64,
213}
214wirevalue::register_type!(DestinationPort);
215
216impl DestinationPort {
217 pub fn new<A, M>(actor_uid: Uid) -> Self
219 where
220 A: Referable + RemoteHandles<M>,
221 M: RemoteMessage,
222 {
223 Self {
224 actor_uid,
225 port: M::port(),
226 }
227 }
228
229 pub fn port(&self) -> u64 {
231 self.port
232 }
233
234 pub fn actor_uid(&self) -> &Uid {
236 &self.actor_uid
237 }
238}
239
240#[derive(Serialize, Deserialize, Debug, Clone, Named)]
242pub struct CastMessage {
243 pub dest: Uslice,
245 pub message: CastMessageEnvelope,
247}
248wirevalue::register_type!(CastMessage);
249
250#[derive(Serialize, Deserialize, Debug, Clone, Named)]
254pub(crate) struct ForwardMessage {
255 pub(crate) sender: ActorAddr,
257 pub(crate) dests: Vec<RoutingFrame>,
259 pub(crate) seq: usize,
261 pub(crate) last_seq: usize,
263 pub(crate) message: CastMessageEnvelope,
265}
266wirevalue::register_type!(ForwardMessage);
267
268#[derive(Serialize, Deserialize, Debug, Clone, Named)]
270pub(crate) struct CastMessageV1 {
271 pub(super) headers: Flattrs,
273 pub(super) sender: ActorAddr,
275 pub(super) session_id: Uuid,
277 pub(super) seqs: ValueMesh<u64>,
279 pub(super) dest_region: Region,
281 pub(super) dest_port: DestinationPort,
284 pub(super) data: wirevalue::Any<wirevalue::encoding::Multipart>,
286}
287
288impl CastEnvelope for CastMessageV1 {
289 fn sender(&self) -> &ActorAddr {
290 &self.sender
291 }
292
293 fn headers(&self) -> &Flattrs {
294 &self.headers
295 }
296
297 fn dest_port(&self) -> &DestinationPort {
298 &self.dest_port
299 }
300
301 fn data(&self) -> &wirevalue::Any<wirevalue::encoding::Multipart> {
302 &self.data
303 }
304
305 fn data_mut(&mut self) -> &mut wirevalue::Any<wirevalue::encoding::Multipart> {
306 &mut self.data
307 }
308
309 fn cast_point(&self, config: &CommMeshConfig) -> anyhow::Result<Point> {
310 let rank_on_root_mesh = config.self_rank();
311 let cast_point = self.dest_region.point_of_base_rank(rank_on_root_mesh)?;
312 Ok(cast_point)
313 }
314}
315
316#[cfg(test)]
317impl CastMessageV1 {
318 pub(crate) fn new<A, M>(
320 sender: ActorAddr,
321 dest_mesh: &ActorMeshId,
322 dest_region: Region,
323 headers: Flattrs,
324 message: M,
325 session_id: Uuid,
326 seqs: ValueMesh<u64>,
327 ) -> Result<Self, anyhow::Error>
328 where
329 A: Referable + RemoteHandles<M>,
330 M: RemoteMessage,
331 {
332 let data = wirevalue::Any::<wirevalue::encoding::Multipart>::serialize(&message)?;
333 Ok(Self {
334 headers,
335 sender,
336 session_id,
337 seqs,
338 dest_region,
339 dest_port: DestinationPort::new::<A, M>(dest_mesh.uid().clone()),
340 data,
341 })
342 }
343}
344
345#[derive(Serialize, Deserialize, Debug, Clone, Named)]
349pub(super) struct ForwardMessageV1 {
350 pub(super) dests: Vec<RoutingFrame>,
352 pub(super) message: CastMessageV1,
354}
355
356pub use hyperactor_cast::cast_actor::CAST_ORIGINATING_SENDER;
357pub use hyperactor_cast::cast_actor::CAST_POINT;
358
359pub fn set_cast_info_on_headers(headers: &mut Flattrs, cast_point: Point, sender: ActorAddr) {
360 headers.set(
365 hyperactor::mailbox::headers::SENDER_ACTOR_ID_HASH,
366 hyperactor_telemetry::hash_to_u64(sender.id()),
367 );
368 headers.set(CAST_POINT, cast_point);
369 headers.set(CAST_ORIGINATING_SENDER, sender);
370}
371
372pub trait CastInfo {
373 fn cast_point(&self) -> Point;
378 fn sender(&self) -> ActorAddr;
379}
380
381impl<A: Actor> CastInfo for Context<'_, A> {
382 fn cast_point(&self) -> Point {
383 match self.headers().get(CAST_POINT) {
384 Some(point) => point,
385 None => Extent::unity().point_of_rank(0).unwrap(),
386 }
387 }
388
389 fn sender(&self) -> ActorAddr {
390 self.headers()
391 .get(CAST_ORIGINATING_SENDER)
392 .expect("has sender header")
393 }
394}