Skip to main content

magicstatemachines/macros/
state_machine_impl.rs

1/// Connects a runtime type to a state-machine definition and generates its effects.
2///
3/// Invoke this macro in the implementation crate, in the same module as the
4/// runtime type's state-specific methods. It implements
5/// [`StateMachineImpl`](trait@crate::StateMachineImpl), creates a private
6/// transition token, and emits module-local extension traits consumed by
7/// [`transition!`](macro@crate::transition). Keeping the token private is what
8/// prevents callers from retagging states directly.
9///
10/// Transition headers must match transitions declared by
11/// [`StateMachineDefinition!`](macro@crate::StateMachineDefinition). The
12/// definition macro proves that an edge is legal; this macro decides what
13/// effect runs when that edge is taken for a particular runtime type. In this
14/// macro, headers may also carry implementation bodies:
15///
16/// - `;` means the transition has no effect body. The runtime value is only
17///   retagged from `From` to `To`.
18/// - `{ ... }` runs the body against a mutable runtime value before retagging.
19///   Inside the body, `self` refers to `&mut Runtime`, not to the state token.
20/// - `,` after a header queues that header and shares the next body with it.
21///   This is not punctuation sugar. It records that those transition edges use
22///   the same effect type. Static union transitions depend on that fact:
23///   `transition!(const Online self)` only compiles when every concrete member
24///   uses the same body and signature for the chosen target.
25/// - `pinned transition From => To(...) { ... }` declares an effect that runs
26///   with `self` bound to `Pin<&mut Runtime>` instead of `&mut Runtime`. Call
27///   it with [`transition!(pin state, ...)`](macro@crate::transition) from a
28///   method whose storage is bounded by `S: SPinMut`. This is the form to use
29///   when the runtime is `!Unpin` and the effect must call pinned methods or
30///   update fields through interior mutability without ever exposing `&mut T`.
31///   Pinned and ordinary effects are separate contracts, so the same
32///   `From => To` edge may have both a normal body and a pinned body. The call
33///   form decides which one is used.
34///
35/// The macro intentionally generates awkward hidden helper names such as
36/// `_magicsm_transition`, `_magicsm_transitionConst`, `_magicsm_transitionDyn`,
37/// `_magicsm_transitionPin`, `_magicsm_transitionPinConst`, and
38/// `_magicsm_transitionPinDyn`. User code should call them through
39/// [`transition!`](macro@crate::transition), which keeps transition calls
40/// uniform and prevents method-name collisions with normal implementation
41/// methods.
42///
43/// A typical implementation keeps the public methods ordinary Rust methods and
44/// uses `State<Storage, Self, StateMarker>` as the receiver. The storage bound
45/// documents what the method needs: `SRef` for reading, `SMut` for mutation and
46/// transitions, and `SMove` when a backend must be movable by value.
47///
48/// ```ignore
49/// use magicstatemachines::{transition, SMut, State, StateMachineImpl};
50/// use test_def::{ConnectionStandin, InOnline, Online};
51/// use test_def::states::{Authenticated, Connected, Disconnected};
52///
53/// pub struct Connection {
54///     user: Option<String>,
55/// }
56///
57/// StateMachineImpl! {
58///     Connection: ConnectionStandin;
59///
60///     transition Disconnected => Connected();
61///
62///     transition Connected => Authenticated(user: String) {
63///         self.user = Some(user);
64///     }
65///
66///     transition Connected | Authenticated => Disconnected(),
67///     transition Authenticated => Connected() {
68///         self.user = None;
69///     }
70/// }
71///
72/// impl Connection {
73///     pub fn connect<S>(self: State<S, Self, Disconnected>) -> State<S, Self, Connected>
74///     where
75///         S: SMut,
76///     {
77///         transition!(self)
78///     }
79///
80///     pub fn authenticate<S>(
81///         self: State<S, Self, Connected>,
82///         user: impl Into<String>,
83///     ) -> State<S, Self, Authenticated>
84///     where
85///         S: SMut,
86///     {
87///         transition!(self, user.into())
88///     }
89///
90///     pub fn disconnect<S>(self: State<S, Self, impl InOnline>) -> State<S, Self, Disconnected>
91///     where
92///         S: SMut,
93///     {
94///         transition!(dyn Online self)
95///     }
96/// }
97/// ```
98///
99/// In the example, the two `=> Disconnected` headers share the same body, so
100/// either `transition!(const Online self)` or `transition!(dyn Online self)`
101/// can be used. If `Connected => Disconnected` and
102/// `Authenticated => Disconnected` had different bodies, the static form would
103/// stop compiling and the dynamic form would remain valid by discriminating the
104/// concrete runtime state first.
105///
106/// Use the static form when the union proof is part of the API contract:
107///
108/// ```ignore
109/// fn disconnect<S>(self: State<S, Self, impl InOnline>) -> State<S, Self, Disconnected>
110/// where
111///     S: SMut,
112/// {
113///     transition!(const Online self)
114/// }
115/// ```
116///
117/// Use the dynamic form when the body may differ per member, or when the value
118/// is already stored as a discriminated union state:
119///
120/// ```ignore
121/// fn stop<S>(self: State<S, Self, impl InOnline>) -> State<S, Self, Disconnected>
122/// where
123///     S: SMut,
124/// {
125///     transition!(dyn Online self,)
126/// }
127/// ```
128///
129/// Pinned transitions are intentionally separate from ordinary transitions.
130/// `SPinBox<T, S>` does not implement `SMut` for `T: !Unpin`, so a normal
131/// body cannot accidentally receive `&mut T`. The pinned body receives
132/// `Pin<&mut T>` and the method advertises that by requiring `S: SPinMut`:
133///
134/// ```ignore
135/// use core::{cell::Cell, marker::PhantomPinned, pin::Pin};
136/// use magicstatemachines::{transition, SPinMut, State};
137///
138/// struct Connection {
139///     ready: Cell<bool>,
140///     _pin: PhantomPinned,
141/// }
142///
143/// impl Connection {
144///     fn mark_ready(self: Pin<&mut Self>) {
145///         self.as_ref().get_ref().ready.set(true);
146///     }
147/// }
148///
149/// StateMachineImpl! {
150///     Connection: ConnectionStandin;
151///
152///     pinned transition Disconnected => Connected() {
153///         self.as_mut().mark_ready();
154///     }
155/// }
156///
157/// impl Connection {
158///     fn connect<S>(self: State<S, Self, Disconnected>) -> State<S, Self, Connected>
159///     where
160///         S: SPinMut,
161///     {
162///         transition!(pin self)
163///     }
164/// }
165/// ```
166///
167/// If an edge can be used from both movable and pinned storage, define both
168/// bodies. The state-machine definition still has only one edge; the
169/// implementation macro records two effects for that edge:
170///
171/// ```ignore
172/// StateMachineImpl! {
173///     Connection: ConnectionStandin;
174///
175///     transition Disconnected => Connected() {
176///         self.connected = true;
177///     }
178///
179///     pinned transition Disconnected => Connected() {
180///         self.as_ref().connected.set(true);
181///     }
182/// }
183///
184/// impl Connection {
185///     fn connect<S>(self: State<S, Self, Disconnected>) -> State<S, Self, Connected>
186///     where
187///         S: SMut,
188///     {
189///         transition!(self)
190///     }
191///
192///     fn connect_pinned<S>(self: State<S, Self, Disconnected>) -> State<S, Self, Connected>
193///     where
194///         S: SPinMut,
195///     {
196///         transition!(pin self)
197///     }
198/// }
199/// ```
200///
201/// Pinned transitions also have static and dynamic union forms. Use
202/// `transition!(pin const Online self)` when every member of the union shares
203/// the same pinned body and signature for the selected target. Use
204/// `transition!(pin dyn Online self)` when the current concrete member should
205/// be discriminated first and each member's own pinned body should run.
206#[macro_export]
207macro_rules! StateMachineImpl {
208    (
209        $implementation:ty : $standin:ty;
210        $($transitions:tt)*
211    ) => {
212        #[doc(hidden)]
213        pub struct __StateMachineTransitionToken(());
214
215        impl $crate::StateMachineImpl for $implementation {
216            type Standin = $standin;
217            type Impl = $implementation;
218            type TransitionToken = __StateMachineTransitionToken;
219        }
220
221        $crate::__StateMachineImpl!(
222            @parse $implementation; $standin; [];
223            $($transitions)*
224        );
225
226        #[doc(hidden)]
227        pub struct __StateMachineUnionTransitionEffect<Marker, To>(
228            ::core::marker::PhantomData<fn() -> (Marker, To)>,
229        );
230
231        impl<Marker, To> $crate::TransitionEffectSelector<$crate::StateUnionState<Marker>, To>
232            for $implementation
233        where
234            Marker: $crate::StateUnionSharedEffect<$implementation, To>,
235            To: $crate::ConcreteStateTrait,
236        {
237            type Effect = __StateMachineUnionTransitionEffect<Marker, To>;
238        }
239
240        impl<Marker, To, Args> $crate::TransitionEffect<
241            $implementation,
242            $crate::StateUnionState<Marker>,
243            To,
244            Args,
245        > for __StateMachineUnionTransitionEffect<Marker, To>
246        where
247            Marker: $crate::StateUnionSharedTransitionEffect<$implementation, To, Args>,
248            To: $crate::ConcreteStateTrait,
249        {
250            fn apply(value: &mut $implementation, args: Args) {
251                <Marker as $crate::StateUnionSharedTransitionEffect<
252                    $implementation,
253                    To,
254                    Args,
255                >>::apply(value, args);
256            }
257        }
258
259        #[allow(dead_code)]
260        trait __GenericStateTransitionExt<Storage, From>
261        where
262            Storage: $crate::StateStorage,
263        {
264            #[must_use]
265            #[track_caller]
266            fn _magicsm_transition<To>(
267                self,
268            ) -> $crate::EffectTransitionCall<
269                Storage,
270                $implementation,
271                From,
272                To,
273                <$implementation as $crate::TransitionEffectSelector<From, To>>::Effect,
274            >
275            where
276                From: $crate::StateTrait,
277                To: $crate::ConcreteStateTrait,
278                From: $crate::StateUnionConcreteState,
279                $standin: $crate::Transition<From, To>,
280                $implementation: $crate::TransitionEffectSelector<From, To>;
281
282        }
283
284        impl<Storage, From> __GenericStateTransitionExt<Storage, From>
285            for $crate::State<Storage, $implementation, From>
286        where
287            Storage: $crate::StateStorage,
288            Storage::Machine<$implementation>: $crate::StateMachineImpl<
289                    Standin = $standin,
290                    Impl = $implementation,
291                    TransitionToken = __StateMachineTransitionToken,
292                >,
293        {
294            #[track_caller]
295            fn _magicsm_transition<To>(
296                self,
297            ) -> $crate::EffectTransitionCall<
298                Storage,
299                $implementation,
300                From,
301                To,
302                <$implementation as $crate::TransitionEffectSelector<From, To>>::Effect,
303            >
304            where
305                From: $crate::StateTrait,
306                To: $crate::ConcreteStateTrait,
307                From: $crate::StateUnionConcreteState,
308                $standin: $crate::Transition<From, To>,
309                $implementation: $crate::TransitionEffectSelector<From, To>,
310            {
311                $crate::transition_state_with_effect(self, __StateMachineTransitionToken(()))
312            }
313
314        }
315
316        #[allow(dead_code, non_snake_case)]
317        trait __GenericStatePinnedTransitionExt<Storage, From>
318        where
319            Storage: $crate::StateStorage,
320        {
321            #[allow(non_snake_case)]
322            #[must_use]
323            #[track_caller]
324            fn _magicsm_transitionPin<To>(
325                self,
326            ) -> $crate::PinnedEffectTransitionCall<
327                Storage,
328                $implementation,
329                From,
330                To,
331                <$implementation as $crate::PinnedTransitionEffectSelector<From, To>>::Effect,
332            >
333            where
334                From: $crate::StateTrait,
335                To: $crate::ConcreteStateTrait,
336                From: $crate::StateUnionConcreteState,
337                $standin: $crate::Transition<From, To>,
338                $implementation: $crate::PinnedTransitionEffectSelector<From, To>;
339
340        }
341
342        impl<Storage, From> __GenericStatePinnedTransitionExt<Storage, From>
343            for $crate::State<Storage, $implementation, From>
344        where
345            Storage: $crate::StateStorage,
346            Storage::Machine<$implementation>: $crate::StateMachineImpl<
347                    Standin = $standin,
348                    Impl = $implementation,
349                    TransitionToken = __StateMachineTransitionToken,
350                >,
351        {
352            #[allow(non_snake_case)]
353            #[track_caller]
354            fn _magicsm_transitionPin<To>(
355                self,
356            ) -> $crate::PinnedEffectTransitionCall<
357                Storage,
358                $implementation,
359                From,
360                To,
361                <$implementation as $crate::PinnedTransitionEffectSelector<From, To>>::Effect,
362            >
363            where
364                From: $crate::StateTrait,
365                To: $crate::ConcreteStateTrait,
366                From: $crate::StateUnionConcreteState,
367                $standin: $crate::Transition<From, To>,
368                $implementation: $crate::PinnedTransitionEffectSelector<From, To>,
369            {
370                $crate::transition_state_with_pinned_effect(self, __StateMachineTransitionToken(()))
371            }
372
373        }
374
375        #[allow(dead_code, non_snake_case)]
376        trait __GenericStateMarkerPinnedTransitionExt<Storage, From>
377        where
378            Storage: $crate::StateStorage,
379        {
380            #[allow(non_snake_case)]
381            #[track_caller]
382            fn _magicsm_transitionPinDyn<Marker, To>(
383                self,
384                _marker: Marker,
385            ) -> $crate::PinnedDiscriminatedTransitionCall<
386                Storage,
387                $implementation,
388                Marker,
389                To,
390            >
391            where
392                From: $crate::StateTrait + $crate::In<Marker>,
393                Marker: $crate::StateUnionDiscriminant,
394                To: $crate::ConcreteStateTrait;
395        }
396
397        impl<Storage, From> __GenericStateMarkerPinnedTransitionExt<Storage, From>
398            for $crate::State<Storage, $implementation, From>
399        where
400            Storage: $crate::StateStorage,
401            Storage::Machine<$implementation>: $crate::StateMachineImpl<
402                    Standin = $standin,
403                    Impl = $implementation,
404                    TransitionToken = __StateMachineTransitionToken,
405                >,
406        {
407            #[allow(non_snake_case)]
408            #[track_caller]
409            fn _magicsm_transitionPinDyn<Marker, To>(
410                self,
411                _marker: Marker,
412            ) -> $crate::PinnedDiscriminatedTransitionCall<
413                Storage,
414                $implementation,
415                Marker,
416                To,
417            >
418            where
419                From: $crate::StateTrait + $crate::In<Marker>,
420                Marker: $crate::StateUnionDiscriminant,
421                To: $crate::ConcreteStateTrait,
422            {
423                let state = <From as $crate::In<Marker>>::into_discriminated(self);
424                $crate::transition_discriminated_state_pinned(state, __StateMachineTransitionToken(()))
425            }
426
427        }
428
429        #[allow(dead_code, non_snake_case)]
430        trait __GenericStateMarkerTransitionExt<Storage, From>
431        where
432            Storage: $crate::StateStorage,
433        {
434            #[allow(non_snake_case)]
435            #[track_caller]
436            fn _magicsm_transitionDyn<Marker, To>(
437                self,
438                _marker: Marker,
439            ) -> $crate::KindProofTransitionCall<
440                Storage,
441                $implementation,
442                From,
443                Marker,
444                To,
445                <Marker as $crate::StateMarker>::Kind,
446            >
447            where
448                From: $crate::StateTrait + $crate::In<Marker>,
449                Marker: $crate::StateMarker,
450                To: $crate::ConcreteStateTrait;
451        }
452
453        impl<Storage, From> __GenericStateMarkerTransitionExt<Storage, From>
454            for $crate::State<Storage, $implementation, From>
455        where
456            Storage: $crate::StateStorage,
457            Storage::Machine<$implementation>: $crate::StateMachineImpl<
458                    Standin = $standin,
459                    Impl = $implementation,
460                    TransitionToken = __StateMachineTransitionToken,
461                >,
462        {
463            #[allow(non_snake_case)]
464            #[track_caller]
465            fn _magicsm_transitionDyn<Marker, To>(
466                self,
467                _marker: Marker,
468            ) -> $crate::KindProofTransitionCall<
469                Storage,
470                $implementation,
471                From,
472                Marker,
473                To,
474                <Marker as $crate::StateMarker>::Kind,
475            >
476            where
477                From: $crate::StateTrait + $crate::In<Marker>,
478                Marker: $crate::StateMarker,
479                To: $crate::ConcreteStateTrait,
480            {
481                $crate::transition_state_with_kind_proof::<
482                    Storage,
483                    $implementation,
484                    From,
485                    Marker,
486                    To,
487                    <Marker as $crate::StateMarker>::Kind,
488                >(
489                    self.with(<From as $crate::In<Marker>>::prove()),
490                    __StateMachineTransitionToken(()),
491                )
492            }
493
494        }
495
496        #[allow(dead_code, non_snake_case)]
497        trait __GenericStateMarkerStaticTransitionExt<Storage, From>
498        where
499            Storage: $crate::StateStorage,
500        {
501            #[allow(non_snake_case)]
502            #[track_caller]
503            fn _magicsm_transitionConst<Marker, To>(
504                self,
505                _marker: Marker,
506            ) -> $crate::StateUnionProofTransitionCall<Storage, $implementation, From, Marker, To>
507            where
508                From: $crate::StateTrait
509                    + $crate::In<Marker>
510                    + $crate::StateUnionErased<Marker>
511                    + $crate::UnionTransitionProof<$implementation, Marker, To>,
512                Marker: $crate::StateUnionDiscriminant
513                    + $crate::StateUnionTransition<$standin, To>
514                    + $crate::StateUnionSharedEffect<$implementation, To>,
515                To: $crate::ConcreteStateTrait,
516                $standin: $crate::Transition<
517                    $crate::StateUnionState<Marker>,
518                    To,
519                    F = <Marker as $crate::StateUnionTransition<$standin, To>>::F,
520                >;
521        }
522
523        impl<Storage, From> __GenericStateMarkerStaticTransitionExt<Storage, From>
524            for $crate::State<Storage, $implementation, From>
525        where
526            Storage: $crate::StateStorage,
527            Storage::Machine<$implementation>: $crate::StateMachineImpl<
528                    Standin = $standin,
529                    Impl = $implementation,
530                    TransitionToken = __StateMachineTransitionToken,
531                >,
532        {
533            #[allow(non_snake_case)]
534            #[track_caller]
535            fn _magicsm_transitionConst<Marker, To>(
536                self,
537                _marker: Marker,
538            ) -> $crate::StateUnionProofTransitionCall<Storage, $implementation, From, Marker, To>
539            where
540                From: $crate::StateTrait
541                    + $crate::In<Marker>
542                    + $crate::StateUnionErased<Marker>
543                    + $crate::UnionTransitionProof<$implementation, Marker, To>,
544                Marker: $crate::StateUnionDiscriminant
545                    + $crate::StateUnionTransition<$standin, To>
546                    + $crate::StateUnionSharedEffect<$implementation, To>,
547                To: $crate::ConcreteStateTrait,
548                $standin: $crate::Transition<
549                    $crate::StateUnionState<Marker>,
550                    To,
551                    F = <Marker as $crate::StateUnionTransition<$standin, To>>::F,
552                >,
553            {
554                $crate::transition_state_with_static_union_proof::<
555                    Storage,
556                    $implementation,
557                    From,
558                    Marker,
559                    To,
560                >(
561                    self,
562                    __StateMachineTransitionToken(()),
563                )
564            }
565
566        }
567
568        #[allow(dead_code, non_snake_case)]
569        trait __GenericStateMarkerPinnedStaticTransitionExt<Storage, From>
570        where
571            Storage: $crate::StateStorage,
572        {
573            #[allow(non_snake_case)]
574            #[track_caller]
575            fn _magicsm_transitionPinConst<Marker, To>(
576                self,
577                _marker: Marker,
578            ) -> $crate::PinnedStateUnionProofTransitionCall<Storage, $implementation, From, Marker, To>
579            where
580                From: $crate::StateTrait
581                    + $crate::In<Marker>
582                    + $crate::StateUnionErased<Marker>,
583                Marker: $crate::StateUnionDiscriminant
584                    + $crate::StateUnionTransition<$standin, To>
585                    + $crate::StateUnionSharedPinnedEffect<$implementation, To>,
586                To: $crate::ConcreteStateTrait,
587                $standin: $crate::Transition<
588                    $crate::StateUnionState<Marker>,
589                    To,
590                    F = <Marker as $crate::StateUnionTransition<$standin, To>>::F,
591                >;
592        }
593
594        impl<Storage, From> __GenericStateMarkerPinnedStaticTransitionExt<Storage, From>
595            for $crate::State<Storage, $implementation, From>
596        where
597            Storage: $crate::StateStorage,
598            Storage::Machine<$implementation>: $crate::StateMachineImpl<
599                    Standin = $standin,
600                    Impl = $implementation,
601                    TransitionToken = __StateMachineTransitionToken,
602                >,
603        {
604            #[allow(non_snake_case)]
605            #[track_caller]
606            fn _magicsm_transitionPinConst<Marker, To>(
607                self,
608                _marker: Marker,
609            ) -> $crate::PinnedStateUnionProofTransitionCall<Storage, $implementation, From, Marker, To>
610            where
611                From: $crate::StateTrait
612                    + $crate::In<Marker>
613                    + $crate::StateUnionErased<Marker>,
614                Marker: $crate::StateUnionDiscriminant
615                    + $crate::StateUnionTransition<$standin, To>
616                    + $crate::StateUnionSharedPinnedEffect<$implementation, To>,
617                To: $crate::ConcreteStateTrait,
618                $standin: $crate::Transition<
619                    $crate::StateUnionState<Marker>,
620                    To,
621                    F = <Marker as $crate::StateUnionTransition<$standin, To>>::F,
622                >,
623            {
624                $crate::transition_state_with_static_union_pinned_proof::<
625                    Storage,
626                    $implementation,
627                    From,
628                    Marker,
629                    To,
630                >(
631                    self,
632                    __StateMachineTransitionToken(()),
633                )
634            }
635
636        }
637
638        #[allow(dead_code)]
639        trait __GenericStateConcreteProofTransitionExt<Storage, From, Marker, To>
640        where
641            Storage: $crate::StateStorage,
642        {
643            #[track_caller]
644            fn _magicsm_transition(
645                self,
646            ) -> $crate::EffectTransitionCall<
647                Storage,
648                $implementation,
649                From,
650                To,
651                <$implementation as $crate::TransitionEffectSelector<From, To>>::Effect,
652            >
653            where
654                Storage: $crate::SRef,
655                Storage::Machine<$implementation>: $crate::StateMachineImpl<
656                    Standin = $standin,
657                    Impl = $implementation,
658                    TransitionToken = __StateMachineTransitionToken,
659                >,
660                From: $crate::StateTrait + $crate::StateUnionConcreteState,
661                Marker: $crate::StateUnionDiscriminant,
662                To: $crate::ConcreteStateTrait,
663                $standin: $crate::Transition<From, To>,
664                $implementation: $crate::TransitionEffectSelector<From, To>;
665        }
666
667        impl<Storage, From, Marker, To>
668            __GenericStateConcreteProofTransitionExt<Storage, From, Marker, To>
669            for $crate::StateConcreteProvenState<
670                Storage,
671                $implementation,
672                From,
673                Marker,
674                To,
675            >
676        where
677            Storage: $crate::StateStorage,
678            Storage::Machine<$implementation>: $crate::StateMachineImpl<
679                    Standin = $standin,
680                    Impl = $implementation,
681                    TransitionToken = __StateMachineTransitionToken,
682                >,
683            From: $crate::StateTrait,
684            Marker: $crate::StateUnionDiscriminant,
685            To: $crate::ConcreteStateTrait,
686        {
687            #[track_caller]
688            fn _magicsm_transition(
689                self,
690            ) -> $crate::EffectTransitionCall<
691                Storage,
692                $implementation,
693                From,
694                To,
695                <$implementation as $crate::TransitionEffectSelector<From, To>>::Effect,
696            >
697            where
698                From: $crate::StateTrait + $crate::StateUnionConcreteState,
699                To: $crate::ConcreteStateTrait,
700                $standin: $crate::Transition<From, To>,
701                $implementation: $crate::TransitionEffectSelector<From, To>,
702                Marker: $crate::StateUnionDiscriminant,
703            {
704                $crate::transition_state_with_concrete_proof(
705                    self,
706                    __StateMachineTransitionToken(()),
707                )
708            }
709
710        }
711
712        #[allow(dead_code)]
713        impl $implementation {
714            #[track_caller]
715            fn transition<Storage, From, Marker, To>(
716                self: $crate::StateUnionProvenState<
717                    Storage,
718                    $implementation,
719                    From,
720                    Marker,
721                    To,
722                >,
723            ) -> $crate::StateUnionProofTransitionCall<
724                Storage,
725                $implementation,
726                From,
727                Marker,
728                To,
729            >
730            where
731                Storage: $crate::SRef,
732                Storage::Machine<$implementation>: $crate::StateMachineImpl<
733                    Standin = $standin,
734                    Impl = $implementation,
735                    TransitionToken = __StateMachineTransitionToken,
736                >,
737                From: $crate::StateUnionErased<Marker>,
738                Marker: $crate::StateUnionSharedEffect<$implementation, To>,
739                To: $crate::ConcreteStateTrait,
740            {
741                $crate::transition_state_with_union_proof(
742                    self,
743                    __StateMachineTransitionToken(()),
744                )
745            }
746        }
747
748        #[allow(dead_code)]
749        trait __GenericStateUnionTransitionExt<Storage, Marker>
750        where
751            Storage: $crate::StateStorage,
752            Marker: $crate::StateUnionDiscriminant,
753        {
754            #[must_use]
755            #[track_caller]
756            fn _magicsm_transition_discriminated<To>(
757                self,
758            ) -> $crate::DiscriminatedTransitionCall<
759                Storage,
760                $implementation,
761                Marker,
762                To,
763            >
764            where
765                To: $crate::ConcreteStateTrait;
766        }
767
768        impl<Storage, Marker> __GenericStateUnionTransitionExt<Storage, Marker>
769            for $crate::DiscriminatedState<Storage, $implementation, Marker>
770        where
771            Storage: $crate::StateStorage,
772            Marker: $crate::StateUnionDiscriminant,
773            Storage::Machine<$implementation>: $crate::StateMachineImpl<
774                    Standin = $standin,
775                    Impl = $implementation,
776                    TransitionToken = __StateMachineTransitionToken,
777                >,
778        {
779            #[track_caller]
780            fn _magicsm_transition_discriminated<To>(
781                self,
782            ) -> $crate::DiscriminatedTransitionCall<
783                Storage,
784                $implementation,
785                Marker,
786                To,
787            >
788            where
789                To: $crate::ConcreteStateTrait,
790            {
791                $crate::transition_discriminated_state(self, __StateMachineTransitionToken(()))
792            }
793        }
794    };
795    ($implementation:ty : $standin:ty $(,)?) => {
796        #[doc(hidden)]
797        pub struct __StateMachineTransitionToken(());
798
799        impl $crate::StateMachineImpl for $implementation {
800            type Standin = $standin;
801            type Impl = $implementation;
802            type TransitionToken = __StateMachineTransitionToken;
803        }
804
805        #[allow(non_snake_case)]
806        trait __StateTransitionExt<T, From>
807        where
808            T: $crate::StateMachineImpl,
809        {
810            #[must_use]
811            #[track_caller]
812            fn _magicsm_transition<To>(self) -> $crate::TransitionCall<T, From, To>
813            where
814                T::Standin: $crate::Transition<From, To>;
815        }
816
817        impl<T, From> __StateTransitionExt<T, From> for $crate::StateOwned<T, From>
818        where
819            T: $crate::StateMachineImpl<
820                    Standin = $standin,
821                    Impl = $implementation,
822                    TransitionToken = __StateMachineTransitionToken,
823                >,
824        {
825            #[track_caller]
826            fn _magicsm_transition<To>(self) -> $crate::TransitionCall<T, From, To>
827            where
828                T::Standin: $crate::Transition<From, To>,
829            {
830                $crate::transition(self, __StateMachineTransitionToken(()))
831            }
832        }
833
834        #[allow(non_snake_case)]
835        trait __GenericStateTransitionExt<Storage, T, From>
836        where
837            T: $crate::StateMachineImpl,
838            Storage: $crate::StateStorage,
839            Storage::Machine<T>: $crate::StateMachineImpl,
840        {
841            #[must_use]
842            #[track_caller]
843            fn _magicsm_transition<To>(self) -> $crate::StateTransitionCall<Storage, T, From, To>
844            where
845                From: $crate::StateTrait,
846                To: $crate::ConcreteStateTrait,
847                T::Standin: $crate::Transition<From, To>;
848        }
849
850        impl<Storage, T, From> __GenericStateTransitionExt<Storage, T, From>
851            for $crate::State<Storage, T, From>
852        where
853            T: $crate::StateMachineImpl,
854            Storage: $crate::StateStorage,
855            Storage::Machine<T>: $crate::StateMachineImpl<
856                    Standin = $standin,
857                    Impl = $implementation,
858                    TransitionToken = __StateMachineTransitionToken,
859                >,
860        {
861            #[track_caller]
862            fn _magicsm_transition<To>(self) -> $crate::StateTransitionCall<Storage, T, From, To>
863            where
864                From: $crate::StateTrait,
865                To: $crate::ConcreteStateTrait,
866                T::Standin: $crate::Transition<From, To>,
867            {
868                $crate::transition_state(self, __StateMachineTransitionToken(()))
869            }
870        }
871
872        #[allow(non_snake_case)]
873        trait __StateMutTransitionExt<G, T, From>
874        where
875            G: ::core::ops::DerefMut<Target = $crate::SharedValue<T>>,
876            T: $crate::StateMachineImpl,
877        {
878            #[must_use]
879            fn _magicsm_transition<To>(self) -> $crate::StateMutTransitionCall<G, T, From, To>
880            where
881                T::Standin: $crate::Transition<From, To>;
882        }
883
884        impl<G, T, From> __StateMutTransitionExt<G, T, From> for $crate::StateMut<G, T, From>
885        where
886            G: ::core::ops::DerefMut<Target = $crate::SharedValue<T>>,
887            T: $crate::StateMachineImpl<
888                    Standin = $standin,
889                    Impl = $implementation,
890                    TransitionToken = __StateMachineTransitionToken,
891                >,
892        {
893            fn _magicsm_transition<To>(self) -> $crate::StateMutTransitionCall<G, T, From, To>
894            where
895                T::Standin: $crate::Transition<From, To>,
896            {
897                $crate::transition_mut(self, __StateMachineTransitionToken(()))
898            }
899        }
900    };
901}
902
903#[doc(hidden)]
904#[macro_export]
905macro_rules! __StateMachineImpl {
906    (
907        @parse $implementation:ty; $standin:ty; [$($pending:tt)*];
908    ) => {
909        $crate::__StateMachineImpl!(@finish_pending [$($pending)*]);
910    };
911    (
912        @parse $implementation:ty; $standin:ty; [$($pending:tt)*];
913        pinned transition $first_from:ident $(| $from:ident)* => $to:ident
914            ($($arg:ident : $arg_ty:ty),* $(,)?);
915        $($rest:tt)*
916    ) => {
917        $crate::__StateMachineImpl!(@emit_pending $implementation; $standin; {}; $($pending)*);
918        $crate::__StateMachineImpl!(
919            @pinned_effect_impls $implementation; $standin; $first_from $(| $from)* => $to
920            ($($arg : $arg_ty),*) {}
921        );
922        $crate::__StateMachineImpl!(@parse $implementation; $standin; []; $($rest)*);
923    };
924    (
925        @parse $implementation:ty; $standin:ty; [$($pending:tt)*];
926        pinned transition $first_from:ident $(| $from:ident)* => $to:ident
927            ($($arg:ident : $arg_ty:ty),* $(,)?) { $($body:tt)* },
928        $($rest:tt)*
929    ) => {
930        $crate::__StateMachineImpl!(@emit_pending $implementation; $standin; { $($body)* }; $($pending)*);
931        $crate::__StateMachineImpl!(
932            @pinned_effect_impls $implementation; $standin; $first_from $(| $from)* => $to
933            ($($arg : $arg_ty),*) { $($body)* }
934        );
935        $crate::__StateMachineImpl!(@parse $implementation; $standin; []; $($rest)*);
936    };
937    (
938        @parse $implementation:ty; $standin:ty; [$($pending:tt)*];
939        pinned transition $first_from:ident $(| $from:ident)* => $to:ident
940            ($($arg:ident : $arg_ty:ty),* $(,)?) { $($body:tt)* }
941        $($rest:tt)*
942    ) => {
943        $crate::__StateMachineImpl!(@emit_pending $implementation; $standin; { $($body)* }; $($pending)*);
944        $crate::__StateMachineImpl!(
945            @pinned_effect_impls $implementation; $standin; $first_from $(| $from)* => $to
946            ($($arg : $arg_ty),*) { $($body)* }
947        );
948        $crate::__StateMachineImpl!(@parse $implementation; $standin; []; $($rest)*);
949    };
950    (
951        @parse $implementation:ty; $standin:ty; [$($pending:tt)*];
952        transition $first_from:ident $(| $from:ident)* => $to:ident
953            ($($arg:ident : $arg_ty:ty),* $(,)?),
954        $($rest:tt)*
955    ) => {
956        $crate::__StateMachineImpl!(
957            @parse $implementation; $standin;
958            [
959                $($pending)*
960                { $first_from $(| $from)* => $to ($($arg : $arg_ty),*) }
961            ];
962            $($rest)*
963        );
964    };
965    (
966        @parse $implementation:ty; $standin:ty; [$($pending:tt)*];
967        transition $first_from:ident $(| $from:ident)* => $to:ident
968            ($($arg:ident : $arg_ty:ty),* $(,)?);
969        $($rest:tt)*
970    ) => {
971        $crate::__StateMachineImpl!(@emit_pending $implementation; $standin; {}; $($pending)*);
972        $crate::__StateMachineImpl!(
973            @effect_impls $implementation; $standin; $first_from $(| $from)* => $to
974            ($($arg : $arg_ty),*) {}
975        );
976        $crate::__StateMachineImpl!(@parse $implementation; $standin; []; $($rest)*);
977    };
978    (
979        @parse $implementation:ty; $standin:ty; [$($pending:tt)*];
980        transition $first_from:ident $(| $from:ident)* => $to:ident
981            ($($arg:ident : $arg_ty:ty),* $(,)?) { $($body:tt)* },
982        $($rest:tt)*
983    ) => {
984        $crate::__StateMachineImpl!(@emit_pending $implementation; $standin; { $($body)* }; $($pending)*);
985        $crate::__StateMachineImpl!(
986            @effect_impls $implementation; $standin; $first_from $(| $from)* => $to
987            ($($arg : $arg_ty),*) { $($body)* }
988        );
989        $crate::__StateMachineImpl!(@parse $implementation; $standin; []; $($rest)*);
990    };
991    (
992        @parse $implementation:ty; $standin:ty; [$($pending:tt)*];
993        transition $first_from:ident $(| $from:ident)* => $to:ident
994            ($($arg:ident : $arg_ty:ty),* $(,)?) { $($body:tt)* }
995        $($rest:tt)*
996    ) => {
997        $crate::__StateMachineImpl!(@emit_pending $implementation; $standin; { $($body)* }; $($pending)*);
998        $crate::__StateMachineImpl!(
999            @effect_impls $implementation; $standin; $first_from $(| $from)* => $to
1000            ($($arg : $arg_ty),*) { $($body)* }
1001        );
1002        $crate::__StateMachineImpl!(@parse $implementation; $standin; []; $($rest)*);
1003    };
1004    (@finish_pending []) => {};
1005    (@finish_pending [$($pending:tt)+]) => {
1006        ::core::compile_error!(
1007            "comma-terminated state-machine transitions must be followed by a transition body or semicolon"
1008        );
1009    };
1010    (
1011        @emit_pending $implementation:ty; $standin:ty; { $($body:tt)* };
1012    ) => {};
1013    (
1014        @emit_pending $implementation:ty; $standin:ty; { $($body:tt)* };
1015        { $first_from:ident $(| $from:ident)* => $to:ident ($($arg:ident : $arg_ty:ty),*) }
1016        $($rest:tt)*
1017    ) => {
1018        $crate::__StateMachineImpl!(
1019            @effect_impls $implementation; $standin; $first_from $(| $from)* => $to
1020            ($($arg : $arg_ty),*) { $($body)* }
1021        );
1022        $crate::__StateMachineImpl!(
1023            @emit_pending $implementation; $standin; { $($body)* };
1024            $($rest)*
1025        );
1026    };
1027    (
1028        @effect_impls $implementation:ty; $standin:ty; $first_from:ident $(| $from:ident)* => $to:ident
1029        $args:tt $body:tt
1030    ) => {
1031        $crate::__private::paste! {
1032            #[doc(hidden)]
1033            pub struct [<__StateMachineTransitionEffect $first_from To $to>];
1034        }
1035
1036        $crate::__StateMachineImpl!(
1037            @effect_impl $implementation; $standin; $first_from $first_from => $to
1038            $args $body
1039        );
1040        $(
1041            $crate::__StateMachineImpl!(
1042                @effect_impl $implementation; $standin; $from $first_from => $to
1043                $args $body
1044            );
1045        )*
1046
1047    };
1048    (
1049        @pinned_effect_impls $implementation:ty; $standin:ty; $first_from:ident $(| $from:ident)* => $to:ident
1050        $args:tt $body:tt
1051    ) => {
1052        $crate::__private::paste! {
1053            #[doc(hidden)]
1054            pub struct [<__StateMachinePinnedTransitionEffect $first_from To $to>];
1055        }
1056
1057        $crate::__StateMachineImpl!(
1058            @pinned_effect_impl $implementation; $standin; $first_from $first_from => $to
1059            $args $body
1060        );
1061        $(
1062            $crate::__StateMachineImpl!(
1063                @pinned_effect_impl $implementation; $standin; $from $first_from => $to
1064                $args $body
1065            );
1066        )*
1067
1068    };
1069    (
1070        @effect_impl $implementation:ty; $standin:ty; $from:ident $effect_from:ident => $to:ident
1071        ($($arg:ident : $arg_ty:ty),*) { $($body:tt)* }
1072    ) => {
1073        $crate::__private::paste! {
1074            impl $crate::TransitionEffectSelector<$from, $to> for $implementation {
1075                type Effect = [<__StateMachineTransitionEffect $effect_from To $to>];
1076            }
1077
1078            impl $crate::TransitionEffect<$implementation, $from, $to, ($($arg_ty,)*)>
1079                for [<__StateMachineTransitionEffect $effect_from To $to>]
1080            where
1081                $standin: $crate::Transition<$from, $to, F = fn($($arg_ty),*)>,
1082            {
1083                fn apply(
1084                    __state_machine_value: &mut $implementation,
1085                    ($($arg,)*): ($($arg_ty,)*),
1086                ) {
1087                    let __state_machine_self = __state_machine_value;
1088                    $crate::__StateMachineImpl!(@replace_self __state_machine_self; []; $($body)*);
1089                }
1090            }
1091        }
1092    };
1093    (
1094        @pinned_effect_impl $implementation:ty; $standin:ty; $from:ident $effect_from:ident => $to:ident
1095        ($($arg:ident : $arg_ty:ty),*) { $($body:tt)* }
1096    ) => {
1097        $crate::__private::paste! {
1098            impl $crate::PinnedTransitionEffectSelector<$from, $to> for $implementation {
1099                type Effect = [<__StateMachinePinnedTransitionEffect $effect_from To $to>];
1100            }
1101
1102            impl $crate::PinnedTransitionEffect<$implementation, $from, $to, ($($arg_ty,)*)>
1103                for [<__StateMachinePinnedTransitionEffect $effect_from To $to>]
1104            where
1105                $standin: $crate::Transition<$from, $to, F = fn($($arg_ty),*)>,
1106            {
1107                fn apply(
1108                    __state_machine_value: ::core::pin::Pin<&mut $implementation>,
1109                    ($($arg,)*): ($($arg_ty,)*),
1110                ) {
1111                    let mut __state_machine_self = __state_machine_value;
1112                    $crate::__StateMachineImpl!(@replace_self __state_machine_self; []; $($body)*);
1113                }
1114            }
1115        }
1116    };
1117    (@replace_self $self_ident:ident; [$($out:tt)*];) => {
1118        $($out)*
1119    };
1120    (@replace_self $self_ident:ident; [$($out:tt)*]; self $($rest:tt)*) => {
1121        $crate::__StateMachineImpl!(
1122            @replace_self $self_ident; [$($out)* $self_ident]; $($rest)*
1123        )
1124    };
1125    (@replace_self $self_ident:ident; [$($out:tt)*]; $token:tt $($rest:tt)*) => {
1126        $crate::__StateMachineImpl!(
1127            @replace_self $self_ident; [$($out)* $token]; $($rest)*
1128        )
1129    };
1130}