Skip to content

Commit 9ebf410

Browse files
pzhan9facebook-github-bot
authored andcommitted
Change export signature (#284)
Summary: Pull Request resolved: #284 suggested by mariusae in [this comment](https://www.internalfb.com/diff/D75759809?dst_version_fbid=1389850665398938&transaction_fbid=1080308053969443). Reviewed By: mariusae Differential Revision: D76751617
1 parent 7a2da6f commit 9ebf410

File tree

22 files changed

+258
-81
lines changed

22 files changed

+258
-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: 107 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ 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;
@@ -32,6 +33,9 @@ use syn::Meta;
3233
use syn::MetaNameValue;
3334
use syn::Token;
3435
use syn::Type;
36+
use syn::bracketed;
37+
use syn::parse::Parse;
38+
use syn::parse::ParseStream;
3539
use syn::parse_macro_input;
3640
use syn::punctuated::Punctuated;
3741
use syn::spanned::Spanned;
@@ -443,7 +447,12 @@ fn parse_message_enum(input: DeriveInput) -> Result<Vec<Message>, syn::Error> {
443447
///
444448
/// // Define an actor.
445449
/// #[derive(Debug)]
446-
/// #[hyperactor::export_spawn(ShoppingList)]
450+
/// #[hyperactor::export(
451+
/// spawn = true,
452+
/// handlers = [
453+
/// ShoppingList,
454+
/// ],
455+
/// )]
447456
/// struct ShoppingListActor(HashSet<String>);
448457
///
449458
/// #[async_trait]
@@ -1139,45 +1148,97 @@ pub fn named_derive(input: TokenStream) -> TokenStream {
11391148
TokenStream::from(expanded)
11401149
}
11411150

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))
1151+
/// Attribute Struct for [`fn export`] macro.
1152+
struct ExportAttr {
1153+
spawn: bool,
1154+
handlers: Vec<Type>,
11491155
}
11501156

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);
1157+
impl Parse for ExportAttr {
1158+
fn parse(input: ParseStream) -> syn::Result<Self> {
1159+
let mut spawn = false;
1160+
let mut handlers = vec![];
1161+
1162+
while !input.is_empty() {
1163+
let key: Ident = input.parse()?;
1164+
input.parse::<Token![=]>()?;
1165+
1166+
if key == "spawn" {
1167+
let expr: Expr = input.parse()?;
1168+
if let Expr::Lit(ExprLit {
1169+
lit: Lit::Bool(b), ..
1170+
}) = expr
1171+
{
1172+
spawn = b.value;
1173+
} else {
1174+
return Err(syn::Error::new_spanned(
1175+
expr,
1176+
"expected boolean for `spawn`",
1177+
));
1178+
}
1179+
} else if key == "handlers" {
1180+
let content;
1181+
bracketed!(content in input);
1182+
let types = content.parse_terminated(Type::parse, Token![,])?;
1183+
if types.is_empty() {
1184+
return Err(syn::Error::new_spanned(
1185+
types,
1186+
"`handlers` must include at least one type",
1187+
));
1188+
}
1189+
handlers = types.into_iter().collect();
1190+
} else {
1191+
return Err(syn::Error::new_spanned(
1192+
key,
1193+
"unexpected key in `#[export(...)]`. Only supports `spawn` and `handlers`",
1194+
));
1195+
}
11571196

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

1163-
exported
1201+
Ok(ExportAttr { spawn, handlers })
1202+
}
11641203
}
11651204

1166-
fn export_impl(which: &'static str, attr: TokenStream, input: &DeriveInput) -> TokenStream {
1205+
/// Exports handlers for this actor. The set of exported handlers
1206+
/// determine the messages that may be sent to remote references of
1207+
/// the actor ([`hyperaxtor::ActorRef`]). Only messages that implement
1208+
/// [`hyperactor::RemoteMessage`] may be exported.
1209+
///
1210+
/// Additionally, an exported actor may be remotely spawned,
1211+
/// indicated by `spawn = true`. Such actors must also ensure that
1212+
/// their parameter type implements [`hyperactor::RemoteMessage`].
1213+
///
1214+
/// # Example
1215+
///
1216+
/// In the following example, `MyActor` can be spawned remotely. It also has
1217+
/// exports handlers for two message types, `MyMessage` and `MyOtherMessage`.
1218+
/// Consequently, `ActorRef`s of the actor's type may dispatch messages of these
1219+
/// types.
1220+
///
1221+
/// ```ignore
1222+
/// #[export(
1223+
/// spawn = true,
1224+
/// handlers = [
1225+
/// MyMessage,
1226+
/// MyOtherMessage,
1227+
/// ],
1228+
/// )]
1229+
/// struct MyActor {}
1230+
/// ```
1231+
#[proc_macro_attribute]
1232+
pub fn export(attr: TokenStream, item: TokenStream) -> TokenStream {
1233+
let input: DeriveInput = parse_macro_input!(item as DeriveInput);
11671234
let data_type_name = &input.ident;
11681235

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-
}
1236+
let ExportAttr { spawn, handlers } = parse_macro_input!(attr as ExportAttr);
11761237

11771238
let mut handles = Vec::new();
11781239
let mut bindings = Vec::new();
11791240

1180-
for ty in &attr_args {
1241+
for ty in &handlers {
11811242
handles.push(quote! {
11821243
impl hyperactor::actor::RemoteHandles<#ty> for #data_type_name {}
11831244
});
@@ -1186,26 +1247,33 @@ fn export_impl(which: &'static str, attr: TokenStream, input: &DeriveInput) -> T
11861247
});
11871248
}
11881249

1189-
let expanded = quote! {
1190-
#input
1250+
let mut expanded = quote! {
1251+
#input
11911252

1192-
impl hyperactor::actor::RemoteActor for #data_type_name {}
1253+
impl hyperactor::actor::RemoteActor for #data_type_name {}
11931254

1194-
#(#handles)*
1255+
#(#handles)*
11951256

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

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

12051266
impl hyperactor::data::Named for #data_type_name {
12061267
fn typename() -> &'static str { concat!(std::module_path!(), "::", stringify!(#data_type_name)) }
12071268
}
12081269
};
12091270

1271+
if spawn {
1272+
expanded.extend(quote! {
1273+
1274+
hyperactor::remote!(#data_type_name);
1275+
});
1276+
}
1277+
12101278
TokenStream::from(expanded)
12111279
}

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
@@ -375,15 +375,18 @@ pub(crate) mod test_util {
375375
// 'hyperactor_mesh_test_bootstrap' for the `tests::process` actor
376376
// mesh test suite.
377377
#[derive(Debug)]
378-
#[hyperactor::export_spawn(
379-
Cast<Echo>,
380-
Cast<GetRank>,
381-
Cast<Error>,
382-
GetRank,
383-
Relay,
384-
IndexedErasedUnbound<Cast<Echo>>,
385-
IndexedErasedUnbound<Cast<GetRank>>,
386-
IndexedErasedUnbound<Cast<Error>>,
378+
#[hyperactor::export(
379+
spawn = true,
380+
handlers = [
381+
Cast<Echo>,
382+
Cast<GetRank>,
383+
Cast<Error>,
384+
GetRank,
385+
Relay,
386+
IndexedErasedUnbound<Cast<Echo>>,
387+
IndexedErasedUnbound<Cast<GetRank>>,
388+
IndexedErasedUnbound<Cast<Error>>,
389+
],
387390
)]
388391
pub struct TestActor;
389392

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>,
@@ -434,7 +441,15 @@ pub mod test_utils {
434441
}
435442

436443
#[derive(Debug)]
437-
#[hyperactor::export_spawn(TestMessage, Cast<TestMessage>, IndexedErasedUnbound<TestMessage>, IndexedErasedUnbound<Cast<TestMessage>>)]
444+
#[hyperactor::export(
445+
spawn = true,
446+
handlers = [
447+
TestMessage,
448+
Cast<TestMessage>,
449+
IndexedErasedUnbound<TestMessage>,
450+
IndexedErasedUnbound<Cast<TestMessage>>,
451+
],
452+
)]
438453
pub struct TestActor {
439454
// Forward the received message to this port, so it can be inspected by
440455
// 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)