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