Skip to content

Commit 5f11cd2

Browse files
committed
[hyperactor] assert_behaves!
Pull Request resolved: #1826 This adds a macro that asserts an actor's behavior; we use it to test the mesh behavior: ``` hyperactor::assert_behaves!(TestMeshController as Controller<TestMesh>); ``` It is implemented by statically validating that the actor type can bind to the defined behavior. This then provide a way to both document the intended behavior of an actor, and also to statically validate at the definition site that the behavior is implemented correctly. (We already statically validate this at the *use* site, but then the errors are already "at a distance".) ghstack-source-id: 322839082 Differential Revision: [D86786231](https://our.internmc.facebook.com/intern/diff/D86786231/) **NOTE FOR REVIEWERS**: This PR has internal Meta-specific changes or comments, please review them on [Phabricator](https://our.internmc.facebook.com/intern/diff/D86786231/)!
1 parent eb43063 commit 5f11cd2

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

hyperactor/src/actor.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,43 @@ pub trait Binds<A: Actor>: Referable {
703703
/// is handled by a specific actor type.
704704
pub trait RemoteHandles<M: RemoteMessage>: Referable {}
705705

706+
/// Check if the actor behaves-as the a given behavior (defined by [`behavior!`]).
707+
///
708+
/// ```
709+
/// # use serde::Serialize;
710+
/// # use serde::Deserialize;
711+
/// # use hyperactor::Named;
712+
///
713+
/// // First, define a behavior, based on handling a single message type `()`.
714+
/// hyperactor::behavior!(UnitBehavior, ());
715+
///
716+
/// #[derive(hyperactor::Actor, Debug, Default)]
717+
/// struct MyActor;
718+
///
719+
/// #[async_trait::async_trait]
720+
/// impl hyperactor::Handler<()> for MyActor {
721+
/// async fn handle(
722+
/// &mut self,
723+
/// _cx: &hyperactor::Context<Self>,
724+
/// _message: (),
725+
/// ) -> Result<(), anyhow::Error> {
726+
/// // no-op
727+
/// Ok(())
728+
/// }
729+
/// }
730+
///
731+
/// hyperactor::assert_behaves!(MyActor as UnitBehavior);
732+
/// ```
733+
#[macro_export]
734+
macro_rules! assert_behaves {
735+
($ty:ty as $behavior:ty) => {
736+
const _: fn() = || {
737+
fn check<B: hyperactor::actor::Binds<$ty>>() {}
738+
check::<$behavior>();
739+
};
740+
};
741+
}
742+
706743
#[cfg(test)]
707744
mod tests {
708745
use std::sync::Mutex;

hyperactor_mesh/src/resource/mesh.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ hyperactor::behavior!(
6464
#[cfg(test)]
6565
mod test {
6666
use hyperactor::Actor;
67-
use hyperactor::ActorRef;
6867
use hyperactor::Context;
6968
use hyperactor::Handler;
7069

@@ -114,14 +113,5 @@ mod test {
114113
_message: Stop => unimplemented!(),
115114
}
116115

117-
#[test]
118-
fn test_controller_behavior() {
119-
use hyperactor::ActorHandle;
120-
121-
// This is a compile-time check that TestMeshController implements
122-
// the Controller<TestMesh> behavior correctly.
123-
fn _assert_bind(handle: ActorHandle<TestMeshController>) -> ActorRef<Controller<TestMesh>> {
124-
handle.bind()
125-
}
126-
}
116+
hyperactor::assert_behaves!(TestMeshController as Controller<TestMesh>);
127117
}

0 commit comments

Comments
 (0)