Skip to content

Commit 8bd3038

Browse files
pzhan9facebook-github-bot
authored andcommitted
Change export signature
Differential Revision: D76751617
1 parent 5e089f2 commit 8bd3038

File tree

22 files changed

+256
-81
lines changed

22 files changed

+256
-81
lines changed

controller/src/lib.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ const CASTING_FANOUT_SIZE: usize = 8;
7474
/// compute tasks. This acts a proxy managing comms with the workers and handling things like history,
7575
/// data dependency, worker lifecycles etc for the client abstracting it away.
7676
#[derive(Debug)]
77-
#[hyperactor::export_spawn(ControllerMessage)]
77+
#[hyperactor::export(
78+
spawn = true,
79+
handlers = [
80+
ControllerMessage,
81+
],
82+
)]
7883
pub(crate) struct ControllerActor {
7984
client_actor_ref: OnceCell<ActorRef<ClientActor>>,
8085
comm_actor_ref: ActorRef<CommActor>,
@@ -1772,7 +1777,11 @@ mod tests {
17721777
}
17731778

17741779
#[derive(Debug)]
1775-
#[hyperactor::export(PanickingMessage)]
1780+
#[hyperactor::export(
1781+
handlers = [
1782+
PanickingMessage,
1783+
],
1784+
)]
17761785
struct PanickingActor;
17771786

17781787
#[async_trait]

hyper/src/commands/demo.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,12 @@ enum DemoMessage {
207207
}
208208

209209
#[derive(Debug)]
210-
#[hyperactor::export_spawn(DemoMessage)]
210+
#[hyperactor::export(
211+
spawn = true,
212+
handlers = [
213+
DemoMessage,
214+
],
215+
)]
211216
struct DemoActor;
212217

213218
#[async_trait]

hyperactor/example/derive.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ enum ShoppingList {
3636

3737
// Define an actor.
3838
#[derive(Debug)]
39-
#[hyperactor::export_spawn(ShoppingList)]
39+
#[hyperactor::export(
40+
spawn = true,
41+
handlers = [
42+
ShoppingList,
43+
],
44+
)]
4045
struct ShoppingListActor(HashSet<String>);
4146

4247
#[async_trait]

