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