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, RoutedCreation,
11};
12use crate::next::{Never, Step, Stopped};
13use crate::transition::{Behavior, BehaviorAddr};
14
15pub type Become<Ph = Never> = Step<Ph, Stopped>;
16
17#[derive(Clone, Debug, Eq, PartialEq)]
24pub struct ActionSettlement<Creations, Sends, Ph> {
25 pub creations: Creations,
26 pub sends: Sends,
27 pub become_: Become<Ph>,
28}
29
30#[doc(hidden)]
32#[derive(Clone, Debug, Eq, PartialEq)]
33pub enum CreationSettlement<Requests, Settlements> {
34 Settled(Settlements),
36 Rejected {
38 creations: Requests,
39 reason: ChildNamespaceExhausted,
40 },
41 Corrupt {
43 creations: Requests,
44 fault: InterpreterFault,
45 },
46}
47
48pub trait ActionSettlements {
54 type Settlements;
55}
56
57impl<A, Ph, Sends, Birth> ActionSettlements for Actions<A, Ph, Sends, Birth>
58where
59 A: Address,
60 Sends: SendSettlements,
61 Birth: CreationSettlements<A>,
62{
63 type Settlements = ActionSettlement<Birth::Settlements, Sends::Settlements, Ph>;
64}
65
66pub trait BehaviorSettlements: Behavior {
73 type Settlements;
74}
75
76impl<B> BehaviorSettlements for B
77where
78 B: Behavior,
79 B::Sends: SendSettlements,
80 B::Birth: CreationSettlements<BehaviorAddr<B>>,
81{
82 type Settlements =
83 <Actions<BehaviorAddr<B>, B::Ph, B::Sends, B::Birth> as ActionSettlements>::Settlements;
84}
85
86impl<Requests, Settlements> ClassifySettlement for CreationSettlement<Requests, Settlements>
87where
88 Settlements: ClassifySettlement,
89{
90 fn settlement_status(&self) -> SettlementStatus {
91 match self {
92 Self::Settled(settlements) => settlements.settlement_status(),
93 Self::Rejected { .. } => SettlementStatus::Rejected,
94 Self::Corrupt { .. } => SettlementStatus::Corrupt,
95 }
96 }
97}
98
99impl<Item> ClassifySettlement for Creations<Item>
100where
101 Item: ClassifySettlement,
102{
103 fn settlement_status(&self) -> SettlementStatus {
104 let mut status = SettlementStatus::Accepted;
105 for item in self.iter() {
106 status = status.combine(item.settlement_status());
107 }
108 status
109 }
110}
111
112#[doc(hidden)]
114pub trait CreationSettlements<A: Address>: BirthMode {
115 type Settlements: ClassifySettlement;
116}
117
118impl<A: Address> CreationSettlements<A> for NoBirths {
119 type Settlements = Creations<Never>;
120}
121
122impl<A, C> CreationSettlements<A> for Births<C>
123where
124 A: Address,
125 C: ChildCreationProduct<A, ChildHead>,
126{
127 type Settlements = CreationSettlement<
128 Creations<CreateChild<A, C>>,
129 Creations<
130 SettledItem<
131 RoutedCreation<A, C>,
132 ItemSettlement<
133 RoutedCreation<A, C>,
134 <C as ChildCreationProduct<A, ChildHead>>::Result,
135 CreationRejection,
136 Never,
137 >,
138 >,
139 >,
140 >;
141}
142
143#[doc(hidden)]
149#[must_use = "a returned creation batch must be admitted or retained"]
150pub struct CreationsSettled<A, C>
151where
152 A: Address,
153 C: ChildCreationProduct<A, ChildHead>,
154{
155 settlement: <Births<C> as CreationSettlements<A>>::Settlements,
156}
157
158impl<A, C> CreationsSettled<A, C>
159where
160 A: Address,
161 C: ChildCreationProduct<A, ChildHead>,
162{
163 #[must_use]
164 pub const fn new(settlement: <Births<C> as CreationSettlements<A>>::Settlements) -> Self {
165 Self { settlement }
166 }
167
168 #[must_use]
169 pub fn into_settlement(self) -> <Births<C> as CreationSettlements<A>>::Settlements {
170 self.settlement
171 }
172}
173
174impl<Host, RootEvent> SourceSettlementCustody<Host, RootEvent> for Creations<Never> {
175 fn offer_next_to_source(
176 self,
177 _: &mut Host,
178 ) -> impl core::future::Future<Output = SourceCustody<Self>> + Send {
179 core::future::ready(SourceCustody::Exhausted(self))
180 }
181}
182
183impl<A, C, Host, RootEvent> SourceSettlementCustody<Host, RootEvent>
184 for CreationSettlement<
185 Creations<CreateChild<A, C>>,
186 Creations<
187 SettledItem<
188 RoutedCreation<A, C>,
189 ItemSettlement<
190 RoutedCreation<A, C>,
191 <C as ChildCreationProduct<A, ChildHead>>::Result,
192 CreationRejection,
193 Never,
194 >,
195 >,
196 >,
197 >
198where
199 A: Address,
200 A::Nonce: Send,
201 C: ChildCreationProduct<A, ChildHead> + Send,
202 <C as ChildCreationProduct<A, ChildHead>>::Result: Send,
203 Host: SourceAdmission<RootEvent, Births<C>, CreationsSettled<A, C>>,
204 RootEvent: crate::EventIngress<Births<C>, CreationsSettled<A, C>>,
205{
206 fn offer_next_to_source(
207 self,
208 host: &mut Host,
209 ) -> impl core::future::Future<Output = SourceCustody<Self>> + Send {
210 async move {
211 if matches!(&self, CreationSettlement::Settled(settlements) if settlements.is_empty()) {
212 return SourceCustody::Exhausted(self);
213 }
214 match host.admit_source(CreationsSettled::new(self)).await {
215 Ok(()) => SourceCustody::Admitted(CreationSettlement::Settled(Creations::empty())),
216 Err(returned) => SourceCustody::Closed(returned.into_settlement()),
217 }
218 }
219 }
220}
221
222#[doc(hidden)]
227pub trait InterpretCreations<A, Interpreter, RootEvent, Path>: CreationSettlements<A>
228where
229 A: Address,
230{
231 fn interpret_creations(
232 creations: Creations<CreateChild<A, Self::Child>>,
233 interpreter: &mut Interpreter,
234 ) -> impl core::future::Future<Output = Interpretation<Self::Settlements>> + Send;
235}
236
237impl<A, Interpreter, RootEvent, Path> InterpretCreations<A, Interpreter, RootEvent, Path>
238 for NoBirths
239where
240 A: Address,
241{
242 fn interpret_creations(
243 _: Creations<CreateChild<A, Never>>,
244 _: &mut Interpreter,
245 ) -> impl core::future::Future<Output = Interpretation<Self::Settlements>> + Send {
246 core::future::ready(Interpretation::Complete(Creations::empty()))
247 }
248}
249
250impl<A, C, Interpreter, RootEvent, Path> InterpretCreations<A, Interpreter, RootEvent, Path>
251 for Births<C>
252where
253 A: Address,
254 A::Nonce: Send,
255 C: ChildCreationProduct<A, ChildHead> + DispatchBirth<A, Interpreter> + Send,
256 <C as ChildCreationProduct<A, ChildHead>>::Result: Send,
257 Interpreter: InterpretItem<Creations<CreateChild<A, C>>, RootEvent, Path> + Send,
258{
259 fn interpret_creations(
260 creations: Creations<CreateChild<A, C>>,
261 interpreter: &mut Interpreter,
262 ) -> impl core::future::Future<Output = Interpretation<Self::Settlements>> + Send {
263 async move {
264 let routed = match interpreter.interpret_item(creations).await {
265 ItemSettlement::Accepted(routed) => routed,
266 ItemSettlement::Rejected { item, reason } => {
267 return Interpretation::Complete(CreationSettlement::Rejected {
268 creations: item,
269 reason,
270 });
271 }
272 ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
273 ItemSettlement::Corrupt { item, fault } => {
274 return Interpretation::Corrupt(CreationSettlement::Corrupt {
275 creations: item,
276 fault,
277 });
278 }
279 };
280
281 let mut remaining = routed.into_iter();
282 let mut settled = Vec::with_capacity(remaining.len());
283 while let Some(creation) = remaining.next() {
284 let (creation, route) = creation.into_parts();
285 let (id, child, kind) = creation.into_parts();
286 let settlement = child.dispatch_birth(id, route, kind, interpreter).await;
287 match settlement {
288 corrupt @ ItemSettlement::Corrupt { .. } => {
289 settled.push(SettledItem::Attempted(corrupt));
290 settled.extend(remaining.map(SettledItem::Unattempted));
291 return Interpretation::Corrupt(CreationSettlement::Settled(
292 Creations::from_items(settled),
293 ));
294 }
295 creation => settled.push(SettledItem::Attempted(creation)),
296 }
297 }
298 Interpretation::Complete(CreationSettlement::Settled(Creations::from_items(settled)))
299 }
300 }
301}
302
303impl<Creations, Sends, Ph> ClassifySettlement for ActionSettlement<Creations, Sends, Ph>
304where
305 Creations: ClassifySettlement,
306 Sends: ClassifySettlement,
307{
308 fn settlement_status(&self) -> SettlementStatus {
309 self.creations
310 .settlement_status()
311 .combine(self.sends.settlement_status())
312 }
313}
314
315impl<Host, RootEvent, Creations, Sends, Ph> SourceSettlementCustody<Host, RootEvent>
316 for ActionSettlement<Creations, Sends, Ph>
317where
318 Host: Send,
319 Creations: SourceSettlementCustody<Host, RootEvent> + Send,
320 Sends: SourceSettlementCustody<Host, RootEvent> + Send,
321 Ph: Send,
322{
323 fn offer_next_to_source(
324 self,
325 host: &mut Host,
326 ) -> impl core::future::Future<Output = SourceCustody<Self>> + Send {
327 async move {
328 let Self {
329 creations,
330 sends,
331 become_,
332 } = self;
333 offer_source_in_order(creations, sends, host)
334 .await
335 .map(|(creations, sends)| Self {
336 creations,
337 sends,
338 become_,
339 })
340 }
341 }
342}
343
344pub trait AppendSend<Input, Path>: Sized {
347 #[must_use]
349 fn append_send(self, input: Input) -> Self;
350}
351
352#[must_use = "actor transition effects must be interpreted, inspected, or retained"]
367pub struct Actions<A: Address, Ph, Sends, Birth: BirthMode> {
368 pub sends: Sends,
369 pub creates: Creations<CreateChild<A, Birth::Child>>,
370 pub become_: Become<Ph>,
371}
372
373impl<A, Ph, Sends, Birth> core::fmt::Debug for Actions<A, Ph, Sends, Birth>
374where
375 A: Address + core::fmt::Debug,
376 A::Nonce: core::fmt::Debug,
377 Ph: core::fmt::Debug,
378 Sends: core::fmt::Debug,
379 Birth: BirthMode,
380 Birth::Child: core::fmt::Debug,
381{
382 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
383 formatter
384 .debug_struct("Actions")
385 .field("sends", &self.sends)
386 .field("creates", &self.creates)
387 .field("become", &self.become_)
388 .finish()
389 }
390}
391
392impl<A, Ph, Sends, Birth> PartialEq for Actions<A, Ph, Sends, Birth>
393where
394 A: Address + PartialEq,
395 A::Nonce: PartialEq,
396 Ph: PartialEq,
397 Sends: PartialEq,
398 Birth: BirthMode,
399 Birth::Child: PartialEq,
400{
401 fn eq(&self, other: &Self) -> bool {
402 self.sends == other.sends && self.creates == other.creates && self.become_ == other.become_
403 }
404}
405
406impl<A, Ph, Sends, Birth> Eq for Actions<A, Ph, Sends, Birth>
407where
408 A: Address + Eq,
409 A::Nonce: Eq,
410 Ph: Eq,
411 Sends: Eq,
412 Birth: BirthMode,
413 Birth::Child: Eq,
414{
415}
416
417impl<A: Address, Ph, Sends, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
418 #[must_use]
421 pub fn map_sends<Mapped>(
422 self,
423 map: impl FnOnce(Sends) -> Mapped,
424 ) -> Actions<A, Ph, Mapped, Birth> {
425 Actions {
426 sends: map(self.sends),
427 creates: self.creates,
428 become_: self.become_,
429 }
430 }
431
432 #[must_use]
435 pub fn map_become<NextPh>(
436 self,
437 map: impl FnOnce(Become<Ph>) -> Become<NextPh>,
438 ) -> Actions<A, NextPh, Sends, Birth> {
439 Actions {
440 sends: self.sends,
441 creates: self.creates,
442 become_: map(self.become_),
443 }
444 }
445
446 #[must_use]
452 pub fn with_send<Input, Path>(mut self, input: Input) -> Self
453 where
454 Sends: SendInput<Input, Path>,
455 {
456 <Sends as SendInput<Input, Path>>::emit(&mut self.sends, input);
457 self
458 }
459
460 pub async fn interpret<Interpreter, RootEvent, Path>(
469 self,
470 interpreter: &mut Interpreter,
471 ) -> Interpretation<
472 ActionSettlement<Birth::Settlements, <Sends as SendSettlements>::Settlements, Ph>,
473 >
474 where
475 Ph: Send,
476 Sends: InterpretSends<Interpreter, RootEvent, Path>,
477 Birth: InterpretCreations<A, Interpreter, RootEvent, Path>,
478 Interpreter: Send,
479 {
480 let Actions {
481 sends,
482 creates,
483 become_,
484 } = self;
485 let creations = match Birth::interpret_creations(creates, interpreter).await {
486 Interpretation::Complete(creations) => creations,
487 Interpretation::Corrupt(creations) => {
488 return Interpretation::Corrupt(ActionSettlement {
489 creations,
490 sends: Sends::unattempted(sends),
491 become_,
492 });
493 }
494 };
495
496 match Sends::interpret(sends, interpreter).await {
497 Interpretation::Complete(sends) => Interpretation::Complete(ActionSettlement {
498 creations,
499 sends,
500 become_,
501 }),
502 Interpretation::Corrupt(sends) => Interpretation::Corrupt(ActionSettlement {
503 creations,
504 sends,
505 become_,
506 }),
507 }
508 }
509}
510
511impl<A, Ph, Sends, Birth, Input, Path> AppendSend<Input, Path> for Actions<A, Ph, Sends, Birth>
512where
513 A: Address,
514 Birth: BirthMode,
515 Sends: SendInput<Input, Path>,
516{
517 fn append_send(self, input: Input) -> Self {
518 self.with_send::<Input, Path>(input)
519 }
520}
521
522impl<A: Address, Ph, Sends: SendEffects, Birth: BirthMode> Actions<A, Ph, Sends, Birth> {
523 #[must_use]
524 pub const fn new(
525 sends: Sends,
526 creates: Creations<CreateChild<A, Birth::Child>>,
527 become_: Become<Ph>,
528 ) -> Self {
529 Self {
530 sends,
531 creates,
532 become_,
533 }
534 }
535
536 #[must_use]
537 pub fn just(become_: Become<Ph>) -> Self {
538 Self {
539 sends: Sends::empty(),
540 creates: Creations::empty(),
541 become_,
542 }
543 }
544
545 #[must_use]
546 pub fn cont() -> Self {
547 Self::just(Step::Continue)
548 }
549 #[must_use]
550 pub fn stop() -> Self {
551 Self::just(Step::Stop(Stopped))
552 }
553 #[must_use]
554 pub fn goto(phase: Ph) -> Self {
555 Self::just(Step::Goto(phase))
556 }
557
558 #[must_use]
560 pub fn send(sends: Sends) -> Self {
561 Self::new(sends, Creations::empty(), Step::Continue)
562 }
563
564 #[must_use]
566 pub fn create(creates: Creations<CreateChild<A, Birth::Child>>) -> Self {
567 Self::new(Sends::empty(), creates, Step::Continue)
568 }
569}
570
571impl<A: Address, Ph, Sends, Birth: BirthMode>
572 From<(Sends, Creations<CreateChild<A, Birth::Child>>, Become<Ph>)>
573 for Actions<A, Ph, Sends, Birth>
574{
575 fn from(
576 (sends, creates, become_): (Sends, Creations<CreateChild<A, Birth::Child>>, Become<Ph>),
577 ) -> Self {
578 Self {
579 sends,
580 creates,
581 become_,
582 }
583 }
584}
585
586pub type Acted<A, Ph, Sends, Birth, E> = Result<Actions<A, Ph, Sends, Birth>, E>;
587
588#[cfg(test)]
589mod tests {
590 use super::*;
591 use crate::{Births, CreationSequence, MailAddr, NoBirths, Own};
592
593 fn two_ids() -> (crate::CreationId, crate::CreationId) {
594 let mut sequence = CreationSequence::new();
595 let first = sequence.issue().expect("the first creation ID exists");
596 let second = sequence.issue().expect("the second creation ID exists");
597 (first, second)
598 }
599
600 #[test]
601 fn equality_and_debug_cover_every_named_effect_leg() {
602 type Plain = Actions<MailAddr, u8, Vec<u8>, NoBirths>;
603 type Creating = Actions<MailAddr, Never, Vec<u8>, Births<u8>>;
604
605 let value = Plain::new(vec![1], Creations::empty(), Step::Goto(3));
606 assert_eq!(
607 value,
608 Plain::new(vec![1], Creations::empty(), Step::Goto(3))
609 );
610 assert_ne!(
611 value,
612 Plain::new(vec![2], Creations::empty(), Step::Goto(3))
613 );
614 assert_ne!(
615 value,
616 Plain::new(vec![1], Creations::empty(), Step::Goto(4))
617 );
618 assert_ne!(
619 value,
620 Plain::new(vec![1], Creations::empty(), Step::Continue)
621 );
622 assert_eq!(
623 format!("{value:?}"),
624 "Actions { sends: [1], creates: Creations { items: [] }, become: Goto(3) }"
625 );
626
627 let (first, second) = two_ids();
628 let created = Creating::new(
629 Vec::new(),
630 Creations::one(CreateChild::birth(first, 9)),
631 Step::Continue,
632 );
633 let other_creation = Creating::new(
634 Vec::new(),
635 Creations::one(CreateChild::birth(second, 9)),
636 Step::Continue,
637 );
638 assert_ne!(created, other_creation);
639 }
640
641 #[test]
642 fn mapping_sends_preserves_creation_order_and_verdict() {
643 let (first, second) = two_ids();
644 let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
645 vec![1, 2],
646 Creations::one(CreateChild::birth(first, ())).and(CreateChild::replacement(
647 second,
648 first,
649 (),
650 )),
651 Step::Goto(7),
652 );
653
654 let mapped = actions.map_sends(|sends| sends.len());
655 assert_eq!(mapped.sends, 2);
656 assert_eq!(
657 mapped
658 .creates
659 .iter()
660 .map(CreateChild::id)
661 .collect::<Vec<_>>(),
662 [first, second]
663 );
664 assert!(matches!(mapped.become_, Step::Goto(7)));
665 }
666
667 #[test]
668 fn mapping_become_preserves_sends_and_creation_order() {
669 let (first, _) = two_ids();
670 let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
671 vec![1, 2],
672 Creations::one(CreateChild::birth(first, ())),
673 Step::Goto(7),
674 );
675
676 let mapped: Actions<MailAddr, Never, Vec<u8>, Births<()>> =
677 actions.map_become(|_| Step::Stop(Stopped));
678 assert_eq!(mapped.sends, [1, 2]);
679 assert_eq!(
680 mapped.creates.iter().next().map(CreateChild::id),
681 Some(first)
682 );
683 assert!(matches!(mapped.become_, Step::Stop(Stopped)));
684 }
685
686 #[test]
687 fn fluent_send_changes_only_the_selected_effect_leg() {
688 let (first, second) = two_ids();
689 let actions: Actions<MailAddr, u8, Vec<u8>, Births<()>> = Actions::new(
690 vec![1],
691 Creations::one(CreateChild::birth(first, ())).and(CreateChild::replacement(
692 second,
693 first,
694 (),
695 )),
696 Step::Goto(7),
697 )
698 .with_send::<_, Own>(2)
699 .with_send::<_, Own>(3);
700
701 assert_eq!(actions.sends, [1, 2, 3]);
702 assert_eq!(
703 actions
704 .creates
705 .iter()
706 .map(CreateChild::id)
707 .collect::<Vec<_>>(),
708 [first, second]
709 );
710 assert!(matches!(actions.become_, Step::Goto(7)));
711
712 let stopped: Actions<MailAddr, Never, Vec<u8>, NoBirths> =
713 Actions::stop().with_send::<_, Own>(5);
714 assert_eq!(stopped.sends, [5]);
715 assert!(matches!(stopped.become_, Step::Stop(Stopped)));
716 }
717}