hyperactor/src/actor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ mod tests {
10051005
impl MultiValuesTest {}
10061006

10071007
#[derive(Debug)]
1008-
#[hyperactor::export(u64, String)]
1008+
#[hyperactor::export(handlers = [u64, String])]
10091009
struct MultiActor(MultiValues);
10101010

10111011
#[async_trait]

hyperactor/src/actor/remote.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ mod tests {
143143
use crate::Instance;
144144

145145
#[derive(Debug)]
146-
#[hyperactor::export(())]
146+
#[hyperactor::export(handlers = [()])]
147147
struct MyActor;
148148

149149
#[async_trait]

hyperactor/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ pub use hyperactor_macros::RefClient;
116116
#[doc(inline)]
117117
pub use hyperactor_macros::export;
118118
#[doc(inline)]
119-
pub use hyperactor_macros::export_spawn;
120-
#[doc(inline)]
121119
pub use hyperactor_macros::forward;
122120
#[doc(inline)]
123121
pub use hyperactor_macros::instrument;

hyperactor/src/test_utils/pingpong.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl PingPongActorParams {
6464

6565
/// A PingPong actor that can play the PingPong game by sending messages around.
6666
#[derive(Debug)]
67-
#[hyperactor::export(PingPongMessage)]
67+
#[hyperactor::export(handlers = [PingPongMessage])]
6868
pub struct PingPongActor {
6969
params: PingPongActorParams,
7070
}

hyperactor_macros/src/lib.rs

Lines changed: 105 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,24 @@ use syn::Data;
2222
use syn::DataEnum;
2323
use syn::DeriveInput;
2424
use syn::Expr;
25+
use syn::ExprLit;
2526
use syn::Field;
2627
use syn::Fields;
2728
use syn::Ident;
29+
use syn::Item;
30+
use syn::ItemEnum;
2831
use syn::ItemFn;
2932
use syn::ItemImpl;
33+
use syn::ItemStruct;
3034
use syn::Lit;
3135
use syn::Meta;
3236
use syn::MetaNameValue;
37+
use syn::PatLit;
3338
use syn::Token;
3439
use syn::Type;
40+
use syn::bracketed;
41+
use syn::parse::Parse;
42+
use syn::parse::ParseStream;
3543
use syn::parse_macro_input;
3644
use syn::punctuated::Punctuated;
3745
use syn::spanned::Spanned;
@@ -443,7 +451,12 @@ fn parse_message_enum(input: DeriveInput) -> Result<Vec<Message>, syn::Error> {
443451
///
444452
/// // Define an actor.
445453
/// #[derive(Debug)]
446-
/// #[hyperactor::export_spawn(ShoppingList)]
454+
/// #[hyperactor::export(
455+
/// spawn = true,
456+
/// handlers = [
457+
/// ShoppingList,
458+
/// ],
459+
/// )]
447460
/// struct ShoppingListActor(HashSet<String>);
448461
///
449462
/// #[async_trait]
@@ -1139,45 +1152,91 @@ pub fn named_derive(input: TokenStream) -> TokenStream {
11391152
TokenStream::from(expanded)
11401153
}
11411154

1142-
/// Exports an actor so that it may be bound to [`hyperactor::ActorRef`]s.
1143-
///
1144-
/// The macro must be provided with the set of types that are exported, and
1145-
/// which may therefore be dispatched through references to the actor.
1146-
#[proc_macro_attribute]
1147-
pub fn export(attr: TokenStream, item: TokenStream) -> TokenStream {
1148-
export_impl("export", attr, &parse_macro_input!(item as DeriveInput))
1155+
/// Attribute Struct for [`fn export`] macro.
1156+
struct ExportAttr {
1157+
spawn: bool,
1158+
handlers: Vec<Type>,
11491159
}
11501160

1151-
/// A version of [`export`] which also makes the actor remotely spawnable.
1152-
#[proc_macro_attribute]
1153-
pub fn export_spawn(attr: TokenStream, item: TokenStream) -> TokenStream {
1154-
let input: DeriveInput = parse_macro_input!(item as DeriveInput);
1155-
1156-
let mut exported = export_impl("export_spawn", attr, &input);
1161+
impl Parse for ExportAttr {
1162+
fn parse(input: ParseStream) -> syn::Result<Self> {
1163+
let mut spawn = false;
1164+
let mut handlers = vec![];
1165+
1166+
while !input.is_empty() {
1167+
let key: Ident = input.parse()?;
1168+
input.parse::<Token![=]>()?;
1169+
1170+
if key == "spawn" {
1171+
let expr: Expr = input.parse()?;
1172+
if let Expr::Lit(ExprLit {
1173+
lit: Lit::Bool(b), ..
1174+
}) = expr
1175+
{
1176+
spawn = b.value;
1177+
} else {
1178+
return Err(syn::Error::new_spanned(
1179+
expr,
1180+
"expected boolean for `spawn`",
1181+
));
1182+
}
1183+
} else if key == "handlers" {
1184+
let content;
1185+
bracketed!(content in input);
1186+
let types = content.parse_terminated(Type::parse, Token![,])?;
1187+
if types.is_empty() {
1188+
return Err(syn::Error::new_spanned(
1189+
types,
1190+
"`handlers` must include at least one type",
1191+
));
1192+
}
1193+
handlers = types.into_iter().collect();
1194+
} else {
1195+
return Err(syn::Error::new_spanned(
1196+
key,
1197+
"unexpected key in `#[export(...)]`. Only supports `spawn` and `handlers`",
1198+
));
1199+
}
11571200

1158-
let data_type_name = &input.ident;
1159-
exported.extend(TokenStream::from(quote! {
1160-
hyperactor::remote!(#data_type_name);
1161-
}));
1201+
// optional trailing comma
1202+
let _ = input.parse::<Token![,]>();
1203+
}
11621204

1163-
exported
1205+
Ok(ExportAttr { spawn, handlers })
1206+
}
11641207
}
11651208

1166-
fn export_impl(which: &'static str, attr: TokenStream, input: &DeriveInput) -> TokenStream {
1209+
/// Exports an actor so that
1210+
/// 1. it may be bound to [`hyperactor::ActorRef`]s for message types specified
1211+
/// in the `handlers` attribute;
1212+
/// 2. it may be spawned as a [`hyperactor::ActorHandle`], if the optional
1213+
/// `spawn` attribute is set to `true`.
1214+
///
1215+
/// # Example
1216+
///
1217+
/// In the following example, `MyActor` can be spawned remotely. It also has two
1218+
/// message types, `MyMessage` and `MyOtherMessage`, which can be bound to
1219+
/// `ActorRef`.
1220+
/// ```ignore
1221+
/// #[export(
1222+
/// spawn = true,
1223+
/// handlers = [
1224+
/// MyMessage,
1225+
/// MyOtherMessage],
1226+
/// )]
1227+
/// struct MyActor {}
1228+
/// ```
1229+
#[proc_macro_attribute]
1230+
pub fn export(attr: TokenStream, item: TokenStream) -> TokenStream {
1231+
let input: DeriveInput = parse_macro_input!(item as DeriveInput);
11671232
let data_type_name = &input.ident;
11681233

1169-
let attr_args =
1170-
parse_macro_input!(attr with Punctuated::<syn::Type, Token![,]>::parse_terminated);
1171-
if attr_args.is_empty() {
1172-
return TokenStream::from(
1173-
syn::Error::new_spanned(attr_args, format!("`{}` expects one or more type path arguments\n\n= help: use `#[{}(MyType, MyOtherType<T>)]`", which, which)).to_compile_error(),
1174-
);
1175-
}
1234+
let ExportAttr { spawn, handlers } = parse_macro_input!(attr as ExportAttr);
11761235

11771236
let mut handles = Vec::new();
11781237
let mut bindings = Vec::new();
11791238

1180-
for ty in &attr_args {
1239+
for ty in &handlers {
11811240
handles.push(quote! {
11821241
impl hyperactor::actor::RemoteHandles<#ty> for #data_type_name {}
11831242
});
@@ -1186,26 +1245,33 @@ fn export_impl(which: &'static str, attr: TokenStream, input: &DeriveInput) -> T
11861245
});
11871246
}
11881247

1189-
let expanded = quote! {
1190-
#input
1248+
let mut expanded = quote! {
1249+
#input
11911250

1192-
impl hyperactor::actor::RemoteActor for #data_type_name {}
1251+
impl hyperactor::actor::RemoteActor for #data_type_name {}
11931252

1194-
#(#handles)*
1253+
#(#handles)*
11951254

1196-
// Always export the `Signal` type.
1197-
impl hyperactor::actor::RemoteHandles<hyperactor::actor::Signal> for #data_type_name {}
1255+
// Always export the `Signal` type.
1256+
impl hyperactor::actor::RemoteHandles<hyperactor::actor::Signal> for #data_type_name {}
11981257

1199-
impl hyperactor::actor::Binds<#data_type_name> for #data_type_name {
1200-
fn bind(ports: &hyperactor::proc::Ports<Self>) {
1201-
#(#bindings)*
1202-
}
1203-
}
1258+
impl hyperactor::actor::Binds<#data_type_name> for #data_type_name {
1259+
fn bind(ports: &hyperactor::proc::Ports<Self>) {
1260+
#(#bindings)*
1261+
}
1262+
}
12041263

12051264
impl hyperactor::data::Named for #data_type_name {
12061265
fn typename() -> &'static str { concat!(std::module_path!(), "::", stringify!(#data_type_name)) }
12071266
}
12081267
};
12091268

1269+
if spawn {
1270+
expanded.extend(quote! {
1271+
1272+
hyperactor::remote!(#data_type_name);
1273+
});
1274+
}
1275+
12101276
TokenStream::from(expanded)
12111277
}

hyperactor_macros/tests/export.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use serde::Deserialize;
1818
use crate::Serialize;
1919

2020
#[derive(Debug)]
21-
#[hyperactor::export(TestMessage, (), MyGeneric<()>)]
21+
#[hyperactor::export(handlers = [TestMessage, (), MyGeneric<()>,])]
2222
struct TestActor {
2323
// Forward the received message to this port, so it can be inspected by
2424
// the unit test.

hyperactor_mesh/examples/dining_philosophers.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,12 @@ enum ChopstickStatus {
4747
}
4848

4949
#[derive(Debug)]
50-
#[hyperactor::export_spawn(
51-
Cast<PhilosopherMessage>,
52-
IndexedErasedUnbound<Cast<PhilosopherMessage>>,
50+
#[hyperactor::export(
51+
spawn = true,
52+
handlers = [
53+
Cast<PhilosopherMessage>,
54+
IndexedErasedUnbound<Cast<PhilosopherMessage>>,
55+
],
5356
)]
5457
struct PhilosopherActor {
5558
/// Status of left and right chopsticks

hyperactor_mesh/src/actor_mesh.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -372,15 +372,18 @@ pub(crate) mod test_util {
372372
// 'hyperactor_mesh_test_bootstrap' for the `tests::process` actor
373373
// mesh test suite.
374374
#[derive(Debug)]
375-
#[hyperactor::export_spawn(
376-
Cast<Echo>,
377-
Cast<GetRank>,
378-
Cast<Error>,
379-
GetRank,
380-
Relay,
381-
IndexedErasedUnbound<Cast<Echo>>,
382-
IndexedErasedUnbound<Cast<GetRank>>,
383-
IndexedErasedUnbound<Cast<Error>>,
375+
#[hyperactor::export(
376+
spawn = true,
377+
handlers = [
378+
Cast<Echo>,
379+
Cast<GetRank>,
380+
Cast<Error>,
381+
GetRank,
382+
Relay,
383+
IndexedErasedUnbound<Cast<Echo>>,
384+
IndexedErasedUnbound<Cast<GetRank>>,
385+
IndexedErasedUnbound<Cast<Error>>,
386+
],
384387
)]
385388
pub struct TestActor;
386389

hyperactor_mesh/src/comm/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,14 @@ struct ReceiveState {
6666
/// This is the comm actor used for efficient and scalable message multicasting
6767
/// and result accumulation.
6868
#[derive(Debug)]
69-
#[hyperactor::export_spawn(CommActorMode, CastMessage, ForwardMessage)]
69+
#[hyperactor::export(
70+
spawn = true,
71+
handlers = [
72+
CommActorMode,
73+
CastMessage,
74+
ForwardMessage,
75+
],
76+
)]
7077
pub struct CommActor {
7178
/// Each world will use its own seq num from this caster.
7279
send_seq: HashMap<Slice, usize>,
@@ -444,7 +451,15 @@ pub mod test_utils {
444451
}
445452

446453
#[derive(Debug)]
447-
#[hyperactor::export_spawn(TestMessage, Cast<TestMessage>, IndexedErasedUnbound<TestMessage>, IndexedErasedUnbound<Cast<TestMessage>>)]
454+
#[hyperactor::export(
455+
spawn = true,
456+
handlers = [
457+
TestMessage,
458+
Cast<TestMessage>,
459+
IndexedErasedUnbound<TestMessage>,
460+
IndexedErasedUnbound<Cast<TestMessage>>,
461+
],
462+
)]
448463
pub struct TestActor {
449464
// Forward the received message to this port, so it can be inspected by
450465
// the unit test.

hyperactor_mesh/src/proc_mesh/mesh_agent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub(crate) enum MeshAgentMessage {
8888

8989
/// A mesh agent is responsible for managing procs in a [`ProcMesh`].
9090
#[derive(Debug)]
91-
#[hyperactor::export(MeshAgentMessage)]
91+
#[hyperactor::export(handlers=[MeshAgentMessage])]
9292
pub struct MeshAgent {
9393
proc: Proc,
9494
remote: Remote,

0 commit comments

Comments
 (0)