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