11/// Constructs an envelope enumeration that contains all messages for an actor.
22///
3+ /// # Usage
4+ ///
5+ /// Basic usage (no shutdown support):
6+ /// ```ignore
7+ /// actor_envelope! {
8+ /// MyEnvelope,
9+ /// MyActor,
10+ /// MyRecorder,
11+ /// Message1 => Msg1Type,
12+ /// Message2 => Msg2Type,
13+ /// }
14+ /// ```
15+ ///
16+ /// With shutdown support (actor must implement `Shutdown` trait):
17+ /// ```ignore
18+ /// actor_envelope! {
19+ /// MyEnvelope,
20+ /// MyActor,
21+ /// MyRecorder,
22+ /// with_shutdown,
23+ /// Message1 => Msg1Type,
24+ /// Message2 => Msg2Type,
25+ /// }
26+ /// ```
27+ ///
328/// The first identifier is the name of the enum.
429/// The second identifier is the name of a trait specific to the actor.
530/// The third identifier is the name of a trait for recording message events.
31+ /// Optional `with_shutdown` parameter adds shutdown support for actors that implement the Shutdown trait.
632/// The remaining pairs are the variants of the envelope indicating the messages the actor handles.
733///
834/// The constructed actor trait is a union of the [`crate::Handler`] traits for each message along with the [`crate::Actor`] trait.
935///
1036/// The constructed recorder trait is a union of the [`ceramic_metrics::Recorder`] traits for each message.
1137#[ macro_export]
1238macro_rules! actor_envelope {
39+ // Version with shutdown support
40+ (
41+ $enum_name: ident,
42+ $actor_trait: ident,
43+ $recorder_trait: ident,
44+ with_shutdown,
45+ $(
46+ $variant_name: ident => $message_type: ty,
47+ ) *
48+ ) => {
49+ $crate:: actor_envelope_impl!( $enum_name, $actor_trait, $recorder_trait, with_shutdown, $( $variant_name => $message_type, ) * ) ;
50+ } ;
51+
52+ // Default version without shutdown
53+ (
54+ $enum_name: ident,
55+ $actor_trait: ident,
56+ $recorder_trait: ident,
57+ $(
58+ $variant_name: ident => $message_type: ty,
59+ ) *
60+ ) => {
61+ $crate:: actor_envelope_impl!( $enum_name, $actor_trait, $recorder_trait, without_shutdown, $( $variant_name => $message_type, ) * ) ;
62+ } ;
63+ }
64+
65+ /// Internal implementation macro that handles both with/without shutdown cases
66+ #[ macro_export]
67+ macro_rules! actor_envelope_impl {
1368 (
1469 $enum_name: ident,
1570 $actor_trait: ident,
1671 $recorder_trait: ident,
72+ $shutdown_mode: ident,
1773 $(
1874 $variant_name: ident => $message_type: ty,
1975 ) *
@@ -51,11 +107,7 @@ macro_rules! actor_envelope {
51107 }
52108 }
53109 }
54- #[ doc = std:: stringify!( $actor_trait) ]
55- #[ doc = " is an [`ceramic_actor::Actor`] and [`ceramic_actor::Handler`] for each message type in the actor envelope " ]
56- #[ doc = stringify!( $enum_name) ]
57- #[ doc = "." ]
58- pub trait $actor_trait : $crate:: Actor <Envelope = $enum_name> $( + $crate:: Handler <$message_type> ) * + :: std:: marker:: Send + ' static { }
110+ $crate:: actor_trait_def!( $actor_trait, $enum_name, $shutdown_mode, $( $message_type, ) * ) ;
59111
60112 #[ doc = std:: stringify!( $recorder_trait) ]
61113 #[ doc = " is an [`ceramic_metrics::Recorder`] for each message type in the actor envelope " ]
@@ -64,6 +116,7 @@ macro_rules! actor_envelope {
64116 pub trait $recorder_trait : $( :: ceramic_metrics:: Recorder <$crate:: MessageEvent <$message_type>> +) *
65117 :: std:: fmt:: Debug + :: std:: marker:: Send + :: std:: marker:: Sync + ' static { }
66118
119+
67120 impl $enum_name {
68121 /// Runs the actor handling messages as they arrive.
69122 pub async fn run<A >( mut actor: A , mut receiver: $crate:: Receiver <A :: Envelope >, mut shutdown: impl :: std:: future:: Future <Output =( ) > + :: std:: marker:: Send + ' static )
@@ -111,6 +164,7 @@ macro_rules! actor_envelope {
111164 }
112165 }
113166 }
167+ $crate:: actor_shutdown_call!( $shutdown_mode, actor) ;
114168 }
115169 }
116170 $(
@@ -132,3 +186,33 @@ macro_rules! actor_envelope {
132186 ) *
133187 } ;
134188}
189+
190+ /// Helper macro to define actor trait with or without shutdown requirement
191+ #[ macro_export]
192+ macro_rules! actor_trait_def {
193+ ( $actor_trait: ident, $enum_name: ident, with_shutdown, $( $message_type: ty, ) * ) => {
194+ #[ doc = std:: stringify!( $actor_trait) ]
195+ #[ doc = " is an [`ceramic_actor::Actor`] and [`ceramic_actor::Handler`] for each message type in the actor envelope " ]
196+ #[ doc = stringify!( $enum_name) ]
197+ #[ doc = ". This actor must also implement [`ceramic_actor::Shutdown`]." ]
198+ pub trait $actor_trait : $crate:: Actor <Envelope = $enum_name> $( + $crate:: Handler <$message_type> ) * + $crate:: Shutdown + :: std:: marker:: Send + ' static { }
199+ } ;
200+ ( $actor_trait: ident, $enum_name: ident, without_shutdown, $( $message_type: ty, ) * ) => {
201+ #[ doc = std:: stringify!( $actor_trait) ]
202+ #[ doc = " is an [`ceramic_actor::Actor`] and [`ceramic_actor::Handler`] for each message type in the actor envelope " ]
203+ #[ doc = stringify!( $enum_name) ]
204+ #[ doc = "." ]
205+ pub trait $actor_trait : $crate:: Actor <Envelope = $enum_name> $( + $crate:: Handler <$message_type> ) * + :: std:: marker:: Send + ' static { }
206+ } ;
207+ }
208+
209+ /// Helper macro to conditionally call shutdown
210+ #[ macro_export]
211+ macro_rules! actor_shutdown_call {
212+ ( with_shutdown, $actor: ident) => {
213+ $actor. shutdown( ) . await ;
214+ } ;
215+ ( without_shutdown, $actor: ident) => {
216+ // No shutdown call for actors that don't implement shutdown
217+ } ;
218+ }
0 commit comments