1use super::sending::{
4 ClassifySettlement, InterpretItem, InterpretSends, Interpretation, InterpreterFault,
5 ItemSettlement, SendEffects, SendInput, SendSettlements, SettledItem, SettlementStatus,
6 SourceAdmission, SourceCustody, SourceSettlementCustody, offer_source_in_order,
7};
8use crate::actor::{
9 Address, BirthMode, Births, ChildCreationProduct, ChildHead, ChildNamespaceExhausted,
10 CreateChild, CreationRejection, Creations, DispatchBirth, NoBirths, RetirementBirths,
11 RoutedCreation,
12};
13use crate::next::{Never, Step, Stopped};
14use crate::transition::{Behavior, BehaviorAddr};
15use crate::user_event::{EventIngress, User, UserEvent};
16
17pub type Become<Ph = Never> = Step<Ph, Stopped>;
18
19#[derive(Clone, Debug, Eq, PartialEq)]
26pub struct ActionSettlement<Creations, Sends, Ph> {
27 pub creations: Creations,
28 pub sends: Sends,
29 pub become_: Become<Ph>,
30}
31
32#[doc(hidden)]
34#[derive(Clone, Debug, Eq, PartialEq)]
35pub enum CreationSettlement<Requests, Settlements> {
36 Settled(Settlements),
38 Rejected {
40 creations: Requests,
41 reason: ChildNamespaceExhausted,
42 },
43 Corrupt {
45 creations: Requests,
46 fault: InterpreterFault,
47 },
48}
49
50#[must_use = "a retirement creation settlement must remain in terminal custody"]
56#[derive(Clone, Debug, Eq, PartialEq)]
57pub struct RetirementCreationSettlement<Settlement> {
58 settlement: Settlement,
59}
60
61impl<Settlement> RetirementCreationSettlement<Settlement> {
62 #[must_use]
63 pub const fn new(settlement: Settlement) -> Self {
64 Self { settlement }
65 }
66
67 #[must_use]
68 pub fn into_settlement(self) -> Settlement {
69 self.settlement
70 }
71}
72
73pub trait ActionSettlements {
79 type Settlements;
80}
81
82impl<A, Ph, Sends, Birth> ActionSettlements for Actions<A, Ph, Sends, Birth>
83where
84 A: Address,
85 Sends: SendSettlements,
86 Birth: CreationSettlements<A>,
87{
88 type Settlements = ActionSettlement<Birth::Settlements, Sends::Settlements, Ph>;
89}
90
91pub trait BehaviorSettlements: Behavior {
98 type Settlements;
99}
100
101impl<B> BehaviorSettlements for B
102where
103 B: Behavior,
104 B::Sends: SendSettlements,
105 B::Birth: CreationSettlements<BehaviorAddr<B>>,
106{
107 type Settlements =
108 <Actions<BehaviorAddr<B>, B::Ph, B::Sends, B::Birth> as ActionSettlements>::Settlements;
109}
110
111impl<Requests, Settlements> ClassifySettlement for CreationSettlement<Requests, Settlements>
112where
113 Settlements: ClassifySettlement,
114{
115 fn settlement_status(&self) -> SettlementStatus {
116 match self {
117 Self::Settled(settlements) => settlements.settlement_status(),
118 Self::Rejected { .. } => SettlementStatus::Rejected,
119 Self::Corrupt { .. } => SettlementStatus::Corrupt,
120 }
121 }
122}
123
124impl<Settlement> ClassifySettlement for RetirementCreationSettlement<Settlement>
125where
126 Settlement: ClassifySettlement,
127{
128 fn settlement_status(&self) -> SettlementStatus {
129 self.settlement.settlement_status()
130 }
131}
132
133impl<Item> ClassifySettlement for Creations<Item>
134where
135 Item: ClassifySettlement,
136{
137 fn settlement_status(&self) -> SettlementStatus {
138 let mut status = SettlementStatus::Accepted;
139 for item in self.iter() {
140 status = status.combine(item.settlement_status());
141 }
142 status
143 }
144}
145
146#[doc(hidden)]
148pub trait CreationSettlements<A: Address>: BirthMode {
149 type Settlements: ClassifySettlement;
150}
151
152impl<A: Address> CreationSettlements<A> for NoBirths {
153 type Settlements = Creations<Never>;
154}
155
156impl<A, C> CreationSettlements<A> for Births<C>
157where
158 A: Address,
159 C: ChildCreationProduct<A, ChildHead>,
160{
161 type Settlements = CreationSettlement<
162 Creations<CreateChild<A, C>>,
163 Creations<
164 SettledItem<
165 RoutedCreation<A, C>,
166 ItemSettlement<
167 RoutedCreation<A, C>,
168 <C as ChildCreationProduct<A, ChildHead>>::Result,
169 CreationRejection,
170 Never,
171 >,
172 >,
173 >,
174 >;
175}
176
177impl<A, C> CreationSettlements<A> for RetirementBirths<C>
178where
179 A: Address,
180 C: ChildCreationProduct<A, ChildHead>,
181{
182 type Settlements =
183 RetirementCreationSettlement<<Births<C> as CreationSettlements<A>>::Settlements>;
184}
185
186#[doc(hidden)]
192#[must_use = "a returned creation batch must be admitted or retained"]
193pub struct CreationsSettled<A, C>
194where
195 A: Address,
196 C: ChildCreationProduct<A, ChildHead>,
197{
198 settlement: <Births<C> as CreationSettlements<A>>::Settlements,
199}
200
201pub enum CreationEvent<A, C, M>
208where
209 A: Address,
210 C: ChildCreationProduct<A, ChildHead>,
211{
212 Settlements(CreationsSettled<A, C>),
213 User(User<A, M>),
214}
215
216impl<A, C, M> EventIngress<Births<C>, CreationsSettled<A, C>> for CreationEvent<A, C, M>
217where
218 A: Address,
219 C: ChildCreationProduct<A, ChildHead>,
220{
221 fn ingress(input: CreationsSettled<A, C>) -> Self {
222 Self::Settlements(input)
223 }
224}
225
226impl<A, C, M> UserEvent for CreationEvent<A, C, M>
227where
228 A: Address,
229 C: ChildCreationProduct<A, ChildHead>,
230{
231 type Addr = A;
232 type Message = M;
233
234 fn user(from: A, message: M) -> Self {
235 Self::User(User::new(from, message))
236 }
237
238 fn into_user(self) -> Result<User<A, M>, Self> {
239 match self {
240 Self::User(event) => Ok(event),
241 settlements @ Self::Settlements(_) => Err(settlements),
242 }
243 }
244}
245
246impl<A, C> CreationsSettled<A, C>
247where
248 A: Address,
249 C: ChildCreationProduct<A, ChildHead>,
250{
251 #[must_use]
252 pub const fn new(settlement: <Births<C> as CreationSettlements<A>>::Settlements) -> Self {
253 Self { settlement }
254 }
255
256 #[must_use]
257 pub fn into_settlement(self) -> <Births<C> as CreationSettlements<A>>::Settlements {
258 self.settlement
259 }
260}
261
262impl<Host, RootEvent> SourceSettlementCustody<Host, RootEvent> for Creations<Never> {
263 fn offer_next_to_source(
264 self,
265 _: &mut Host,
266 ) -> impl core::future::Future<Output = SourceCustody<Self>> + Send {
267 core::future::ready(SourceCustody::Exhausted(self))
268 }
269}
270
271impl<A, C, Host, RootEvent> SourceSettlementCustody<Host, RootEvent>
272 for CreationSettlement<
273 Creations<CreateChild<A, C>>,
274 Creations<
275 SettledItem<
276 RoutedCreation<A, C>,
277 ItemSettlement<
278 RoutedCreation<A, C>,
279 <C as ChildCreationProduct<A, ChildHead>>::Result,
280 CreationRejection,
281 Never,
282 >,
283 >,
284 >,
285 >
286where
287 A: Address,
288 A::Nonce: Send,
289 C: ChildCreationProduct<A, ChildHead> + Send,
290 <C as ChildCreationProduct<A, ChildHead>>::Result: Send,
291 Host: SourceAdmission<RootEvent, Births<C>, CreationsSettled<A, C>>,
292 RootEvent: crate::EventIngress<Births<C>, CreationsSettled<A, C>>,
293{
294 fn offer_next_to_source(
295 self,
296 host: &mut Host,
297 ) -> impl core::future::Future<Output = SourceCustody<Self>> + Send {
298 async move {
299 if matches!(&self, CreationSettlement::Settled(settlements) if settlements.is_empty()) {
300 return SourceCustody::Exhausted(self);
301 }
302 match host.admit_source(CreationsSettled::new(self)).await {
303 Ok(()) => SourceCustody::Admitted(CreationSettlement::Settled(Creations::empty())),
304 Err(returned) => SourceCustody::Closed(returned.into_settlement()),
305 }
306 }
307 }
308}
309
310impl<A, C, Host, RootEvent> SourceSettlementCustody<Host, RootEvent>
311 for RetirementCreationSettlement<
312 CreationSettlement<
313 Creations<CreateChild<A, C>>,
314 Creations<
315 SettledItem<
316 RoutedCreation<A, C>,
317 ItemSettlement<
318 RoutedCreation<A, C>,
319 <C as ChildCreationProduct<A, ChildHead>>::Result,
320 CreationRejection,
321 Never,
322 >,
323 >,
324 >,
325 >,
326 >
327where
328 A: Address,
329 A::Nonce: Send,
330 C: ChildCreationProduct<A, ChildHead> + Send,
331 <C as ChildCreationProduct<A, ChildHead>>::Result: Send,
332{
333 fn offer_next_to_source(
334 self,
335 _: &mut Host,
336 ) -> impl core::future::Future<Output = SourceCustody<Self>> + Send {
337 async move {
338 if matches!(
339 &self.settlement,
340 CreationSettlement::Settled(settlements) if settlements.is_empty()
341 ) {
342 SourceCustody::Exhausted(self)
343 } else {
344 SourceCustody::Retained(self)
345 }
346 }
347 }
348}
349
350#[doc(hidden)]
355pub trait InterpretCreations<A, Interpreter, RootEvent, Path>: CreationSettlements<A>
356where
357 A: Address,
358{
359 fn interpret_creations(
360 creations: Creations<CreateChild<A, Self::Child>>,
361 interpreter: &mut Interpreter,
362 ) -> impl core::future::Future<Output = Interpretation<Self::Settlements>> + Send;
363}
364
365impl<A, Interpreter, RootEvent, Path> InterpretCreations<A, Interpreter, RootEvent, Path>
366 for NoBirths
367where
368 A: Address,
369{
370 fn interpret_creations(
371 _: Creations<CreateChild<A, Never>>,
372 _: &mut Interpreter,
373 ) -> impl core::future::Future<Output = Interpretation<Self::Settlements>> + Send {
374 core::future::ready(Interpretation::Complete(Creations::empty()))
375 }
376}
377
378impl<A, C, Interpreter, RootEvent, Path> InterpretCreations<A, Interpreter, RootEvent, Path>
379 for Births<C>
380where
381 A: Address,
382 A::Nonce: Send,
383 C: ChildCreationProduct<A, ChildHead> + DispatchBirth<A, Interpreter> + Send,
384 <C as ChildCreationProduct<A, ChildHead>>::Result: Send,
385 Interpreter: InterpretItem<Creations<CreateChild<A, C>>, RootEvent, Path> + Send,
386{
387 fn interpret_creations(
388 creations: Creations<CreateChild<A, C>>,
389 interpreter: &mut Interpreter,
390 ) -> impl core::future::Future<Output = Interpretation<Self::Settlements>> + Send {
391 async move {
392 let routed = match interpreter.interpret_item(creations).await {
393 ItemSettlement::Accepted(routed) => routed,
394 ItemSettlement::Rejected { item, reason } => {
395 return Interpretation::Complete(CreationSettlement::Rejected {
396 creations: item,
397 reason,
398 });
399 }
400 ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
401 ItemSettlement::Corrupt { item, fault } => {
402 return Interpretation::Corrupt(CreationSettlement::Corrupt {
403 creations: item,
404 fault,
405 });
406 }
407 };
408
409 let mut remaining = routed.into_iter();
410 let mut settled = Vec::with_capacity(remaining.len());
411 while let Some(creation) = remaining.next() {
412 let (creation, route) = creation.into_parts();
413 let (id, child, kind) = creation.into_parts();
414 let settlement = child.dispatch_birth(id, route, kind, interpreter).await;
415 match settlement {
416 corrupt @ ItemSettlement::Corrupt { .. } => {
417 settled.push(SettledItem::Attempted(corrupt));
418 settled.extend(remaining.map(SettledItem::Unattempted));
419 return Interpretation::Corrupt(CreationSettlement::Settled(
420 Creations::from_items(settled),
421 ));
422 }
423 creation => settled.push(SettledItem::Attempted(creation)),
424 }
425 }
426 Interpretation::Complete(CreationSettlement::Settled(Creations::from_items(settled)))
427 }
428 }
429}
430
431impl<A, C, Interpreter, RootEvent, Path> InterpretCreations<A, Interpreter, RootEvent, Path>
432 for RetirementBirths<C>
433where
434 A: Address,
435 C: ChildCreationProduct<A, ChildHead>,
436 Births<C>: BirthMode<Child = C> + InterpretCreations<A, Interpreter, RootEvent, Path>,
437{
438 fn interpret_creations(
439 creations: Creations<CreateChild<A, C>>,
440 interpreter: &mut Interpreter,
441 ) -> impl core::future::Future<Output = Interpretation<Self::Settlements>> + Send {
442 let interpretation =
443 <Births<C> as InterpretCreations<A, Interpreter, RootEvent, Path>>::interpret_creations(
444 creations,
445 interpreter,
446 );
447 async move { interpretation.await.map(RetirementCreationSettlement::new) }
448 }
449}
450
451impl<Creations, Sends, Ph> ClassifySettlement for ActionSettlement<Creations, Sends, Ph>
452where
453 Creations: ClassifySettlement,
454 Sends: ClassifySettlement,
455{
456 fn settlement_status(&self) -> SettlementStatus {
457 self.creations
458 .settlement_status()
459 .combine(self.sends.settlement_status())
460 }
461}
462
463impl<Host, RootEvent, Creations, Sends, Ph> SourceSettlementCustody<Host, RootEvent>
464 for ActionSettlement<Creations, Sends, Ph>
465where
466 Host: Send,
467 Creations: SourceSettlementCustody<Host, RootEvent> + Send,
468 Sends: SourceSettlementCustody<Host, RootEvent> + Send,
469 Ph: Send,
470{
471 fn offer_next_to_source(
472 self,
473 host: &mut Host,
474 ) -> impl core::future::Future<Output = SourceCustody<Self>> + Send {
475 async move {
476 let Self {
477 creations,
478 sends,
479 become_,
480 } = self;
481 offer_source_in_order(creations, sends, host)
482 .await
483 .map(|(creations, sends)| Self {
484 creations,
485 sends,
486 become_,
487 })
488 }
489 }
490}
491
492pub trait AppendSend<Input, Path>: Sized {
495 #[must_use]
497 fn append_send(self, input: Input) -> Self;
498}
499
500#[must_use = "actor transition effects must be interpreted, inspected, or retained"]
515pub struct Actions<A: Address, Ph, Sends, Birth: BirthMode> {
516 pub sends: Sends,
517 pub creates: Creations<CreateChild<A, Birth::Child>>,
518 pub become_: Become<Ph>,
519}
520
521impl<A, Ph, Sends, Birth> core::fmt::Debug for Actions<A, Ph, Sends, Birth>
522where
523 A: Address + core::fmt::Debug,
524 A::Nonce: core::fmt::Debug,
525 Ph: core::fmt::Debug,
526 Sends: core::fmt::Debug,
527 Birth: BirthMode,
528 Birth::Child: core::fmt::Debug,
529{
530 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
531 formatter
532 .debug_struct("Actions")
533 .field("sends", &self.sends)
534 .field("creates", &self.creates)
535 .field("become", &self.become_)
536 .finish()
537 }
538}
539
540impl<A, Ph, Sends, Birth> PartialEq for Actions<A, Ph, Sends, Birth>
541where
542 A: Address + PartialEq,
543 A::Nonce: PartialEq,
544 Ph: PartialEq,
545 Sends: PartialEq,
546 Birth: BirthMode,
547 Birth::Child: PartialEq,
548{
549 fn eq(&self, other: &Self) -> bool {
550 self.sends == other.sends && self.creates == other.creates && self.become_ == other.become_
551 }
552}
553
554impl<A, Ph, Sends, Birth> Eq for Actions<A, Ph, Sends, Birth>
555where
556 A: Address + Eq,
557 A::Nonce: Eq,
558 Ph: Eq,
559 Sends: Eq,
560 Birth: BirthMode,
561 Birth::Child: Eq,
562{
563}
564
565impl<A: Address, Ph, Sends, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
566 #[must_use]
569 pub fn map_sends<Mapped>(
570 self,
571 map: impl FnOnce(Sends) -> Mapped,
572 ) -> Actions<A, Ph, Mapped, Birth> {
573 Actions {
574 sends: map(self.sends),
575 creates: self.creates,
576 become_: self.become_,
577 }
578 }
579
580 #[must_use]
583 pub fn map_become<NextPh>(
584 self,
585 map: impl FnOnce(Become<Ph>) -> Become<NextPh>,
586 ) -> Actions<A, NextPh, Sends, Birth> {
587 Actions {
588 sends: self.sends,
589 creates: self.creates,
590 become_: map(self.become_),
591 }
592 }
593
594 #[must_use]
600 pub fn with_send<Input, Path>(mut self, input: Input) -> Self
601 where
602 Sends: SendInput<Input, Path>,
603 {
604 <Sends as SendInput<Input, Path>>::emit(&mut self.sends, input);
605 self
606 }
607
608 pub async fn interpret<Interpreter, RootEvent, Path>(
617 self,
618 interpreter: &mut Interpreter,
619 ) -> Interpretation<
620 ActionSettlement<Birth::Settlements, <Sends as SendSettlements>::Settlements, Ph>,
621 >
622 where
623 Ph: Send,
624 Sends: InterpretSends<Interpreter, RootEvent, Path>,
625 Birth: InterpretCreations<A, Interpreter, RootEvent, Path>,
626 Interpreter: Send,
627 {
628 let Actions {
629 sends,
630 creates,
631 become_,
632 } = self;
633 let creations = match Birth::interpret_creations(creates, interpreter).await {
634 Interpretation::Complete(creations) => creations,
635 Interpretation::Corrupt(creations) => {
636 return Interpretation::Corrupt(ActionSettlement {
637 creations,
638 sends: Sends::unattempted(sends),
639 become_,
640 });
641 }
642 };
643
644 match Sends::interpret(sends, interpreter).await {
645 Interpretation::Complete(sends) => Interpretation::Complete(ActionSettlement {
646 creations,
647 sends,
648 become_,
649 }),
650 Interpretation::Corrupt(sends) => Interpretation::Corrupt(ActionSettlement {
651 creations,
652 sends,
653 become_,
654 }),
655 }
656 }
657}
658
659impl<A, Ph, Sends, Birth, Input, Path> AppendSend<Input, Path> for Actions<A, Ph, Sends, Birth>
660where
661 A: Address,
662 Birth: BirthMode,
663 Sends: SendInput<Input, Path>,
664{
665 fn append_send(self, input: Input) -> Self {
666 self.with_send::<Input, Path>(input)
667 }
668}
669
670impl<A: Address, Ph, Sends: SendEffects, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
671 #[must_use]
672 pub const fn new(
673 sends: Sends,
674 creates: Creations<CreateChild<A, Birth::Child>>,
675 become_: Become<Ph>,
676 ) -> Self {
677 Self {
678 sends,
679 creates,
680 become_,
681 }
682 }
683
684 #[must_use]
685 pub fn just(become_: Become<Ph>) -> Self {
686 Self {
687 sends: Sends::empty(),
688 creates: Creations::empty(),
689 become_,
690 }
691 }
692
693 #[must_use]
694 pub fn cont() -> Self {
695 Self::just(Step::Continue)
696 }
697 #[must_use]
698 pub fn stop() -> Self {
699 Self::just(Step::Stop(Stopped))
700 }
701 #[must_use]
702 pub fn goto(phase: Ph) -> Self {
703 Self::just(Step::Goto(phase))
704 }
705
706 #[must_use]
708 pub fn send(sends: Sends) -> Self {
709 Self::new(sends, Creations::empty(), Step::Continue)
710 }
711
712 #[must_use]
714 pub fn create(creates: Creations<CreateChild<A, Birth::Child>>) -> Self {
715 Self::new(Sends::empty(), creates, Step::Continue)
716 }
717}
718
719impl<A: Address, Ph, Sends, Birth: BirthMode>
720 From<(Sends, Creations<CreateChild<A, Birth::Child>>, Become<Ph>)>
721 for Actions<A, Ph, Sends, Birth>
722{
723 fn from(
724 (sends, creates, become_): (Sends, Creations<CreateChild<A, Birth::Child>>, Become<Ph>),
725 ) -> Self {
726 Self {
727 sends,
728 creates,
729 become_,
730 }
731 }
732}
733
734pub type Acted<A, Ph, Sends, Birth, E> = Result<Actions<A, Ph, Sends, Birth>, E>;
735
736#[cfg(test)]
737mod tests {
738 use super::*;
739 use crate::{Births, CreationSequence, MailAddr, NoBirths, Own};
740
741 fn two_ids() -> (crate::CreationId, crate::CreationId) {
742 let mut sequence = CreationSequence::new();
743 let first = sequence.issue().expect("the first creation ID exists");
744 let second = sequence.issue().expect("the second creation ID exists");
745 (first, second)
746 }
747
748 #[test]
749 fn equality_and_debug_cover_every_named_effect_leg() {
750 type Plain = Actions<MailAddr, u8, Vec<u8>, NoBirths>;
751 type Creating = Actions<MailAddr, Never, Vec<u8>, Births<u8>>;
752
753 let value = Plain::new(vec![1], Creations::empty(), Step::Goto(3));
754 assert_eq!(
755 value,
756 Plain::new(vec![1], Creations::empty(), Step::Goto(3))
757 );
758 assert_ne!(
759 value,
760 Plain::new(vec![2], Creations::empty(), Step::Goto(3))
761 );
762 assert_ne!(
763 value,
764 Plain::new(vec![1], Creations::empty(), Step::Goto(4))
765 );
766 assert_ne!(
767 value,
768 Plain::new(vec![1], Creations::empty(), Step::Continue)
769 );
770 assert_eq!(
771 format!("{value:?}"),
772 "Actions { sends: [1], creates: Creations { items: [] }, become: Goto(3) }"
773 );
774
775 let (first, second) = two_ids();
776 let created = Creating::new(
777 Vec::new(),
778 Creations::one(CreateChild::birth(first, 9)),
779 Step::Continue,
780 );
781 let other_creation = Creating::new(
782 Vec::new(),
783 Creations::one(CreateChild::birth(second, 9)),
784 Step::Continue,
785 );
786 assert_ne!(created, other_creation);
787 }
788
789 #[test]
790 fn mapping_sends_preserves_creation_order_and_verdict() {
791 let (first, second) = two_ids();
792 let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
793 vec![1, 2],
794 Creations::one(CreateChild::birth(first, ())).and(CreateChild::replacement(
795 second,
796 first,
797 (),
798 )),
799 Step::Goto(7),
800 );
801
802 let mapped = actions.map_sends(|sends| sends.len());
803 assert_eq!(mapped.sends, 2);
804 assert_eq!(
805 mapped
806 .creates
807 .iter()
808 .map(CreateChild::id)
809 .collect::<Vec<_>>(),
810 [first, second]
811 );
812 assert!(matches!(mapped.become_, Step::Goto(7)));
813 }
814
815 #[test]
816 fn mapping_become_preserves_sends_and_creation_order() {
817 let (first, _) = two_ids();
818 let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
819 vec![1, 2],
820 Creations::one(CreateChild::birth(first, ())),
821 Step::Goto(7),
822 );
823
824 let mapped: Actions<MailAddr, Never, Vec<u8>, Births<()>> =
825 actions.map_become(|_| Step::Stop(Stopped));
826 assert_eq!(mapped.sends, [1, 2]);
827 assert_eq!(
828 mapped.creates.iter().next().map(CreateChild::id),
829 Some(first)
830 );
831 assert!(matches!(mapped.become_, Step::Stop(Stopped)));
832 }
833
834 #[test]
835 fn fluent_send_changes_only_the_selected_effect_leg() {
836 let (first, second) = two_ids();
837 let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
838 vec![1],
839 Creations::one(CreateChild::birth(first, ())).and(CreateChild::replacement(
840 second,
841 first,
842 (),
843 )),
844 Step::Goto(7),
845 )
846 .with_send::<_, Own>(2)
847 .with_send::<_, Own>(3);
848
849 assert_eq!(actions.sends, [1, 2, 3]);
850 assert_eq!(
851 actions
852 .creates
853 .iter()
854 .map(CreateChild::id)
855 .collect::<Vec<_>>(),
856 [first, second]
857 );
858 assert!(matches!(actions.become_, Step::Goto(7)));
859
860 let stopped: Actions<MailAddr, Never, Vec<u8>, NoBirths> =
861 Actions::stop().with_send::<_, Own>(5);
862 assert_eq!(stopped.sends, [5]);
863 assert!(matches!(stopped.become_, Step::Stop(Stopped)));
864 }
865}