1use crate::{
2 SMove, SMut, SPinMut, SPinRef, SRef, State, StateInference, StateMachineImpl, StateMarker,
3 StateStorage, StateTrait, Transition, TransitionCallsite, TransitionProof, UnionStateKind,
4 state_trait,
5};
6use core::{any::TypeId, marker::PhantomData, pin::Pin};
7
8#[doc(hidden)]
10pub struct StateUnionState<Marker>(PhantomData<fn() -> Marker>);
11
12impl<Marker> StateUnionState<Marker> {
13 #[doc(hidden)]
14 #[must_use]
15 pub const fn new() -> Self {
16 Self(PhantomData)
17 }
18}
19
20#[doc(hidden)]
22pub auto trait StateUnionConcreteState {}
23
24impl<Marker> !StateUnionConcreteState for StateUnionState<Marker> {}
25
26#[doc(hidden)]
28pub trait StateUnionMember<State> {}
29
30pub trait StateUnionDiscriminant: Sized + StateMarker<Kind = UnionStateKind> {
44 type Enum<Storage, T>
49 where
50 Storage: StateStorage,
51 T: StateMachineImpl;
52
53 #[doc(hidden)]
54 fn discriminate<Storage, T>(
55 state: DiscriminatedState<Storage, T, Self>,
56 ) -> Self::Enum<Storage, T>
57 where
58 Storage: StateStorage,
59 T: StateMachineImpl;
60}
61
62pub trait In<Marker>: StateTrait + StateMarker
100where
101 Marker: StateMarker,
102{
103 #[must_use]
108 fn into_discriminated<Storage, T>(
109 state: State<Storage, T, Self>,
110 ) -> DiscriminatedState<Storage, T, Marker>
111 where
112 Self: Sized,
113 Storage: StateStorage,
114 T: StateMachineImpl,
115 Marker: StateUnionDiscriminant;
116
117 #[doc(hidden)]
118 #[must_use]
119 fn prove<Storage, T, To>()
120 -> TransitionProof<Storage, T, Self, Marker, To, <Marker as StateMarker>::Kind>
121 where
122 Self: Sized,
123 Storage: StateStorage,
124 T: StateMachineImpl,
125 To: StateTrait + StateMarker,
126 {
127 TransitionProof::new()
128 }
129}
130
131impl<StateMarkerType> In<StateMarkerType> for StateMarkerType
132where
133 StateMarkerType: StateTrait + StateMarker,
134{
135 fn into_discriminated<Storage, T>(
136 _state: State<Storage, T, Self>,
137 ) -> DiscriminatedState<Storage, T, StateMarkerType>
138 where
139 Self: Sized,
140 Storage: StateStorage,
141 T: StateMachineImpl,
142 StateMarkerType: StateUnionDiscriminant,
143 {
144 unreachable!("concrete identity states are not generated state unions")
145 }
146}
147
148pub type DiscriminatedState<Storage, T, Marker> =
174 State<SDiscriminated<Storage>, T, StateUnionState<Marker>>;
175
176impl<Storage, T, Marker> State<SDiscriminated<Storage>, T, StateUnionState<Marker>>
177where
178 Storage: StateStorage,
179 T: StateMachineImpl,
180 Marker: StateUnionDiscriminant,
181{
182 #[must_use]
198 pub fn discriminate(self) -> <Marker as StateUnionDiscriminant>::Enum<Storage, T> {
199 Marker::discriminate(self)
200 }
201}
202
203#[doc(hidden)]
204#[must_use]
205pub fn discriminate_state<Storage, T, From, Marker>(
206 state: State<Storage, T, From>,
207) -> DiscriminatedState<Storage, T, Marker>
208where
209 Storage: StateStorage,
210 T: StateMachineImpl,
211 From: crate::ConcreteStateTrait,
212 Marker: StateUnionDiscriminant,
213{
214 let inference =
215 <<Storage::Inference as crate::InferenceKind>::Inference as crate::StateInference>::new::<
216 Storage,
217 T,
218 From,
219 >(&state.inner);
220 State::from_inner(DiscriminatedInner {
221 inner: Storage::retag(state.inner),
222 inference,
223 })
224}
225
226#[doc(hidden)]
227#[must_use]
228pub fn rediscriminate_union_state<Storage, T, FromMarker, ToMarker>(
229 state: State<Storage, T, StateUnionState<FromMarker>>,
230) -> DiscriminatedState<Storage, T, ToMarker>
231where
232 Storage: StateStorage,
233 T: StateMachineImpl,
234 FromMarker: StateUnionDiscriminant,
235 StateUnionState<FromMarker>: StateTrait,
236 ToMarker: StateUnionDiscriminant,
237{
238 let inferred_state = Storage::inferred_state(&state.inner);
239 let inference =
240 <<Storage::Inference as crate::InferenceKind>::Inference as crate::StateInference>::from_erased(
241 inferred_state,
242 );
243 State::from_inner(DiscriminatedInner {
244 inner: Storage::retag(state.inner),
245 inference,
246 })
247}
248
249#[doc(hidden)]
250#[must_use]
251pub fn undiscriminate_state<Storage, T, S>(
252 state: State<SDiscriminated<Storage>, T, S>,
253) -> State<Storage, T, S>
254where
255 Storage: StateStorage,
256 T: StateMachineImpl,
257{
258 State::from_inner(state.inner.inner)
259}
260
261#[doc(hidden)]
262#[must_use]
263pub fn concretize_discriminated_state<Storage, T, Marker, Concrete>(
264 state: DiscriminatedState<Storage, T, Marker>,
265) -> State<Storage, T, Concrete>
266where
267 Storage: StateStorage,
268 T: StateMachineImpl,
269 Marker: StateUnionDiscriminant,
270{
271 State::from_inner(Storage::retag(state.inner.inner))
272}
273
274#[doc(hidden)]
275#[must_use]
276pub fn discriminated_state_marker<Storage, T, S>(
277 state: &State<SDiscriminated<Storage>, T, S>,
278) -> state_trait::ErasedState
279where
280 Storage: StateStorage,
281 T: StateMachineImpl,
282 S: StateTrait,
283{
284 state
285 .inner
286 .inference
287 .state::<Storage, T, S>(&state.inner.inner)
288}
289
290#[doc(hidden)]
291#[must_use]
292pub fn state_union_marker<Storage, T, S>(state: &State<Storage, T, S>) -> state_trait::ErasedState
293where
294 Storage: StateStorage,
295 T: StateMachineImpl,
296 S: StateTrait,
297{
298 Storage::inferred_state(&state.inner)
299}
300
301#[doc(hidden)]
302#[must_use]
303pub fn erased_state_type_id(state: &state_trait::ErasedState) -> TypeId {
304 state.type_id()
305}
306
307#[doc(hidden)]
309pub struct SDiscriminated<Storage>(PhantomData<fn() -> Storage>);
310
311#[doc(hidden)]
312pub struct DiscriminatedInner<Inner, Inference> {
313 pub(crate) inner: Inner,
314 pub(crate) inference: Inference,
315}
316
317impl<Storage> StateStorage for SDiscriminated<Storage>
318where
319 Storage: StateStorage,
320{
321 type Inference = Storage::Inference;
322
323 type Inner<T, S>
324 = DiscriminatedInner<
325 Storage::Inner<T, S>,
326 <Storage::Inference as crate::InferenceKind>::Inference,
327 >
328 where
329 T: StateMachineImpl;
330 type Machine<T>
331 = Storage::Machine<T>
332 where
333 T: StateMachineImpl;
334
335 fn retag<T, From, To>(inner: Self::Inner<T, From>) -> Self::Inner<T, To>
336 where
337 T: StateMachineImpl,
338 {
339 DiscriminatedInner {
340 inner: Storage::retag(inner.inner),
341 inference: inner.inference,
342 }
343 }
344
345 fn complete_transition<T, From, To, Args>(
346 state: State<Self, T, From>,
347 args: Args,
348 callsite: TransitionCallsite,
349 ) -> State<Self, T, To>
350 where
351 T: StateMachineImpl,
352 From: StateTrait,
353 To: crate::ConcreteStateTrait,
354 T::Standin: Transition<From, To>,
355 <T::Standin as Transition<From, To>>::F: crate::TransitionSignature<Args>,
356 {
357 let state = State::<Storage, T, From>::from_inner(state.inner.inner);
358 let state = Storage::complete_transition(state, args, callsite);
359 let inference =
360 <<Storage::Inference as crate::InferenceKind>::Inference as crate::StateInference>::new::<
361 Storage,
362 T,
363 To,
364 >(&state.inner);
365 State::from_inner(DiscriminatedInner {
366 inner: state.inner,
367 inference,
368 })
369 }
370
371 fn complete_transition_after_effect<T, From, To>(
372 state: State<Self, T, From>,
373 callsite: TransitionCallsite,
374 ) -> State<Self, T, To>
375 where
376 T: StateMachineImpl,
377 From: StateTrait,
378 To: crate::ConcreteStateTrait,
379 {
380 let state = State::<Storage, T, From>::from_inner(state.inner.inner);
381 let state = Storage::complete_transition_after_effect(state, callsite);
382 let inference =
383 <<Storage::Inference as crate::InferenceKind>::Inference as crate::StateInference>::new::<
384 Storage,
385 T,
386 To,
387 >(&state.inner);
388 State::from_inner(DiscriminatedInner {
389 inner: state.inner,
390 inference,
391 })
392 }
393
394 fn inferred_state<T, State>(inner: &Self::Inner<T, State>) -> state_trait::ErasedState
395 where
396 T: StateMachineImpl,
397 State: StateTrait,
398 {
399 inner.inference.state::<Storage, T, State>(&inner.inner)
400 }
401}
402
403impl<Storage> SRef for SDiscriminated<Storage>
404where
405 Storage: SRef,
406{
407 fn s_ref<T, S>(inner: &Self::Inner<T, S>) -> &T
408 where
409 T: StateMachineImpl,
410 {
411 Storage::s_ref(&inner.inner)
412 }
413}
414
415impl<Storage> SMut for SDiscriminated<Storage>
416where
417 Storage: SMut,
418{
419 fn s_mut<T, S>(inner: &mut Self::Inner<T, S>) -> &mut T
420 where
421 T: StateMachineImpl,
422 {
423 Storage::s_mut(&mut inner.inner)
424 }
425}
426
427impl<Storage> SPinRef for SDiscriminated<Storage>
428where
429 Storage: SPinRef,
430{
431 fn s_pin_ref<T, S>(inner: &Self::Inner<T, S>) -> core::pin::Pin<&T>
432 where
433 T: StateMachineImpl,
434 {
435 Storage::s_pin_ref(&inner.inner)
436 }
437}
438
439impl<Storage> SPinMut for SDiscriminated<Storage>
440where
441 Storage: SPinMut,
442{
443 fn s_pin_mut<T, S>(inner: &mut Self::Inner<T, S>) -> core::pin::Pin<&mut T>
444 where
445 T: StateMachineImpl,
446 {
447 Storage::s_pin_mut(&mut inner.inner)
448 }
449}
450
451impl<Storage> SMove for SDiscriminated<Storage> where Storage: SMove {}
452
453#[doc(hidden)]
455pub trait StateUnionErased<Marker>: StateTrait {
456 fn into_union_erased<Storage, T>(
457 state: State<Storage, T, Self>,
458 ) -> DiscriminatedState<Storage, T, Marker>
459 where
460 Self: Sized,
461 Storage: StateStorage,
462 T: StateMachineImpl,
463 Marker: StateUnionDiscriminant;
464}
465
466#[doc(hidden)]
468pub trait StateUnionRuntime {
469 fn contains(state: &dyn StateTrait) -> bool;
470 fn expected_type_name() -> &'static str;
471}
472
473#[doc(hidden)]
475pub trait StateUnionTransition<Standin, To> {
476 type F;
477}
478
479#[doc(hidden)]
481pub trait StateUnionProofMembership<Marker>: StateUnionErased<Marker>
482where
483 Marker: StateUnionDiscriminant,
484{
485}
486
487#[doc(hidden)]
489pub trait StateUnionProofTarget<T, From>: crate::ConcreteStateTrait + Sized
490where
491 T: StateMachineImpl,
492 From: StateTrait,
493{
494 type Marker: StateUnionDiscriminant + StateUnionSharedEffect<T, Self>;
495}
496
497#[doc(hidden)]
499pub trait StateUnionSharedEffect<T, To>: StateUnionDiscriminant
500where
501 T: StateMachineImpl,
502 To: crate::ConcreteStateTrait,
503{
504 type Effect;
505}
506
507#[doc(hidden)]
509pub trait StateUnionSharedTransitionEffect<T, To, Args>: StateUnionSharedEffect<T, To>
510where
511 T: StateMachineImpl,
512 To: crate::ConcreteStateTrait,
513{
514 fn apply(value: &mut T, args: Args);
515}
516
517#[doc(hidden)]
519pub trait StateUnionSharedPinnedEffect<T, To>: StateUnionDiscriminant
520where
521 T: StateMachineImpl,
522 To: crate::ConcreteStateTrait,
523{
524 type Effect;
525}
526
527#[doc(hidden)]
529pub trait StateUnionSharedPinnedTransitionEffect<T, To, Args>:
530 StateUnionSharedPinnedEffect<T, To>
531where
532 T: StateMachineImpl,
533 To: crate::ConcreteStateTrait,
534{
535 fn apply_pinned(value: Pin<&mut T>, args: Args);
536}
537
538#[doc(hidden)]
540pub trait StateUnionDiscriminatedTransition<T, To, Args>: StateUnionDiscriminant
541where
542 T: StateMachineImpl,
543{
544 fn transition<Storage>(
545 state: DiscriminatedState<Storage, T, Self>,
546 args: Args,
547 callsite: TransitionCallsite,
548 ) -> State<Storage, T, To>
549 where
550 Storage: SMut,
551 To: crate::ConcreteStateTrait;
552}
553
554#[doc(hidden)]
556pub trait StateUnionDiscriminatedPinnedTransition<T, To, Args>: StateUnionDiscriminant
557where
558 T: StateMachineImpl,
559{
560 fn pinned_transition<Storage>(
561 state: DiscriminatedState<Storage, T, Self>,
562 args: Args,
563 callsite: TransitionCallsite,
564 ) -> State<Storage, T, To>
565 where
566 Storage: SPinMut,
567 To: crate::ConcreteStateTrait;
568}
569
570impl<Standin, Marker, To> Transition<StateUnionState<Marker>, To> for Standin
571where
572 Marker: StateUnionTransition<Standin, To>,
573{
574 type F = Marker::F;
575}