Skip to main content

behavior/actor/
creation.rs

1//! Staged fresh-actor creation capabilities.
2
3use core::future::Future;
4use core::marker::PhantomData;
5use core::num::NonZeroU64;
6
7use super::addressing::{Address, EndpointAddress, EstablishedActor, EstablishedRecipient};
8use crate::next::Never;
9use crate::{
10    ActionItem, Actions, Behavior, BehaviorAddr, BehaviorBase, ItemSettlement, Protocol,
11    SettledItem,
12};
13
14/// Correlation for one staged creation within a static child occurrence.
15///
16/// This value is neither an actor address nor a runtime route. Its constructor
17/// is private so only a [`CreationSequence`] can issue it.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub struct CreationId(NonZeroU64);
20
21impl CreationId {
22    /// Return the occurrence-local numeric value for protocols that derive
23    /// another correlation from this creation.
24    #[doc(hidden)]
25    #[must_use]
26    pub const fn get(self) -> u64 {
27        self.0.get()
28    }
29}
30
31/// Checked source of IDs that are not reused within one child occurrence.
32#[derive(Debug, PartialEq, Eq)]
33pub struct CreationSequence {
34    next: Option<NonZeroU64>,
35}
36
37impl CreationSequence {
38    /// Begin a fresh sequence for one child occurrence.
39    #[must_use]
40    pub const fn new() -> Self {
41        Self {
42            next: Some(NonZeroU64::MIN),
43        }
44    }
45
46    /// Issue the next ID, or return absence after the finite sequence is
47    /// exhausted. Exhaustion leaves the sequence unchanged.
48    pub fn issue(&mut self) -> Option<CreationId> {
49        let value = self.next?;
50        self.next = value.checked_add(1);
51        Some(CreationId(value))
52    }
53}
54
55impl Default for CreationSequence {
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61/// Behavior-owned provenance for a staged fresh actor creation request.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum CreationKind {
64    /// An initial or ordinary later birth.
65    Birth,
66    /// A fresh successor requested by a replacement protocol.
67    Replacement {
68        /// Creator-local ID of the exact child this request supersedes.
69        previous: CreationId,
70    },
71}
72
73impl CreationKind {
74    #[must_use]
75    pub const fn replacement(previous: CreationId) -> Self {
76        Self::Replacement { previous }
77    }
78}
79
80/// A staged request to establish one fresh child.
81///
82/// The ID is correlation within the request's static child occurrence, not an
83/// address, route, actor identity, or proof of freshness. The kind is
84/// Behavior-owned intent. Replacement at an existing address is deliberately
85/// absent; stable identity is derived with a proxy actor.
86///
87/// ```compile_fail
88/// let mut creations = behavior::CreationSequence::new();
89/// let id = creations.issue().expect("the first child ID exists");
90/// let _ = behavior::CreateChild::<behavior::MailAddr, ()>::new(
91///     id,
92///     (),
93///     behavior::CreationKind::Birth,
94/// );
95/// ```
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub struct CreateChild<A: Address, New> {
98    id: CreationId,
99    child: New,
100    kind: CreationKind,
101    address: PhantomData<fn() -> A>,
102}
103
104impl<A: Address, New> CreateChild<A, New> {
105    #[must_use]
106    pub(crate) const fn from_parts(id: CreationId, child: New, kind: CreationKind) -> Self {
107        Self {
108            id,
109            child,
110            kind,
111            address: PhantomData,
112        }
113    }
114
115    #[must_use]
116    pub const fn birth(id: CreationId, child: New) -> Self {
117        Self::from_parts(id, child, CreationKind::Birth)
118    }
119
120    #[must_use]
121    pub const fn replacement(id: CreationId, previous: CreationId, child: New) -> Self {
122        Self::from_parts(id, child, CreationKind::replacement(previous))
123    }
124
125    #[must_use]
126    pub const fn id(&self) -> CreationId {
127        self.id
128    }
129
130    #[must_use]
131    pub const fn kind(&self) -> CreationKind {
132        self.kind
133    }
134
135    #[must_use]
136    pub const fn child(&self) -> &New {
137        &self.child
138    }
139
140    #[doc(hidden)]
141    #[must_use]
142    pub fn into_parts(self) -> (CreationId, New, CreationKind) {
143        (self.id, self.child, self.kind)
144    }
145}
146
147/// One ordered creation batch.
148///
149/// The batch is the all-or-none unit for runtime route preparation. After
150/// routing succeeds, each child still settles independently in this declared
151/// order.
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct Creations<Item> {
154    items: Vec<Item>,
155}
156
157impl<Item> Creations<Item> {
158    /// Construct an empty creation batch.
159    #[must_use]
160    pub const fn empty() -> Self {
161        Self { items: Vec::new() }
162    }
163
164    #[must_use]
165    pub fn one(item: Item) -> Self {
166        Self { items: vec![item] }
167    }
168
169    #[must_use]
170    pub fn and(mut self, item: Item) -> Self {
171        self.items.push(item);
172        self
173    }
174
175    /// Transform every item while preserving declared order and cardinality.
176    #[must_use]
177    pub fn map<Mapped>(self, mut map: impl FnMut(Item) -> Mapped) -> Creations<Mapped> {
178        Creations::from_items(self.items.into_iter().map(&mut map).collect())
179    }
180
181    #[must_use]
182    pub fn len(&self) -> usize {
183        self.items.len()
184    }
185
186    #[must_use]
187    pub fn is_empty(&self) -> bool {
188        self.items.is_empty()
189    }
190
191    pub(crate) fn from_items(items: Vec<Item>) -> Self {
192        Self { items }
193    }
194
195    pub fn iter(&self) -> core::slice::Iter<'_, Item> {
196        self.items.iter()
197    }
198}
199
200impl<Item> Default for Creations<Item> {
201    fn default() -> Self {
202        Self::empty()
203    }
204}
205
206impl<Item> Extend<Item> for Creations<Item> {
207    fn extend<Items: IntoIterator<Item = Item>>(&mut self, items: Items) {
208        self.items.extend(items);
209    }
210}
211
212impl<Item> FromIterator<Item> for Creations<Item> {
213    fn from_iter<Items: IntoIterator<Item = Item>>(items: Items) -> Self {
214        Self::from_items(items.into_iter().collect())
215    }
216}
217
218impl<'a, Item> IntoIterator for &'a Creations<Item> {
219    type Item = &'a Item;
220    type IntoIter = core::slice::Iter<'a, Item>;
221
222    fn into_iter(self) -> Self::IntoIter {
223        self.iter()
224    }
225}
226
227impl<Item> IntoIterator for Creations<Item> {
228    type Item = Item;
229    type IntoIter = std::vec::IntoIter<Item>;
230
231    fn into_iter(self) -> Self::IntoIter {
232        self.items.into_iter()
233    }
234}
235
236/// Static proof that `Role` names one exact direct child of `Parent`.
237///
238/// Behavior authoring owns this relationship. A runtime may use the proof to
239/// build application topology, but the role itself allocates nothing and is
240/// not evidence that the child was created or installed.
241pub trait ChildRole<Parent: Behavior> {
242    /// The only child behavior accepted at this role.
243    type Child: Behavior;
244
245    /// Structural position of this role in `Parent`'s closed child sum.
246    type Position: ChildPosition<<Parent::Birth as BirthMode>::Child, Self::Child>;
247}
248
249/// Declares how one effect occurrence is resolved from an authored parent.
250///
251/// This is topology metadata, not actor identity or a runtime capability.
252/// Generated nominal roles implement it with their declared parent, child,
253/// and structural position. [`ChildHead`] and [`ChildTail`] implement it as
254/// raw structural positions. Consumers normally use
255/// [`ResolveChildOccurrence`] rather than inspecting `Resolution`.
256///
257/// Manually authored roles may implement this trait as the power-user path by
258/// selecting [`DeclaredChildOccurrence`] with the same relationship expressed
259/// by their [`ChildRole`] implementation. The actual resolution contract is
260/// sealed, so downstream code cannot redefine wrapper transparency or replace
261/// structural resolution with a runtime lookup.
262pub trait ChildOccurrence<Parent: Behavior>: Sized {
263    /// Sealed descriptor interpreted by [`ResolveChildOccurrence`].
264    #[doc(hidden)]
265    type Resolution: ChildOccurrenceResolution<Parent, Self>;
266}
267
268/// Sealed descriptor for one nominal child occurrence declared by `Parent`.
269///
270/// This type exists so generated and manually authored roles can carry their
271/// static declaration into the sealed resolver. It has no values or runtime
272/// behavior.
273#[doc(hidden)]
274pub struct DeclaredChildOccurrence;
275
276/// Sealed descriptor for a raw structural child position.
277///
278/// This type has no values or runtime behavior.
279#[doc(hidden)]
280pub struct StructuralChildOccurrence<Position>(PhantomData<fn() -> Position>);
281
282/// Resolve an effect's nominal or structural occurrence against the concrete
283/// behavior currently being interpreted.
284///
285/// This is a sealed, type-level derived construction. It performs no lookup,
286/// allocates no actor, and introduces no second identity: the resolved child's
287/// [`Behavior::Protocol`] remains canonical identity, while `Position` is only
288/// navigation evidence into the emitter's direct birth algebra.
289///
290/// A nominal role follows [`BehaviorBase`] through a wrapper only when the
291/// wrapper preserves the exact protocol and the role's declared child at its
292/// exact structural position. A wrapper may append births after that position,
293/// but it cannot replace, reorder, or insert births before it. Raw
294/// [`ChildHead`] and [`ChildTail`] positions instead resolve directly against
295/// the running emitter's own birth algebra.
296///
297/// A wrapper that replaces its base role's child cannot silently reuse that
298/// role:
299///
300/// ```compile_fail
301/// use behavior::{
302///     Actions, Behavior, BehaviorActed, BehaviorBase, Births, ChildHead,
303///     ChildOccurrence, ChildRole, DeclaredChildOccurrence, MailAddr, Never,
304///     NoBirths, NoSends, Protocol, ResolveChildOccurrence,
305/// };
306///
307/// struct ActorProtocol;
308/// impl Protocol for ActorProtocol {
309///     type Addr = MailAddr;
310///     type Msg = Never;
311/// }
312///
313/// macro_rules! inert {
314///     ($actor:ident, $birth:ty) => {
315///         struct $actor;
316///         impl Behavior for $actor {
317///             type Protocol = ActorProtocol;
318///             type Event = Never;
319///             type Sends = NoSends;
320///             type Ph = Never;
321///             type Error = Never;
322///             type Birth = $birth;
323///             fn transition(
324///                 &mut self,
325///                 _: behavior::ActiveTurn,
326///                 event: Never,
327///             ) -> BehaviorActed<Self> {
328///                 match event {}
329///             }
330///         }
331///     };
332/// }
333/// inert!(Child, NoBirths);
334/// inert!(Proxy, NoBirths);
335/// inert!(Parent, Births<Child>);
336/// inert!(ChangedTopology, Births<Proxy>);
337///
338/// impl BehaviorBase for Parent {
339///     type Base = Self;
340///     fn base(&self) -> &Self { self }
341/// }
342/// impl BehaviorBase for ChangedTopology {
343///     type Base = Parent;
344///     fn base(&self) -> &Parent { unreachable!() }
345/// }
346///
347/// struct WorkerRole;
348/// impl ChildRole<Parent> for WorkerRole {
349///     type Child = Child;
350///     type Position = ChildHead;
351/// }
352/// impl ChildOccurrence<Parent> for WorkerRole {
353///     type Resolution = DeclaredChildOccurrence;
354/// }
355///
356/// fn require<T: ResolveChildOccurrence<WorkerRole>>() {}
357/// require::<ChangedTopology>();
358/// ```
359pub trait ResolveChildOccurrence<Occurrence>:
360    Behavior + sealed::ResolveChildOccurrence<Occurrence>
361{
362    /// Exact concrete child behavior at this occurrence.
363    type Child: Behavior;
364
365    /// Exact structural position in this emitter's direct birth algebra.
366    type Position: ChildPosition<<Self::Birth as BirthMode>::Child, Self::Child>;
367}
368
369impl<Emitter, Occurrence> ResolveChildOccurrence<Occurrence> for Emitter
370where
371    Emitter: Behavior + BehaviorBase + sealed::ResolveChildOccurrence<Occurrence>,
372    Emitter::Base: Behavior,
373    Occurrence: ChildOccurrence<Emitter::Base>,
374    Occurrence::Resolution: ResolveChildOccurrenceDescriptor<Emitter, Occurrence>,
375{
376    type Child =
377        <Occurrence::Resolution as ResolveChildOccurrenceDescriptor<Emitter, Occurrence>>::Child;
378    type Position =
379        <Occurrence::Resolution as ResolveChildOccurrenceDescriptor<Emitter, Occurrence>>::Position;
380}
381
382/// Child behavior resolved from `Occurrence` for the running `Emitter`.
383pub type ResolvedChild<Emitter, Occurrence> =
384    <Emitter as ResolveChildOccurrence<Occurrence>>::Child;
385
386/// Structural birth position resolved from `Occurrence` for the running
387/// `Emitter`.
388pub type ResolvedChildPosition<Emitter, Occurrence> =
389    <Emitter as ResolveChildOccurrence<Occurrence>>::Position;
390
391/// Child behavior selected by one named role.
392pub type RoleChild<Parent, Role> = <Role as ChildRole<Parent>>::Child;
393
394/// Canonical protocol selected by one named role.
395pub type RoleProtocol<Parent, Role> = <RoleChild<Parent, Role> as Behavior>::Protocol;
396
397/// One complete creation paired with a route selected by the interpreter.
398///
399/// Behavior never constructs or stores this value. It exists only between the
400/// generic batch-routing step and the concrete child host, and it returns
401/// complete on rejection or corruption.
402#[doc(hidden)]
403#[derive(Debug, Clone, PartialEq, Eq)]
404pub struct RoutedCreation<A: Address, New> {
405    creation: CreateChild<A, New>,
406    route: A::Nonce,
407}
408
409impl<A: Address, New> RoutedCreation<A, New> {
410    /// Pair one creation with the route selected by the current runtime.
411    #[must_use]
412    pub const fn new(creation: CreateChild<A, New>, route: A::Nonce) -> Self {
413        Self { creation, route }
414    }
415
416    #[must_use]
417    pub const fn id(&self) -> CreationId {
418        self.creation.id()
419    }
420
421    #[must_use]
422    pub const fn kind(&self) -> CreationKind {
423        self.creation.kind()
424    }
425
426    #[must_use]
427    pub const fn route(&self) -> A::Nonce {
428        self.route
429    }
430
431    #[must_use]
432    pub fn into_parts(self) -> (CreateChild<A, New>, A::Nonce) {
433        (self.creation, self.route)
434    }
435}
436
437/// Failure to claim an address fresh with respect to the current actor
438/// configuration.
439#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
440pub enum AllocationRejection {
441    /// The allocator has no address it can presently claim.
442    #[error("fresh actor-address allocation is exhausted")]
443    Exhausted,
444    /// The proposed address was already claimed; accepting it would violate
445    /// actor-name freshness.
446    #[error("the proposed actor address is already claimed")]
447    AddressAlreadyClaimed,
448}
449
450/// Complete semantic rejection of one staged fresh creation.
451#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
452pub enum CreationRejection {
453    /// Fresh address allocation failed.
454    #[error("fresh allocation failed: {0}")]
455    Allocation(AllocationRejection),
456    /// The child's initialization fold did not complete successfully.
457    #[error("child initialization failed")]
458    InitializationFailed,
459    /// Installation or commit failed after allocation.
460    #[error("the interpreter could not install and commit the child")]
461    EnvironmentFailed,
462}
463
464/// The creator namespace cannot route an entire declared creation batch.
465#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
466#[error("the creator child namespace is exhausted")]
467pub struct ChildNamespaceExhausted;
468
469impl<A, New> ActionItem for Creations<CreateChild<A, New>>
470where
471    A: Address,
472    A::Nonce: Send,
473    New: Send,
474{
475    type Accepted = Creations<RoutedCreation<A, New>>;
476    type Rejection = ChildNamespaceExhausted;
477    type Prerequisite = Never;
478}
479
480/// Committed or rejected result for one exact child-protocol occurrence.
481///
482/// `Installed` is constructed only after fresh allocation, successful
483/// initialization, endpoint establishment, and creator-local binding. It returns the
484/// exact protocol capability. `Rejected` carries no capability, so a
485/// failed request cannot be used as an established destination. Both variants
486/// preserve Behavior-authored creation provenance.
487///
488/// `Occurrence` is topology navigation evidence authored by the parent. It
489/// distinguishes duplicate occurrences without becoming another protocol
490/// identity or runtime key. `P` remains canonical identity. The concrete child
491/// behavior is deliberately absent: consumers that only retain or communicate
492/// with the installed protocol do not have to pretend to be parent actors.
493///
494/// Duplicate occurrences remain incompatible even when their protocols and
495/// endpoint representations match:
496///
497/// ```compile_fail
498/// use behavior::{
499///     Address, CreationKind, CreationSequence, EndpointAddress, EstablishedCreation,
500///     EstablishedRecipient, Protocol,
501/// };
502/// #[derive(Clone, Copy, PartialEq, Eq)]
503/// struct RuntimeAddr(u64);
504/// impl Address for RuntimeAddr { type Nonce = u64; }
505/// struct Endpoint;
506/// impl Clone for Endpoint { fn clone(&self) -> Self { Self } }
507/// impl EndpointAddress for RuntimeAddr {
508///     type Established<P> = Endpoint where P: Protocol<Addr = Self>;
509/// }
510/// struct Worker;
511/// impl Protocol for Worker { type Addr = RuntimeAddr; type Msg = (); }
512/// struct Primary;
513/// struct Backup;
514/// fn accepts_primary(_: EstablishedCreation<Worker, Primary>) {}
515/// let mut sequence = CreationSequence::new();
516/// let id = sequence.issue().expect("fixture creation ID");
517/// let backup: EstablishedCreation<Worker, Backup> = EstablishedCreation::installed(
518///     id,
519///     CreationKind::Birth,
520///     EstablishedRecipient::issued(Endpoint),
521/// );
522/// accepts_primary(backup);
523/// ```
524pub enum EstablishedCreation<P, Occurrence>
525where
526    P: Protocol,
527    P::Addr: EndpointAddress,
528{
529    Installed {
530        id: CreationId,
531        kind: CreationKind,
532        recipient: EstablishedRecipient<P>,
533        occurrence: PhantomData<fn() -> Occurrence>,
534    },
535    Rejected {
536        id: CreationId,
537        kind: CreationKind,
538        reason: CreationRejection,
539        occurrence: PhantomData<fn() -> Occurrence>,
540    },
541}
542
543impl<P, Occurrence> EstablishedCreation<P, Occurrence>
544where
545    P: Protocol,
546    P::Addr: EndpointAddress,
547{
548    #[must_use]
549    pub const fn installed(
550        id: CreationId,
551        kind: CreationKind,
552        recipient: EstablishedRecipient<P>,
553    ) -> Self {
554        Self::Installed {
555            id,
556            kind,
557            recipient,
558            occurrence: PhantomData,
559        }
560    }
561
562    #[must_use]
563    pub const fn rejected(id: CreationId, kind: CreationKind, reason: CreationRejection) -> Self {
564        Self::Rejected {
565            id,
566            kind,
567            reason,
568            occurrence: PhantomData,
569        }
570    }
571
572    #[must_use]
573    pub const fn id(&self) -> CreationId {
574        match self {
575            Self::Installed { id, .. } | Self::Rejected { id, .. } => *id,
576        }
577    }
578
579    #[must_use]
580    pub const fn kind(&self) -> CreationKind {
581        match self {
582            Self::Installed { kind, .. } | Self::Rejected { kind, .. } => *kind,
583        }
584    }
585
586    /// Consume the report and return its exact endpoint capability.
587    ///
588    /// # Errors
589    /// Returns the original [`CreationRejection`] when child creation did not
590    /// commit.
591    pub fn into_recipient(self) -> Result<EstablishedRecipient<P>, CreationRejection> {
592        match self {
593            Self::Installed { recipient, .. } => Ok(recipient),
594            Self::Rejected { reason, .. } => Err(reason),
595        }
596    }
597
598    /// Recover the concrete installed-actor proof when this occurrence is a
599    /// declared role of `Parent`.
600    ///
601    /// `Parent` is used only as compile-time topology evidence at this
602    /// capability-strengthening boundary; it is not part of the creation-report
603    /// identity. Ordinary consumers can retain [`EstablishedRecipient<P>`]
604    /// without carrying the parent behavior.
605    ///
606    /// # Errors
607    /// Returns the original [`CreationRejection`] when child creation did not
608    /// commit.
609    pub fn into_actor<Parent>(
610        self,
611    ) -> Result<EstablishedActor<RoleChild<Parent, Occurrence>>, CreationRejection>
612    where
613        Parent: Behavior,
614        Occurrence: ChildRole<Parent>,
615        RoleChild<Parent, Occurrence>: Behavior<Protocol = P>,
616    {
617        self.into_recipient().map(EstablishedActor::from_recipient)
618    }
619}
620
621/// Complete result after a runtime accepts one child definition.
622///
623/// A created child leaves only its exact established capability. Rejection
624/// during the pure initialization transition returns the current child and its
625/// exact error. Rejection while establishing the host returns the current child
626/// and the still-uninterpreted initialization actions. No variant reconstructs
627/// a pre-initialization value or silently discards an affine action.
628pub enum ChildCreationOutcome<C, Occurrence>
629where
630    C: Behavior,
631    BehaviorAddr<C>: EndpointAddress,
632{
633    /// Fresh child creation committed successfully.
634    Established {
635        /// Exact capability and creation provenance for this occurrence.
636        established: EstablishedCreation<C::Protocol, Occurrence>,
637    },
638    /// The child's pure initialization transition rejected before host commit.
639    InitializationRejected {
640        /// Current child value with its creator correlation and private route.
641        creation: RoutedCreation<BehaviorAddr<C>, C>,
642        /// Exact error returned by the child's initialization transition.
643        error: C::Error,
644    },
645    /// Host establishment rejected after initialization produced actions.
646    HostRejected {
647        /// Current child value with its creator correlation and private route.
648        creation: RoutedCreation<BehaviorAddr<C>, C>,
649        /// Complete initialization actions that were never interpreted.
650        initialization: Actions<BehaviorAddr<C>, C::Ph, C::Sends, C::Birth>,
651        /// Exact reason the host could not commit this child.
652        reason: CreationRejection,
653    },
654}
655
656impl<C, Occurrence> ChildCreationOutcome<C, Occurrence>
657where
658    C: Behavior,
659    BehaviorAddr<C>: EndpointAddress,
660{
661    /// Consume a committed child result into its exact concrete actor
662    /// capability.
663    ///
664    /// The enclosing `ChildCreationOutcome<C, Occurrence>` already proves which
665    /// concrete behavior was created. A protocol recipient is therefore
666    /// strengthened only to `EstablishedActor<C>`; callers cannot select a
667    /// different behavior sharing the same protocol.
668    ///
669    /// # Errors
670    ///
671    /// Returns the complete original result when creation did not commit.
672    pub fn into_actor(self) -> Result<EstablishedActor<C>, Self> {
673        match self {
674            Self::Established {
675                established: EstablishedCreation::Installed { recipient, .. },
676            } => Ok(EstablishedActor::from_recipient(recipient)),
677            other => Err(other),
678        }
679    }
680}
681
682/// One complete child-creation settlement returned to its creator.
683///
684/// This product moves the existing settlement without reclassifying it. In
685/// particular, initialization and host rejection retain the current child and
686/// exact initialization value. A runtime that cannot admit this value to the
687/// live creator must recover it from the returned event and keep it in host
688/// custody.
689#[must_use = "a child-creation settlement must be admitted or retained"]
690pub struct ChildCreationSettled<C, Occurrence>
691where
692    C: Behavior,
693    BehaviorAddr<C>: EndpointAddress,
694{
695    settlement: SettledItem<
696        RoutedCreation<BehaviorAddr<C>, C>,
697        ItemSettlement<
698            RoutedCreation<BehaviorAddr<C>, C>,
699            ChildCreationOutcome<C, Occurrence>,
700            CreationRejection,
701            Never,
702        >,
703    >,
704}
705
706impl<C, Occurrence> ChildCreationSettled<C, Occurrence>
707where
708    C: Behavior,
709    BehaviorAddr<C>: EndpointAddress,
710{
711    #[must_use]
712    pub const fn new(
713        settlement: SettledItem<
714            RoutedCreation<BehaviorAddr<C>, C>,
715            ItemSettlement<
716                RoutedCreation<BehaviorAddr<C>, C>,
717                ChildCreationOutcome<C, Occurrence>,
718                CreationRejection,
719                Never,
720            >,
721        >,
722    ) -> Self {
723        Self { settlement }
724    }
725
726    /// Recover the exact generic settlement without cloning any owned value.
727    #[must_use]
728    pub fn into_settlement(
729        self,
730    ) -> SettledItem<
731        RoutedCreation<BehaviorAddr<C>, C>,
732        ItemSettlement<
733            RoutedCreation<BehaviorAddr<C>, C>,
734            ChildCreationOutcome<C, Occurrence>,
735            CreationRejection,
736            Never,
737        >,
738    > {
739        self.settlement
740    }
741}
742
743impl<C, Occurrence> core::fmt::Debug for ChildCreationSettled<C, Occurrence>
744where
745    C: Behavior,
746    BehaviorAddr<C>: EndpointAddress,
747{
748    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
749        formatter
750            .debug_struct("ChildCreationSettled")
751            .finish_non_exhaustive()
752    }
753}
754
755/// Non-authoritative correlation to one creation result in the current action.
756///
757/// `P` and `Occurrence` select the exact creator-local entry statically. The
758/// value carries no recipient, actor identity, or child-hosting authority; the
759/// corresponding creation settlement remains its sole authoritative owner.
760///
761/// Equal ID representations at different occurrences cannot be
762/// substituted:
763///
764/// ```compile_fail,E0308
765/// struct Worker;
766/// impl behavior::Protocol for Worker {
767///     type Addr = behavior::MailAddr;
768///     type Msg = ();
769/// }
770/// struct Primary;
771/// struct Backup;
772/// let mut sequence = behavior::CreationSequence::new();
773/// let id = sequence.issue().expect("fixture creation ID");
774/// let backup = behavior::CreationCorrelation::<Worker, Backup>::new(id);
775/// let _: behavior::CreationCorrelation<Worker, Primary> = backup;
776/// ```
777#[doc(hidden)]
778pub struct CreationCorrelation<P, Occurrence>
779where
780    P: Protocol,
781{
782    id: CreationId,
783    occurrence: PhantomData<fn() -> (P, Occurrence)>,
784}
785
786impl<P, Occurrence> CreationCorrelation<P, Occurrence>
787where
788    P: Protocol,
789{
790    #[must_use]
791    pub const fn new(id: CreationId) -> Self {
792        Self {
793            id,
794            occurrence: PhantomData,
795        }
796    }
797
798    #[must_use]
799    pub const fn id(self) -> CreationId {
800        self.id
801    }
802}
803
804impl<P, Occurrence> Copy for CreationCorrelation<P, Occurrence> where P: Protocol {}
805
806impl<P, Occurrence> Clone for CreationCorrelation<P, Occurrence>
807where
808    P: Protocol,
809{
810    fn clone(&self) -> Self {
811        *self
812    }
813}
814
815impl<P, Occurrence> core::fmt::Debug for CreationCorrelation<P, Occurrence>
816where
817    P: Protocol,
818{
819    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
820        formatter
821            .debug_tuple("CreationCorrelation")
822            .field(&self.id)
823            .finish()
824    }
825}
826
827impl<P, Occurrence> PartialEq for CreationCorrelation<P, Occurrence>
828where
829    P: Protocol,
830{
831    fn eq(&self, other: &Self) -> bool {
832        self.id == other.id
833    }
834}
835
836impl<P, Occurrence> Eq for CreationCorrelation<P, Occurrence> where P: Protocol {}
837
838/// Same-action communication to one declared creator-local role.
839///
840/// The interpreter resolves this route only after all creations in the same
841/// [`crate::Actions`] have committed. A rejected or absent binding must produce
842/// a typed interpreter outcome; it can never be converted into a logical
843/// address by nonce arithmetic.
844pub struct ChildDelivery<P, Occurrence>
845where
846    P: Protocol,
847{
848    pub creation: CreationId,
849    pub message: P::Msg,
850    occurrence: PhantomData<fn() -> Occurrence>,
851}
852
853/// Private typed communication to one declared creator-local child role.
854///
855/// `ChildDelivery` addresses the child's public protocol. `ChildInput`
856/// instead selects one owner-defined member of the concrete child's event
857/// algebra through `Source`. This is the static boundary used for lifecycle
858/// coordination between an owner and a composed child: it retains the exact
859/// child behavior, occurrence, input, and ingress owner without exposing the
860/// input through the child's public protocol or performing a runtime lookup.
861///
862/// This is a derived Bombay communication form. Like `ChildDelivery`, its
863/// creator-local route is interpreted only after same-action creations have
864/// committed; constructing it performs no delivery.
865pub struct ChildInput<Child, Source, Input, Occurrence>
866where
867    Child: Behavior,
868{
869    /// Creator-local creation ID of the concrete child receiving the input.
870    pub creation: CreationId,
871    /// Complete private input transferred to the child.
872    pub input: Input,
873    marker: PhantomData<fn() -> (Child, Source, Occurrence)>,
874}
875
876/// Exact reason one public child delivery was not accepted.
877#[derive(Clone, Copy, Debug, Eq, PartialEq)]
878pub enum ChildDeliveryReason {
879    MissingBinding,
880    ClosedRecipient,
881}
882
883/// Exact reason one private child input was not accepted.
884#[derive(Clone, Copy, Debug, Eq, PartialEq)]
885pub enum ChildInputReason {
886    MissingBinding,
887    ClosedControlLane,
888}
889
890/// One report emitted through an established creator/child relationship.
891///
892/// The interpreter attaches `child` from its exact local binding; the
893/// emitting behavior supplies only `report`. `EventIngress` separately keeps
894/// the concrete child behavior and occurrence in the parent's event type, so
895/// equal nonce representations cannot confuse different child roles.
896#[derive(Debug, Clone, Copy, PartialEq, Eq)]
897pub struct ChildReport<R> {
898    /// Creator-local ID of the child that emitted the report.
899    pub child: CreationId,
900    /// Complete report value transferred by that child.
901    pub report: R,
902}
903
904impl<R> ChildReport<R> {
905    /// Attach an established creator-local creation ID to one report.
906    #[must_use]
907    pub const fn new(child: CreationId, report: R) -> Self {
908        Self { child, report }
909    }
910}
911
912impl<R> From<(CreationId, crate::ReportToParent<R>)> for ChildReport<R> {
913    fn from((child, request): (CreationId, crate::ReportToParent<R>)) -> Self {
914        Self::new(child, request.into_inner())
915    }
916}
917
918impl<Child, Source, Input, Occurrence> ChildInput<Child, Source, Input, Occurrence>
919where
920    Child: Behavior,
921    Child::Event: crate::ChildInputIngress<Source, Input>,
922{
923    /// Construct a private input for one exact creator-local child creation.
924    #[must_use]
925    pub const fn after(creation: CreationId, input: Input) -> Self {
926        Self {
927            creation,
928            input,
929            marker: PhantomData,
930        }
931    }
932}
933
934impl<Child, Source, Input, Occurrence> Clone for ChildInput<Child, Source, Input, Occurrence>
935where
936    Child: Behavior,
937    Input: Clone,
938{
939    fn clone(&self) -> Self {
940        Self {
941            creation: self.creation,
942            input: self.input.clone(),
943            marker: PhantomData,
944        }
945    }
946}
947
948impl<P, Occurrence> ChildDelivery<P, Occurrence>
949where
950    P: Protocol,
951{
952    #[must_use]
953    pub const fn after(creation: CreationId, message: P::Msg) -> Self {
954        Self {
955            creation,
956            message,
957            occurrence: PhantomData,
958        }
959    }
960}
961
962impl<P, Occurrence> Clone for ChildDelivery<P, Occurrence>
963where
964    P: Protocol,
965    P::Msg: Clone,
966{
967    fn clone(&self) -> Self {
968        Self {
969            creation: self.creation,
970            message: self.message.clone(),
971            occurrence: PhantomData,
972        }
973    }
974}
975
976impl<P, Occurrence> ActionItem for ChildDelivery<P, Occurrence>
977where
978    P: Protocol,
979    P::Msg: Send,
980{
981    type Accepted = ();
982    type Rejection = ChildDeliveryReason;
983    type Prerequisite = CreationCorrelation<P, Occurrence>;
984}
985
986impl<Child, Source, Input, Occurrence> ActionItem for ChildInput<Child, Source, Input, Occurrence>
987where
988    Child: Behavior,
989    Input: Send,
990{
991    type Accepted = ();
992    type Rejection = ChildInputReason;
993    type Prerequisite = CreationCorrelation<Child::Protocol, Occurrence>;
994}
995
996/// Runtime ownership port for establishing one concrete child behavior.
997///
998/// The result vocabulary belongs to the creation request, never the runtime.
999/// Accepting ownership consumes the child definition and returns its one
1000/// authoritative created-or-rejected result. Refusal before ownership transfer
1001/// returns the complete request. Child creation has no prerequisite, while
1002/// interpreter corruption uses the shared [`crate::InterpreterFault`] sum.
1003///
1004/// A runtime cannot substitute a private receipt or rejection type:
1005///
1006/// ```compile_fail,E0053
1007/// #[derive(Clone, Copy, Eq, PartialEq)]
1008/// struct RuntimeAddr;
1009/// impl behavior::Address for RuntimeAddr { type Nonce = u8; }
1010/// #[derive(Clone)]
1011/// struct Endpoint;
1012/// impl behavior::EndpointAddress for RuntimeAddr {
1013///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
1014/// }
1015/// struct Child;
1016/// impl behavior::Protocol for Child {
1017///     type Addr = RuntimeAddr;
1018///     type Msg = behavior::Never;
1019/// }
1020/// impl behavior::Behavior for Child {
1021///     type Protocol = Self;
1022///     type Event = behavior::User<RuntimeAddr, behavior::Never>;
1023///     type Sends = behavior::NoSends;
1024///     type Ph = behavior::Never;
1025///     type Error = behavior::Never;
1026///     type Birth = behavior::NoBirths;
1027///     fn transition(
1028///         &mut self,
1029///         _: behavior::ActiveTurn,
1030///         event: Self::Event,
1031///     ) -> behavior::BehaviorActed<Self> {
1032///         match event.message {}
1033///     }
1034/// }
1035/// struct Runtime;
1036///
1037/// impl behavior::EstablishChild<behavior::ChildHead, Child> for Runtime {
1038///     fn establish_child(
1039///         &mut self,
1040///         creation: behavior::RoutedCreation<behavior::BehaviorAddr<Child>, Child>,
1041///     ) -> impl core::future::Future<Output = behavior::ItemSettlement<
1042///         behavior::RoutedCreation<behavior::BehaviorAddr<Child>, Child>,
1043///         (),
1044///         &'static str,
1045///         behavior::Never,
1046///     >> + Send {
1047///         async move { behavior::ItemSettlement::Rejected { item: creation, reason: "no" } }
1048///     }
1049/// }
1050/// ```
1051pub trait EstablishChild<Occurrence, C>
1052where
1053    C: Behavior,
1054    BehaviorAddr<C>: EndpointAddress,
1055{
1056    /// Establish exactly the supplied child or return its complete settlement.
1057    fn establish_child(
1058        &mut self,
1059        creation: RoutedCreation<BehaviorAddr<C>, C>,
1060    ) -> impl Future<
1061        Output = ItemSettlement<
1062            RoutedCreation<BehaviorAddr<C>, C>,
1063            ChildCreationOutcome<C, Occurrence>,
1064            CreationRejection,
1065            Never,
1066        >,
1067    > + Send;
1068}
1069
1070/// Authoritative result shape for one closed child choice.
1071///
1072/// This type-level product depends only on the declared child protocols and
1073/// their occurrences. It contains no runtime-selected type.
1074#[doc(hidden)]
1075pub trait ChildCreationProduct<A: Address, Occurrence>: Sized {
1076    type Result;
1077}
1078
1079/// Exhaustive static dispatch of one creation-only child sum.
1080///
1081/// This is an interpreter-facing derived construction, not another actor-model
1082/// operation. Implementations must preserve the ID, route, and creation kind and
1083/// call exactly one concrete [`EstablishChild`] implementation. [`ChildChoice`]
1084/// provides the closed recursive heterogeneous sum. Dispatch futures are
1085/// sendable; heterogeneous sums therefore require sendable alternatives,
1086/// runtime routes, and child hosts.
1087pub trait DispatchBirth<A: Address, Host>: ChildCreationProduct<A, ChildHead> + Sized {
1088    /// Select exactly one concrete child host while preserving creation data
1089    /// in every non-accepted settlement.
1090    fn dispatch_birth(
1091        self,
1092        id: CreationId,
1093        route: A::Nonce,
1094        kind: CreationKind,
1095        host: &mut Host,
1096    ) -> impl Future<
1097        Output = ItemSettlement<
1098            RoutedCreation<A, Self>,
1099            <Self as ChildCreationProduct<A, ChildHead>>::Result,
1100            CreationRejection,
1101            Never,
1102        >,
1103    > + Send;
1104}
1105
1106trait CreateSelectedChild<A: Address, Occurrence, Host>:
1107    ChildCreationProduct<A, Occurrence> + Sized
1108{
1109    fn dispatch_birth_at(
1110        self,
1111        id: CreationId,
1112        route: A::Nonce,
1113        kind: CreationKind,
1114        host: &mut Host,
1115    ) -> impl Future<
1116        Output = ItemSettlement<
1117            RoutedCreation<A, Self>,
1118            <Self as ChildCreationProduct<A, Occurrence>>::Result,
1119            CreationRejection,
1120            Never,
1121        >,
1122    > + Send;
1123}
1124
1125impl<A, Child, Host> DispatchBirth<A, Host> for Child
1126where
1127    A: Address,
1128    Child: CreateSelectedChild<A, ChildHead, Host>,
1129{
1130    fn dispatch_birth(
1131        self,
1132        id: CreationId,
1133        route: A::Nonce,
1134        kind: CreationKind,
1135        host: &mut Host,
1136    ) -> impl Future<
1137        Output = ItemSettlement<
1138            RoutedCreation<A, Self>,
1139            <Self as ChildCreationProduct<A, ChildHead>>::Result,
1140            CreationRejection,
1141            Never,
1142        >,
1143    > + Send {
1144        self.dispatch_birth_at(id, route, kind, host)
1145    }
1146}
1147
1148/// One alternative in a closed, recursively composed child-creation sum.
1149///
1150/// `Head` is one concrete child behavior and `Tail` is the remaining closed
1151/// sum. This is a creation choice only: it is not a behavior, message
1152/// envelope, registry, or runtime dispatch mechanism.
1153///
1154/// Every alternative requires a concrete child host; incomplete interpreter
1155/// support is rejected statically:
1156///
1157/// ```compile_fail
1158/// #[derive(Clone, Copy, Eq, PartialEq)]
1159/// struct RuntimeAddr;
1160/// impl behavior::Address for RuntimeAddr { type Nonce = u8; }
1161/// #[derive(Clone)]
1162/// struct Endpoint;
1163/// impl behavior::EndpointAddress for RuntimeAddr {
1164///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
1165/// }
1166/// struct CacheWorker;
1167/// struct QueueWorker;
1168///
1169/// macro_rules! inert {
1170///     ($child:ty) => {
1171///         impl behavior::Protocol for $child {
1172///             type Addr = RuntimeAddr;
1173///             type Msg = behavior::Never;
1174///         }
1175///         impl behavior::Behavior for $child {
1176///             type Protocol = Self;
1177///             type Event = behavior::User<RuntimeAddr, behavior::Never>;
1178///             type Sends = behavior::NoSends;
1179///             type Ph = behavior::Never;
1180///             type Error = behavior::Never;
1181///             type Birth = behavior::NoBirths;
1182///
1183///             fn transition(
1184///                 &mut self,
1185///                 _: behavior::ActiveTurn,
1186///                 event: Self::Event,
1187///             ) -> behavior::BehaviorActed<Self> {
1188///                 match event.message {}
1189///             }
1190///         }
1191///     };
1192/// }
1193/// inert!(CacheWorker);
1194/// inert!(QueueWorker);
1195///
1196/// struct Incomplete;
1197/// impl behavior::EstablishChild<behavior::ChildHead, CacheWorker> for Incomplete {
1198///     async fn establish_child(
1199///         &mut self,
1200///         creation: behavior::RoutedCreation<RuntimeAddr, CacheWorker>,
1201///     ) -> behavior::ItemSettlement<
1202///         behavior::RoutedCreation<RuntimeAddr, CacheWorker>,
1203///         behavior::ChildCreationOutcome<CacheWorker, behavior::ChildHead>,
1204///         behavior::CreationRejection,
1205///         behavior::Never,
1206///     > {
1207///         behavior::ItemSettlement::Rejected {
1208///             item: creation,
1209///             reason: behavior::CreationRejection::EnvironmentFailed,
1210///         }
1211///     }
1212/// }
1213///
1214/// type WorkerChoices = behavior::ChildChoice<
1215///     CacheWorker,
1216///     behavior::ChildChoice<QueueWorker, behavior::Never>,
1217/// >;
1218/// fn require_complete<T: behavior::DispatchBirth<RuntimeAddr, Incomplete>>() {}
1219/// require_complete::<WorkerChoices>();
1220/// ```
1221#[derive(Debug, Clone, PartialEq, Eq)]
1222pub enum ChildChoice<Head, Tail> {
1223    /// Select the concrete child at this position.
1224    Head(Head),
1225    /// Select one concrete child from the remaining alternatives.
1226    Tail(Tail),
1227}
1228
1229/// Position selecting the head of a closed [`ChildChoice`] sum.
1230#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1231pub struct ChildHead;
1232
1233/// Position selecting inside the tail of a closed [`ChildChoice`] sum.
1234#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1235pub struct ChildTail<Position>(PhantomData<fn() -> Position>);
1236
1237/// Static proof that `Child` occupies `Position` in a closed child sum.
1238///
1239/// This trait provides structural evidence only. It does not construct a
1240/// choice, perform creation, or select a child through runtime inspection.
1241/// A role cannot claim a position occupied by a different child:
1242///
1243/// ```compile_fail
1244/// use behavior::{
1245///     Actions, Behavior, BehaviorActed, Births, ChildChoice, ChildHead,
1246///     ChildRole, MailAddr, Never, NoBirths, User,
1247/// };
1248/// struct CacheWorker;
1249/// struct QueueWorker;
1250/// struct Parent;
1251/// macro_rules! inert {
1252///     ($actor:ty) => {
1253///         impl behavior::Protocol for $actor {
1254///             type Addr = MailAddr;
1255///             type Msg = Never;
1256///         }
1257///         impl Behavior for $actor {
1258///             type Protocol = Self;
1259///             type Event = User<MailAddr, Never>;
1260///             type Sends = Vec<Never>;
1261///             type Ph = Never;
1262///             type Error = Never;
1263///             type Birth = NoBirths;
1264///             fn transition(&mut self, _: behavior::ActiveTurn, event: Self::Event) -> BehaviorActed<Self> {
1265///                 match event.message {}
1266///             }
1267///         }
1268///     };
1269/// }
1270/// inert!(CacheWorker);
1271/// inert!(QueueWorker);
1272/// impl behavior::Protocol for Parent {
1273///     type Addr = MailAddr;
1274///     type Msg = Never;
1275/// }
1276/// impl Behavior for Parent {
1277///     type Protocol = Self;
1278///     type Event = User<MailAddr, Never>;
1279///     type Sends = Vec<Never>;
1280///     type Ph = Never;
1281///     type Error = Never;
1282///     type Birth = Births<ChildChoice<QueueWorker, ChildChoice<CacheWorker, Never>>>;
1283///     fn transition(&mut self, _: behavior::ActiveTurn, event: Self::Event) -> BehaviorActed<Self> {
1284///         match event.message {}
1285///     }
1286/// }
1287/// struct ForgedCacheRole;
1288/// impl ChildRole<Parent> for ForgedCacheRole {
1289///     type Child = CacheWorker;
1290///     type Position = ChildHead;
1291/// }
1292/// ```
1293pub trait ChildPosition<Children, Child: Behavior>: sealed::ChildPosition {}
1294
1295impl sealed::ChildPosition for ChildHead {}
1296
1297impl<Child: Behavior> ChildPosition<Child, Child> for ChildHead {}
1298
1299impl<Head: Behavior, Tail> ChildPosition<ChildChoice<Head, Tail>, Head> for ChildHead {}
1300
1301impl<Position> sealed::ChildPosition for ChildTail<Position> {}
1302
1303impl<Head, Tail, Position, Child> ChildPosition<ChildChoice<Head, Tail>, Child>
1304    for ChildTail<Position>
1305where
1306    Child: Behavior,
1307    Position: ChildPosition<Tail, Child>,
1308{
1309}
1310
1311/// Append one closed direct-child algebra after another.
1312///
1313/// `Self` remains the structural prefix, so every child occurrence already
1314/// valid in that prefix retains both its child type and its position. `Tail`
1315/// begins only after the prefix's final position. The two injection functions
1316/// change only the closed sum containing a child; [`append_creations`](Self::append_creations)
1317/// additionally preserves every creation's ID, kind, and batch order while
1318/// placing all prefix creations before all appended creations.
1319///
1320/// This is a static composition of Bombay's existing staged-creation
1321/// capability, not another actor effect and not an allocation operation. The
1322/// interpreter remains solely responsible for establishing and binding the child.
1323///
1324/// A generic topology owner can therefore retain an inner behavior's exact
1325/// creation effects and append children whose concrete types were inferred
1326/// from value construction:
1327///
1328/// ```
1329/// use behavior::{BirthNodeAppend, Never};
1330/// use core::marker::PhantomData;
1331///
1332/// type Combined = <Never as BirthNodeAppend<Never>>::Output;
1333/// let _: PhantomData<Combined> = PhantomData;
1334/// ```
1335pub trait BirthNodeAppend<Tail>: sealed::BirthNode + Sized
1336where
1337    Tail: sealed::BirthNode,
1338{
1339    /// Closed child algebra containing the complete prefix followed by the
1340    /// complete appended tail.
1341    type Output: sealed::BirthNode;
1342
1343    /// Inject one child from the existing prefix without changing its
1344    /// structural occurrence.
1345    fn append_prefix(self) -> Self::Output;
1346
1347    /// Inject one child from the appended tail after every prefix occurrence.
1348    fn append_tail(tail: Tail) -> Self::Output;
1349
1350    /// Preserve and concatenate two ordered creation batches.
1351    #[must_use]
1352    fn append_creations<A: Address>(
1353        prefix: Creations<CreateChild<A, Self>>,
1354        tail: Creations<CreateChild<A, Tail>>,
1355    ) -> Creations<CreateChild<A, Self::Output>> {
1356        let mut combined = Vec::with_capacity(prefix.len() + tail.len());
1357        combined.extend(prefix.into_iter().map(|creation| {
1358            let (id, child, kind) = creation.into_parts();
1359            CreateChild::from_parts(id, Self::append_prefix(child), kind)
1360        }));
1361        combined.extend(tail.into_iter().map(|creation| {
1362            let (id, child, kind) = creation.into_parts();
1363            CreateChild::from_parts(id, Self::append_tail(child), kind)
1364        }));
1365        Creations::from_items(combined)
1366    }
1367}
1368
1369impl<Tail> BirthNodeAppend<Tail> for Never
1370where
1371    Tail: sealed::BirthNode,
1372{
1373    type Output = Tail;
1374
1375    fn append_prefix(self) -> Self::Output {
1376        match self {}
1377    }
1378
1379    fn append_tail(tail: Tail) -> Self::Output {
1380        tail
1381    }
1382}
1383
1384impl<Node> BirthNodeAppend<Never> for Node
1385where
1386    Node: sealed::NonEmptyBirthNode,
1387{
1388    type Output = Node;
1389
1390    fn append_prefix(self) -> Self::Output {
1391        self
1392    }
1393
1394    fn append_tail(tail: Never) -> Self::Output {
1395        match tail {}
1396    }
1397}
1398
1399impl<Child, Tail> BirthNodeAppend<Tail> for Child
1400where
1401    Child: Behavior,
1402    Tail: sealed::NonEmptyBirthNode,
1403{
1404    type Output = ChildChoice<Child, Tail>;
1405
1406    fn append_prefix(self) -> Self::Output {
1407        ChildChoice::Head(self)
1408    }
1409
1410    fn append_tail(tail: Tail) -> Self::Output {
1411        ChildChoice::Tail(tail)
1412    }
1413}
1414
1415impl<Head, Rest, Tail> BirthNodeAppend<Tail> for ChildChoice<Head, Rest>
1416where
1417    Head: Behavior,
1418    Rest: sealed::BirthNode + BirthNodeAppend<Tail>,
1419    Tail: sealed::NonEmptyBirthNode,
1420    Rest::Output: sealed::BirthNode,
1421{
1422    type Output = ChildChoice<Head, Rest::Output>;
1423
1424    fn append_prefix(self) -> Self::Output {
1425        match self {
1426            ChildChoice::Head(head) => ChildChoice::Head(head),
1427            ChildChoice::Tail(rest) => ChildChoice::Tail(rest.append_prefix()),
1428        }
1429    }
1430
1431    fn append_tail(tail: Tail) -> Self::Output {
1432        ChildChoice::Tail(Rest::append_tail(tail))
1433    }
1434}
1435
1436impl<Parent: Behavior> ChildOccurrence<Parent> for ChildHead {
1437    type Resolution = StructuralChildOccurrence<Self>;
1438}
1439
1440impl<Parent: Behavior, Position> ChildOccurrence<Parent> for ChildTail<Position> {
1441    type Resolution = StructuralChildOccurrence<Self>;
1442}
1443
1444/// Sealed proof that an occurrence may select one resolver descriptor.
1445///
1446/// Nominal occurrences can select [`DeclaredChildOccurrence`] only when their
1447/// existing [`ChildRole`] implementation supplies the child and position. Raw
1448/// structural descriptors are available only to the identical
1449/// [`ChildHead`] or [`ChildTail`] occurrence.
1450#[doc(hidden)]
1451pub trait ChildOccurrenceResolution<Parent: Behavior, Occurrence>:
1452    sealed::ChildOccurrenceDescriptor + sealed::OccurrenceResolution<Parent, Occurrence>
1453{
1454}
1455
1456impl<Parent, Occurrence> ChildOccurrenceResolution<Parent, Occurrence> for DeclaredChildOccurrence
1457where
1458    Parent: Behavior,
1459    Occurrence: ChildRole<Parent>,
1460{
1461}
1462
1463impl<Parent: Behavior> ChildOccurrenceResolution<Parent, ChildHead>
1464    for StructuralChildOccurrence<ChildHead>
1465{
1466}
1467
1468impl<Parent: Behavior, Position> ChildOccurrenceResolution<Parent, ChildTail<Position>>
1469    for StructuralChildOccurrence<ChildTail<Position>>
1470{
1471}
1472
1473/// Sealed implementation detail for resolving occurrence descriptors.
1474#[doc(hidden)]
1475pub trait ResolveChildOccurrenceDescriptor<Emitter: Behavior, Occurrence>:
1476    sealed::ChildOccurrenceDescriptor + sealed::ResolveDescriptor<Emitter, Occurrence>
1477{
1478    type Child: Behavior;
1479    type Position: ChildPosition<<Emitter::Birth as BirthMode>::Child, Self::Child>;
1480}
1481
1482impl<Emitter, Occurrence, Position> ResolveChildOccurrenceDescriptor<Emitter, Occurrence>
1483    for StructuralChildOccurrence<Position>
1484where
1485    Emitter: Behavior,
1486    <Emitter::Birth as BirthMode>::Child: BirthNodeAt<Position>,
1487    Position: ChildPosition<
1488            <Emitter::Birth as BirthMode>::Child,
1489            <<Emitter::Birth as BirthMode>::Child as BirthNodeAt<Position>>::Child,
1490        >,
1491{
1492    type Child = <<Emitter::Birth as BirthMode>::Child as BirthNodeAt<Position>>::Child;
1493    type Position = Position;
1494}
1495
1496impl<Emitter, Occurrence> ResolveChildOccurrenceDescriptor<Emitter, Occurrence>
1497    for DeclaredChildOccurrence
1498where
1499    Emitter:
1500        Behavior<Protocol = <<Emitter as BehaviorBase>::Base as Behavior>::Protocol> + BehaviorBase,
1501    Emitter::Base: Behavior,
1502    Occurrence: ChildRole<Emitter::Base>,
1503    <Emitter::Birth as BirthMode>::Child:
1504        BirthNodeAt<Occurrence::Position, Child = Occurrence::Child>,
1505    Occurrence::Position: ChildPosition<<Emitter::Birth as BirthMode>::Child, Occurrence::Child>,
1506{
1507    type Child = Occurrence::Child;
1508    type Position = Occurrence::Position;
1509}
1510
1511/// Sealed inverse projection from one structural position to its child.
1512#[doc(hidden)]
1513pub trait BirthNodeAt<Position>: sealed::BirthNode {
1514    type Child: Behavior;
1515}
1516
1517impl<Child: Behavior> BirthNodeAt<ChildHead> for Child {
1518    type Child = Child;
1519}
1520
1521impl<Head: Behavior, Tail> BirthNodeAt<ChildHead> for ChildChoice<Head, Tail>
1522where
1523    Tail: sealed::BirthNode,
1524{
1525    type Child = Head;
1526}
1527
1528impl<Head, Tail, Position> BirthNodeAt<ChildTail<Position>> for ChildChoice<Head, Tail>
1529where
1530    Head: Behavior,
1531    Tail: BirthNodeAt<Position>,
1532{
1533    type Child = <Tail as BirthNodeAt<Position>>::Child;
1534}
1535
1536/// Downstream shape of one direct-child occurrence product.
1537///
1538/// Behavior owns the closed node algebra: a concrete [`Behavior`] leaf,
1539/// [`ChildChoice`], or [`Never`]. A runtime owns the representation associated
1540/// with each leaf. `Empty` supplies its terminal representation and `Member`
1541/// receives one concrete child, its structural occurrence, and the remaining
1542/// child product.
1543///
1544/// This is a type-level derived construction. It creates no value, allocates
1545/// no actor, interprets no effect, and introduces no protocol identity or
1546/// runtime key. A shape that builds a heterogeneous product should retain
1547/// `Tail`; the product includes every declared child exactly once.
1548///
1549/// ```
1550/// use core::marker::PhantomData;
1551/// use behavior::{Behavior, ChildOccurrenceShape, ChildOccurrences};
1552///
1553/// struct NoChildBindings;
1554/// struct ChildBinding<Position, Child, Tail>(PhantomData<fn() -> (Position, Child, Tail)>);
1555/// struct RuntimeStorage;
1556///
1557/// impl ChildOccurrenceShape for RuntimeStorage {
1558///     type Empty = NoChildBindings;
1559///     type Member<Occurrence, Child: Behavior, Tail> =
1560///         ChildBinding<Occurrence, Child, Tail>;
1561/// }
1562///
1563/// type ChildBindings<Node> = ChildOccurrences<Node, RuntimeStorage>;
1564/// ```
1565pub trait ChildOccurrenceShape {
1566    /// Representation of the empty [`Never`] node.
1567    type Empty;
1568
1569    /// Representation of one concrete child followed by the remaining product.
1570    type Member<Occurrence, Child: Behavior, Tail>;
1571}
1572
1573/// Sealed occurrence product of a closed direct-child birth node.
1574///
1575/// The product starts at [`ChildHead`] and advances through
1576/// [`ChildTail<Position>`] in exactly the same way as [`DispatchBirth`] and
1577/// [`ChildPosition`]. A downstream runtime selects only the result shape
1578/// through [`ChildOccurrenceShape`]; it cannot reclassify a foreign type as a
1579/// birth node or replace the recursion.
1580///
1581/// This product is intentionally direct rather than transitive. Each installed
1582/// actor owns the bindings for its own `Behavior::Birth`; when a concrete child
1583/// is installed, the same product law applies to that child's birth algebra.
1584///
1585/// Foreign types cannot extend the closed node algebra:
1586///
1587/// ```compile_fail
1588/// use behavior::{ChildOccurrenceProduct, ChildOccurrenceShape};
1589///
1590/// struct RuntimeShape;
1591/// impl ChildOccurrenceShape for RuntimeShape {
1592///     type Empty = ();
1593///     type Member<Occurrence, Child: behavior::Behavior, Tail> = ();
1594/// }
1595///
1596/// struct ForeignNode;
1597/// impl ChildOccurrenceProduct<RuntimeShape> for ForeignNode {
1598///     type Product = ();
1599/// }
1600/// ```
1601pub trait ChildOccurrenceProduct<Shape>: sealed::BirthNode
1602where
1603    Shape: ChildOccurrenceShape,
1604{
1605    /// Complete shape-owned representation of this closed birth node.
1606    type Product;
1607}
1608
1609/// Occurrence-carrying recursion for [`ChildOccurrenceProduct`]. Consumers
1610/// should name [`ChildOccurrenceProduct`] or [`ChildOccurrences`] instead.
1611#[doc(hidden)]
1612pub trait ChildOccurrenceProductAt<Occurrence, Shape>: sealed::BirthNode
1613where
1614    Shape: ChildOccurrenceShape,
1615{
1616    type Product;
1617}
1618
1619impl<Node, Shape> ChildOccurrenceProduct<Shape> for Node
1620where
1621    Node: ChildOccurrenceProductAt<ChildHead, Shape>,
1622    Shape: ChildOccurrenceShape,
1623{
1624    type Product = <Node as ChildOccurrenceProductAt<ChildHead, Shape>>::Product;
1625}
1626
1627impl<Occurrence, Shape, Child> ChildOccurrenceProductAt<Occurrence, Shape> for Child
1628where
1629    Shape: ChildOccurrenceShape,
1630    Child: Behavior,
1631{
1632    type Product = Shape::Member<Occurrence, Child, Shape::Empty>;
1633}
1634
1635impl<Occurrence, Shape, Head, Tail> ChildOccurrenceProductAt<Occurrence, Shape>
1636    for ChildChoice<Head, Tail>
1637where
1638    Shape: ChildOccurrenceShape,
1639    Head: Behavior,
1640    Tail: ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>,
1641{
1642    type Product = Shape::Member<
1643        Occurrence,
1644        Head,
1645        <Tail as ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>>::Product,
1646    >;
1647}
1648
1649impl<Occurrence, Shape> ChildOccurrenceProductAt<Occurrence, Shape> for Never
1650where
1651    Shape: ChildOccurrenceShape,
1652{
1653    type Product = Shape::Empty;
1654}
1655
1656/// Occurrence-preserving representation selected by one downstream shape.
1657pub type ChildOccurrences<Node, Shape> = <Node as ChildOccurrenceProduct<Shape>>::Product;
1658
1659mod sealed {
1660    use super::{
1661        Behavior, BehaviorBase, BirthMode, BirthNodeAt, ChildChoice, ChildHead, ChildOccurrence,
1662        ChildRole, ChildTail, DeclaredChildOccurrence, Never, ResolveChildOccurrenceDescriptor,
1663        StructuralChildOccurrence,
1664    };
1665
1666    pub trait BirthNode {}
1667
1668    pub trait NonEmptyBirthNode: BirthNode {}
1669
1670    impl<Child: Behavior> BirthNode for Child {}
1671    impl<Child: Behavior> NonEmptyBirthNode for Child {}
1672
1673    impl<Head, Tail> BirthNode for ChildChoice<Head, Tail>
1674    where
1675        Head: Behavior,
1676        Tail: BirthNode,
1677    {
1678    }
1679
1680    impl<Head, Tail> NonEmptyBirthNode for ChildChoice<Head, Tail>
1681    where
1682        Head: Behavior,
1683        Tail: BirthNode,
1684    {
1685    }
1686
1687    impl BirthNode for Never {}
1688
1689    pub trait ChildPosition {}
1690    pub trait ChildProduct {}
1691
1692    pub trait ChildOccurrenceDescriptor {}
1693
1694    impl ChildOccurrenceDescriptor for DeclaredChildOccurrence {}
1695
1696    impl<Position> ChildOccurrenceDescriptor for StructuralChildOccurrence<Position> {}
1697
1698    pub trait OccurrenceResolution<Parent: Behavior, Occurrence> {}
1699
1700    impl<Parent, Occurrence> OccurrenceResolution<Parent, Occurrence> for DeclaredChildOccurrence
1701    where
1702        Parent: Behavior,
1703        Occurrence: ChildRole<Parent>,
1704    {
1705    }
1706
1707    impl<Parent: Behavior> OccurrenceResolution<Parent, ChildHead>
1708        for StructuralChildOccurrence<ChildHead>
1709    {
1710    }
1711
1712    impl<Parent: Behavior, Position> OccurrenceResolution<Parent, ChildTail<Position>>
1713        for StructuralChildOccurrence<ChildTail<Position>>
1714    {
1715    }
1716
1717    pub trait ResolveDescriptor<Emitter: Behavior, Occurrence> {}
1718
1719    impl<Emitter, Occurrence, Position> ResolveDescriptor<Emitter, Occurrence>
1720        for StructuralChildOccurrence<Position>
1721    where
1722        Emitter: Behavior,
1723        <Emitter::Birth as BirthMode>::Child: BirthNodeAt<Position>,
1724    {
1725    }
1726
1727    impl<Emitter, Occurrence> ResolveDescriptor<Emitter, Occurrence> for DeclaredChildOccurrence
1728    where
1729        Emitter: Behavior<Protocol = <<Emitter as BehaviorBase>::Base as Behavior>::Protocol>
1730            + BehaviorBase,
1731        Emitter::Base: Behavior,
1732        Occurrence: ChildRole<Emitter::Base>,
1733        <Emitter::Birth as BirthMode>::Child:
1734            BirthNodeAt<Occurrence::Position, Child = Occurrence::Child>,
1735        Occurrence::Position:
1736            super::ChildPosition<<Emitter::Birth as BirthMode>::Child, Occurrence::Child>,
1737    {
1738    }
1739
1740    pub trait ResolveChildOccurrence<Occurrence> {}
1741
1742    impl<Emitter, Occurrence> ResolveChildOccurrence<Occurrence> for Emitter
1743    where
1744        Emitter: Behavior + BehaviorBase,
1745        Emitter::Base: Behavior,
1746        Occurrence: ChildOccurrence<Emitter::Base>,
1747        Occurrence::Resolution: ResolveChildOccurrenceDescriptor<Emitter, Occurrence>,
1748    {
1749    }
1750}
1751
1752/// The empty heterogeneous creation product.
1753#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1754pub struct NoChildren;
1755
1756impl sealed::ChildProduct for NoChildren {}
1757
1758/// One creation appended to an ordered heterogeneous child product.
1759pub struct ChildCons<A: Address, C, Earlier> {
1760    creation: CreateChild<A, C>,
1761    earlier: Earlier,
1762}
1763
1764impl<A: Address, C, Earlier> sealed::ChildProduct for ChildCons<A, C, Earlier> {}
1765
1766/// A pure, ordered heterogeneous product of staged direct-child creations.
1767///
1768/// This value owns no mailbox, address, runtime actor, or lifecycle. Every
1769/// product position is a distinct static child occurrence, so equal numeric IDs
1770/// in different positions remain distinct correlations.
1771pub struct Children<A: Address, Product = NoChildren> {
1772    product: Product,
1773    address: PhantomData<fn() -> A>,
1774}
1775
1776/// Closed recursive conversion implemented only by Bombay child products.
1777pub trait ChildProduct<A: Address>: sealed::ChildProduct + Sized {
1778    /// Closed sum containing exactly the concrete child behavior types.
1779    type Choice: BirthNodeAppend<Never>;
1780
1781    #[doc(hidden)]
1782    fn stage(self) -> Vec<CreateChild<A, Self::Choice>>;
1783}
1784
1785impl<A: Address> ChildProduct<A> for NoChildren {
1786    type Choice = Never;
1787
1788    fn stage(self) -> Vec<CreateChild<A, Self::Choice>> {
1789        Vec::new()
1790    }
1791}
1792
1793impl<A, C, Earlier> ChildProduct<A> for ChildCons<A, C, Earlier>
1794where
1795    A: Address,
1796    C: Behavior,
1797    C::Protocol: Protocol<Addr = A>,
1798    Earlier: ChildProduct<A>,
1799{
1800    type Choice = ChildChoice<C, Earlier::Choice>;
1801
1802    fn stage(self) -> Vec<CreateChild<A, Self::Choice>> {
1803        let earlier = self.earlier.stage();
1804        let mut creates = earlier
1805            .into_iter()
1806            .map(|creation| {
1807                let (id, child, kind) = creation.into_parts();
1808                CreateChild::from_parts(id, ChildChoice::Tail(child), kind)
1809            })
1810            .collect::<Vec<_>>();
1811        let (id, child, kind) = self.creation.into_parts();
1812        creates.push(CreateChild::from_parts(id, ChildChoice::Head(child), kind));
1813        creates
1814    }
1815}
1816
1817impl<A: Address> Children<A, NoChildren> {
1818    /// Start an empty heterogeneous creation product.
1819    #[must_use]
1820    pub const fn new() -> Self {
1821        Self {
1822            product: NoChildren,
1823            address: PhantomData,
1824        }
1825    }
1826}
1827
1828impl<A: Address> Default for Children<A, NoChildren> {
1829    fn default() -> Self {
1830        Self::new()
1831    }
1832}
1833
1834impl<A: Address, Product> Children<A, Product> {
1835    /// Append one complete staged creation, preserving its provenance.
1836    #[must_use]
1837    pub fn create<C>(self, creation: CreateChild<A, C>) -> Children<A, ChildCons<A, C, Product>>
1838    where
1839        C: Behavior,
1840        C::Protocol: Protocol<Addr = A>,
1841    {
1842        Children {
1843            product: ChildCons {
1844                creation,
1845                earlier: self.product,
1846            },
1847            address: PhantomData,
1848        }
1849    }
1850
1851    /// Append one ordinary fresh-birth request.
1852    #[must_use]
1853    pub fn child<C>(self, id: CreationId, child: C) -> Children<A, ChildCons<A, C, Product>>
1854    where
1855        C: Behavior,
1856        C::Protocol: Protocol<Addr = A>,
1857    {
1858        self.create(CreateChild::birth(id, child))
1859    }
1860}
1861
1862impl<A, Product> Children<A, Product>
1863where
1864    A: Address,
1865    Product: ChildProduct<A>,
1866{
1867    /// Produce one ordered creation batch.
1868    #[must_use]
1869    pub fn into_creates(self) -> Creations<CreateChild<A, Product::Choice>> {
1870        Creations::from_items(self.product.stage())
1871    }
1872}
1873
1874impl<A, Occurrence, Head, Tail> ChildCreationProduct<A, Occurrence> for ChildChoice<Head, Tail>
1875where
1876    A: EndpointAddress,
1877    Head: Behavior,
1878    Head::Protocol: Protocol<Addr = A>,
1879    Tail: ChildCreationProduct<A, ChildTail<Occurrence>>,
1880{
1881    type Result = ChildChoice<
1882        ChildCreationOutcome<Head, Occurrence>,
1883        <Tail as ChildCreationProduct<A, ChildTail<Occurrence>>>::Result,
1884    >;
1885}
1886
1887impl<A, Occurrence, Head, Tail, Host> CreateSelectedChild<A, Occurrence, Host>
1888    for ChildChoice<Head, Tail>
1889where
1890    A: EndpointAddress,
1891    A::Nonce: Send,
1892    Head: Behavior + Send,
1893    Head::Protocol: Protocol<Addr = A>,
1894    Tail: CreateSelectedChild<A, ChildTail<Occurrence>, Host> + Send,
1895    Host: EstablishChild<Occurrence, Head> + Send,
1896{
1897    async fn dispatch_birth_at(
1898        self,
1899        id: CreationId,
1900        route: A::Nonce,
1901        kind: CreationKind,
1902        host: &mut Host,
1903    ) -> ItemSettlement<
1904        RoutedCreation<A, Self>,
1905        <Self as ChildCreationProduct<A, Occurrence>>::Result,
1906        CreationRejection,
1907        Never,
1908    > {
1909        match self {
1910            Self::Head(child) => {
1911                let creation = RoutedCreation::new(CreateChild::from_parts(id, child, kind), route);
1912                match host.establish_child(creation).await {
1913                    ItemSettlement::Accepted(receipt) => {
1914                        ItemSettlement::Accepted(ChildChoice::Head(receipt))
1915                    }
1916                    ItemSettlement::Rejected { item, reason } => {
1917                        let (creation, route) = item.into_parts();
1918                        let (id, child, kind) = creation.into_parts();
1919                        ItemSettlement::Rejected {
1920                            item: RoutedCreation::new(
1921                                CreateChild::from_parts(id, Self::Head(child), kind),
1922                                route,
1923                            ),
1924                            reason,
1925                        }
1926                    }
1927                    ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
1928                    ItemSettlement::Corrupt { item, fault } => {
1929                        let (creation, route) = item.into_parts();
1930                        let (id, child, kind) = creation.into_parts();
1931                        ItemSettlement::Corrupt {
1932                            item: RoutedCreation::new(
1933                                CreateChild::from_parts(id, Self::Head(child), kind),
1934                                route,
1935                            ),
1936                            fault,
1937                        }
1938                    }
1939                }
1940            }
1941            Self::Tail(tail) => match tail.dispatch_birth_at(id, route, kind, host).await {
1942                ItemSettlement::Accepted(receipt) => {
1943                    ItemSettlement::Accepted(ChildChoice::Tail(receipt))
1944                }
1945                ItemSettlement::Rejected { item, reason } => {
1946                    let (creation, route) = item.into_parts();
1947                    let (id, child, kind) = creation.into_parts();
1948                    ItemSettlement::Rejected {
1949                        item: RoutedCreation::new(
1950                            CreateChild::from_parts(id, Self::Tail(child), kind),
1951                            route,
1952                        ),
1953                        reason,
1954                    }
1955                }
1956                ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
1957                ItemSettlement::Corrupt { item, fault } => {
1958                    let (creation, route) = item.into_parts();
1959                    let (id, child, kind) = creation.into_parts();
1960                    ItemSettlement::Corrupt {
1961                        item: RoutedCreation::new(
1962                            CreateChild::from_parts(id, Self::Tail(child), kind),
1963                            route,
1964                        ),
1965                        fault,
1966                    }
1967                }
1968            },
1969        }
1970    }
1971}
1972
1973impl<A, Occurrence> ChildCreationProduct<A, Occurrence> for Never
1974where
1975    A: Address,
1976{
1977    type Result = Never;
1978}
1979
1980impl<A, Occurrence, Host> CreateSelectedChild<A, Occurrence, Host> for Never
1981where
1982    A: Address,
1983{
1984    fn dispatch_birth_at(
1985        self,
1986        _id: CreationId,
1987        _route: A::Nonce,
1988        _kind: CreationKind,
1989        _host: &mut Host,
1990    ) -> impl Future<
1991        Output = ItemSettlement<
1992            RoutedCreation<A, Self>,
1993            <Self as ChildCreationProduct<A, Occurrence>>::Result,
1994            CreationRejection,
1995            Never,
1996        >,
1997    > + Send {
1998        async move { match self {} }
1999    }
2000}
2001
2002impl<A, Occurrence, C> ChildCreationProduct<A, Occurrence> for C
2003where
2004    A: EndpointAddress,
2005    C: Behavior,
2006    C::Protocol: Protocol<Addr = A>,
2007{
2008    type Result = ChildCreationOutcome<C, Occurrence>;
2009}
2010
2011impl<A, Occurrence, C, Host> CreateSelectedChild<A, Occurrence, Host> for C
2012where
2013    A: EndpointAddress,
2014    C: Behavior,
2015    C::Protocol: Protocol<Addr = A>,
2016    Host: EstablishChild<Occurrence, C>,
2017{
2018    fn dispatch_birth_at(
2019        self,
2020        id: CreationId,
2021        route: A::Nonce,
2022        kind: CreationKind,
2023        host: &mut Host,
2024    ) -> impl Future<
2025        Output = ItemSettlement<
2026            RoutedCreation<A, Self>,
2027            <Self as ChildCreationProduct<A, Occurrence>>::Result,
2028            CreationRejection,
2029            Never,
2030        >,
2031    > + Send {
2032        host.establish_child(RoutedCreation::new(
2033            CreateChild::from_parts(id, self, kind),
2034            route,
2035        ))
2036    }
2037}
2038
2039/// A type-level description of a behavior's creation capability.
2040pub trait BirthMode {
2041    type Child;
2042}
2043
2044/// Empty protocol projection of a closed behavior-birth algebra.
2045pub struct NoBirthProtocols;
2046
2047/// One behavior protocol followed by the remaining closed birth projection.
2048pub struct BirthProtocol<P: Protocol, Tail> {
2049    protocol: PhantomData<fn() -> P>,
2050    tail: PhantomData<fn() -> Tail>,
2051}
2052
2053/// Structural position selecting the current projected birth protocol.
2054pub struct BirthProtocolHead;
2055
2056/// Structural position selecting inside the remaining protocol projection.
2057pub struct BirthProtocolTail<Position>(PhantomData<fn() -> Position>);
2058
2059/// Static membership evidence for one occurrence in a birth-protocol product.
2060pub trait BirthProtocolAt<P: Protocol, Position> {}
2061
2062impl<P: Protocol, Tail> BirthProtocolAt<P, BirthProtocolHead> for BirthProtocol<P, Tail> {}
2063
2064impl<Head, Tail, P, Position> BirthProtocolAt<P, BirthProtocolTail<Position>>
2065    for BirthProtocol<Head, Tail>
2066where
2067    Head: Protocol,
2068    P: Protocol,
2069    Tail: BirthProtocolAt<P, Position>,
2070{
2071}
2072
2073/// Closed product operation used by the structural birth projection.
2074#[doc(hidden)]
2075pub trait BirthProtocolProduct {
2076    type Append<Tail: BirthProtocolProduct>: BirthProtocolProduct;
2077}
2078
2079impl BirthProtocolProduct for NoBirthProtocols {
2080    type Append<Tail: BirthProtocolProduct> = Tail;
2081}
2082
2083impl<P, Rest> BirthProtocolProduct for BirthProtocol<P, Rest>
2084where
2085    P: Protocol,
2086    Rest: BirthProtocolProduct,
2087{
2088    type Append<Tail: BirthProtocolProduct> = BirthProtocol<P, Rest::Append<Tail>>;
2089}
2090
2091/// Closed static projection of a behavior's own protocol and every protocol
2092/// reachable through its transitive staged-birth algebra.
2093///
2094/// This is structural information derived from [`Behavior::Birth`]. It makes
2095/// no hosting or allocation decision and does not inspect send destinations.
2096pub trait BirthProtocols: Behavior {
2097    type Protocols: BirthProtocolProduct;
2098}
2099
2100impl<B> BirthProtocols for B
2101where
2102    B: Behavior,
2103    B::Birth: BirthModeProtocols,
2104{
2105    type Protocols = BirthProtocol<B::Protocol, <B::Birth as BirthModeProtocols>::Protocols>;
2106}
2107
2108#[doc(hidden)]
2109pub trait BirthModeProtocols {
2110    type Protocols: BirthProtocolProduct;
2111}
2112
2113impl<M> BirthModeProtocols for M
2114where
2115    M: BirthMode,
2116    M::Child: BirthNodeProtocols,
2117{
2118    type Protocols = <M::Child as BirthNodeProtocols>::Protocols;
2119}
2120
2121#[doc(hidden)]
2122pub trait BirthNodeProtocols {
2123    type Protocols: BirthProtocolProduct;
2124}
2125
2126impl<B> BirthNodeProtocols for B
2127where
2128    B: BirthProtocols,
2129{
2130    type Protocols = B::Protocols;
2131}
2132
2133impl<Head, Tail> BirthNodeProtocols for ChildChoice<Head, Tail>
2134where
2135    Head: BirthNodeProtocols,
2136    Tail: BirthNodeProtocols,
2137{
2138    type Protocols = <Head::Protocols as BirthProtocolProduct>::Append<Tail::Protocols>;
2139}
2140
2141impl BirthNodeProtocols for Never {
2142    type Protocols = NoBirthProtocols;
2143}
2144
2145/// Structural logical-destination projection for one closed birth node.
2146///
2147/// This implementation detail is public only because its associated product
2148/// participates in the blanket [`crate::LogicalHostRequirements`] interface.
2149#[doc(hidden)]
2150pub trait BirthNodeLogicalHosts {
2151    type LogicalHosts: BirthProtocolProduct;
2152}
2153
2154impl<B> BirthNodeLogicalHosts for B
2155where
2156    B: crate::LogicalHostRequirements,
2157{
2158    type LogicalHosts = B::LogicalHosts;
2159}
2160
2161impl<Head, Tail> BirthNodeLogicalHosts for ChildChoice<Head, Tail>
2162where
2163    Head: BirthNodeLogicalHosts,
2164    Tail: BirthNodeLogicalHosts,
2165{
2166    type LogicalHosts = <Head::LogicalHosts as BirthProtocolProduct>::Append<Tail::LogicalHosts>;
2167}
2168
2169impl BirthNodeLogicalHosts for Never {
2170    type LogicalHosts = NoBirthProtocols;
2171}
2172
2173/// This behavior cannot emit child births.
2174#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2175pub struct NoBirths;
2176
2177impl BirthMode for NoBirths {
2178    type Child = Never;
2179}
2180
2181/// This behavior may emit births of `C`.
2182#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2183pub struct Births<C>(PhantomData<fn() -> C>);
2184
2185impl<C> BirthMode for Births<C> {
2186    type Child = C;
2187}
2188
2189#[cfg(test)]
2190mod tests {
2191    use super::*;
2192    use crate::{Actions, BehaviorActed, NoBirths, User};
2193
2194    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
2195    struct TestAddr(u64);
2196
2197    impl Address for TestAddr {
2198        type Nonce = u64;
2199    }
2200
2201    struct TestEndpoint<P>(PhantomData<fn() -> P>);
2202
2203    impl<P> Clone for TestEndpoint<P> {
2204        fn clone(&self) -> Self {
2205            *self
2206        }
2207    }
2208
2209    impl<P> Copy for TestEndpoint<P> {}
2210
2211    impl EndpointAddress for TestAddr {
2212        type Established<P>
2213            = TestEndpoint<P>
2214        where
2215            P: Protocol<Addr = Self>;
2216    }
2217
2218    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2219    struct Child;
2220
2221    struct SharedProtocol;
2222
2223    impl behavior::Protocol for SharedProtocol {
2224        type Addr = TestAddr;
2225        type Msg = u8;
2226    }
2227
2228    struct Primary;
2229    struct Fallback;
2230
2231    macro_rules! shared_protocol_behavior {
2232        ($behavior:ty, $birth:ty) => {
2233            impl Behavior for $behavior {
2234                type Protocol = SharedProtocol;
2235                type Event = User<TestAddr, u8>;
2236                type Sends = Vec<Never>;
2237                type Ph = Never;
2238                type Error = Never;
2239                type Birth = $birth;
2240
2241                fn transition(
2242                    &mut self,
2243                    _: crate::ActiveTurn,
2244                    _: Self::Event,
2245                ) -> BehaviorActed<Self> {
2246                    Ok(Actions::cont())
2247                }
2248            }
2249        };
2250    }
2251
2252    shared_protocol_behavior!(Primary, Births<Child>);
2253    shared_protocol_behavior!(Fallback, NoBirths);
2254
2255    impl behavior::Protocol for Child {
2256        type Addr = TestAddr;
2257        type Msg = u8;
2258    }
2259
2260    impl Behavior for Child {
2261        type Protocol = Self;
2262        type Event = User<TestAddr, u8>;
2263        type Sends = Vec<Never>;
2264        type Ph = Never;
2265        type Error = Never;
2266        type Birth = NoBirths;
2267
2268        fn transition(&mut self, _: crate::ActiveTurn, _: Self::Event) -> BehaviorActed<Self> {
2269            Ok(Actions::cont())
2270        }
2271    }
2272
2273    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2274    enum ChildPlan {
2275        CreateChild,
2276        RejectBeforeTransfer,
2277    }
2278
2279    struct RecordingHost {
2280        calls: usize,
2281        observed: Vec<(CreationId, u64, CreationKind)>,
2282        plan: ChildPlan,
2283    }
2284
2285    #[derive(Debug, PartialEq, Eq)]
2286    enum SharedCreation {
2287        Primary(CreationId, u64),
2288        Fallback(CreationId, u64),
2289    }
2290
2291    #[derive(Default)]
2292    struct SharedProtocolHost(Vec<SharedCreation>);
2293
2294    impl EstablishChild<ChildHead, Primary> for SharedProtocolHost {
2295        async fn establish_child(
2296            &mut self,
2297            creation: RoutedCreation<TestAddr, Primary>,
2298        ) -> ItemSettlement<
2299            RoutedCreation<TestAddr, Primary>,
2300            ChildCreationOutcome<Primary, ChildHead>,
2301            CreationRejection,
2302            Never,
2303        > {
2304            let id = creation.id();
2305            let kind = creation.kind();
2306            let route = creation.route();
2307            let (creation, _) = creation.into_parts();
2308            let (_, _child, _) = creation.into_parts();
2309            self.0.push(SharedCreation::Primary(id, route));
2310            ItemSettlement::Accepted(ChildCreationOutcome::Established {
2311                established: EstablishedCreation::installed(
2312                    id,
2313                    kind,
2314                    EstablishedRecipient::issued(TestEndpoint(PhantomData)),
2315                ),
2316            })
2317        }
2318    }
2319
2320    impl EstablishChild<ChildTail<ChildHead>, Fallback> for SharedProtocolHost {
2321        async fn establish_child(
2322            &mut self,
2323            creation: RoutedCreation<TestAddr, Fallback>,
2324        ) -> ItemSettlement<
2325            RoutedCreation<TestAddr, Fallback>,
2326            ChildCreationOutcome<Fallback, ChildTail<ChildHead>>,
2327            CreationRejection,
2328            Never,
2329        > {
2330            let id = creation.id();
2331            let kind = creation.kind();
2332            let route = creation.route();
2333            let (creation, _) = creation.into_parts();
2334            let (_, _child, _) = creation.into_parts();
2335            self.0.push(SharedCreation::Fallback(id, route));
2336            ItemSettlement::Accepted(ChildCreationOutcome::Established {
2337                established: EstablishedCreation::installed(
2338                    id,
2339                    kind,
2340                    EstablishedRecipient::issued(TestEndpoint(PhantomData)),
2341                ),
2342            })
2343        }
2344    }
2345
2346    impl EstablishChild<ChildHead, Child> for RecordingHost {
2347        async fn establish_child(
2348            &mut self,
2349            creation: RoutedCreation<TestAddr, Child>,
2350        ) -> ItemSettlement<
2351            RoutedCreation<TestAddr, Child>,
2352            ChildCreationOutcome<Child, ChildHead>,
2353            CreationRejection,
2354            Never,
2355        > {
2356            self.calls += 1;
2357            self.observed
2358                .push((creation.id(), creation.route(), creation.kind()));
2359            match self.plan {
2360                ChildPlan::CreateChild => {
2361                    let id = creation.id();
2362                    let kind = creation.kind();
2363                    let (creation, _) = creation.into_parts();
2364                    let (_, _child, _) = creation.into_parts();
2365                    ItemSettlement::Accepted(ChildCreationOutcome::Established {
2366                        established: EstablishedCreation::installed(
2367                            id,
2368                            kind,
2369                            EstablishedRecipient::issued(TestEndpoint(PhantomData)),
2370                        ),
2371                    })
2372                }
2373                ChildPlan::RejectBeforeTransfer => ItemSettlement::Rejected {
2374                    item: creation,
2375                    reason: CreationRejection::EnvironmentFailed,
2376                },
2377            }
2378        }
2379    }
2380
2381    fn host(plan: ChildPlan) -> RecordingHost {
2382        RecordingHost {
2383            calls: 0,
2384            observed: Vec::new(),
2385            plan,
2386        }
2387    }
2388
2389    fn assert_send<T: Send>(_: &T) {}
2390
2391    #[test]
2392    fn empty_child_product_stages_no_creations() {
2393        let creations = <NoChildren as ChildProduct<TestAddr>>::stage(NoChildren);
2394        assert!(creations.is_empty());
2395    }
2396
2397    #[test]
2398    fn creation_values_preserve_ids_order_and_debug_identity() {
2399        let mut sequence = CreationSequence::new();
2400        let first = sequence.issue().expect("the first creation ID exists");
2401        let second = sequence.issue().expect("the second creation ID exists");
2402        assert_eq!(first.get(), 1);
2403        assert_eq!(second.get(), 2);
2404
2405        let first_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(first);
2406        let same_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(first);
2407        let second_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(second);
2408        assert_eq!(first_correlation, same_correlation);
2409        assert_ne!(first_correlation, second_correlation);
2410        assert_eq!(
2411            format!("{first_correlation:?}"),
2412            "CreationCorrelation(CreationId(1))"
2413        );
2414
2415        let mut creations = Creations::one(1_u8);
2416        creations.extend([2, 3]);
2417        assert_eq!(creations.len(), 3);
2418        assert!(!creations.is_empty());
2419        assert_eq!(creations.iter().copied().collect::<Vec<_>>(), [1, 2, 3]);
2420        assert_eq!(
2421            (&creations).into_iter().copied().collect::<Vec<_>>(),
2422            [1, 2, 3]
2423        );
2424
2425        let collected: Creations<_> = [4_u8, 5].into_iter().collect();
2426        assert_eq!(collected.len(), 2);
2427        assert_eq!(collected.into_iter().collect::<Vec<_>>(), [4, 5]);
2428
2429        let returned = ChildCreationSettled::<Child, ChildHead>::new(SettledItem::Unattempted(
2430            RoutedCreation::new(CreateChild::birth(first, Child), 17),
2431        ));
2432        assert_eq!(format!("{returned:?}"), "ChildCreationSettled { .. }");
2433    }
2434
2435    #[tokio::test]
2436    async fn concrete_child_dispatches_once_with_exact_creation_and_route() {
2437        let mut sequence = CreationSequence::new();
2438        let previous = sequence.issue().expect("the previous ID exists");
2439        let id = sequence.issue().expect("the replacement ID exists");
2440        let mut host = host(ChildPlan::CreateChild);
2441        let kind = CreationKind::replacement(previous);
2442        let future = Child.dispatch_birth(id, 17, kind, &mut host);
2443        assert_send(&future);
2444        let result = future.await;
2445
2446        let ItemSettlement::Accepted(ChildCreationOutcome::Established { established }) = result
2447        else {
2448            panic!("expected the child to be created");
2449        };
2450        assert_eq!(established.id(), id);
2451        assert_eq!(host.calls, 1);
2452        assert_eq!(host.observed, [(id, 17, kind)]);
2453    }
2454
2455    #[tokio::test]
2456    async fn concrete_child_returns_the_exact_rejected_creation_without_retry() {
2457        let mut sequence = CreationSequence::new();
2458        let previous = sequence.issue().expect("the previous ID exists");
2459        let id = sequence.issue().expect("the replacement ID exists");
2460        let mut host = host(ChildPlan::RejectBeforeTransfer);
2461        let kind = CreationKind::replacement(previous);
2462        let future = Child.dispatch_birth(id, 23, kind, &mut host);
2463        assert_send(&future);
2464        let result = future.await;
2465
2466        let ItemSettlement::Rejected { item, reason } = result else {
2467            panic!("expected refusal before child ownership transfer");
2468        };
2469        assert_eq!(
2470            item,
2471            RoutedCreation::new(CreateChild::replacement(id, previous, Child), 23)
2472        );
2473        assert_eq!(reason, CreationRejection::EnvironmentFailed);
2474        assert_eq!(host.calls, 1);
2475        assert_eq!(host.observed, [(id, 23, kind)]);
2476    }
2477
2478    #[tokio::test]
2479    async fn distinct_child_alternatives_preserve_one_canonical_protocol_identity() {
2480        type Alternatives = ChildChoice<Primary, ChildChoice<Fallback, Never>>;
2481
2482        fn requires_shared_protocol<C: Behavior<Protocol = SharedProtocol>>() {}
2483        requires_shared_protocol::<Primary>();
2484        requires_shared_protocol::<Fallback>();
2485
2486        let mut sequence = CreationSequence::new();
2487        let primary_id = sequence.issue().expect("the primary ID exists");
2488        let fallback_id = sequence.issue().expect("the fallback ID exists");
2489        let mut host = SharedProtocolHost::default();
2490        let primary = Alternatives::Head(Primary)
2491            .dispatch_birth(primary_id, 11, CreationKind::Birth, &mut host)
2492            .await;
2493        let fallback = Alternatives::Tail(ChildChoice::Head(Fallback))
2494            .dispatch_birth(fallback_id, 17, CreationKind::Birth, &mut host)
2495            .await;
2496
2497        let ItemSettlement::Accepted(ChildChoice::Head(ChildCreationOutcome::Established {
2498            established: primary,
2499        })) = primary
2500        else {
2501            panic!("expected the primary child result");
2502        };
2503        assert_eq!(primary.id(), primary_id);
2504        let ItemSettlement::Accepted(ChildChoice::Tail(ChildChoice::Head(
2505            ChildCreationOutcome::Established {
2506                established: fallback,
2507            },
2508        ))) = fallback
2509        else {
2510            panic!("expected the fallback child result");
2511        };
2512        assert_eq!(fallback.id(), fallback_id);
2513
2514        assert_eq!(
2515            host.0,
2516            [
2517                SharedCreation::Primary(primary_id, 11),
2518                SharedCreation::Fallback(fallback_id, 17),
2519            ]
2520        );
2521    }
2522
2523    #[test]
2524    fn birth_protocol_projection_recurses_without_inspecting_send_lanes() {
2525        type Protocols = <Primary as BirthProtocols>::Protocols;
2526        type Expected = BirthProtocol<SharedProtocol, BirthProtocol<Child, NoBirthProtocols>>;
2527
2528        trait Same<T> {}
2529        impl<T> Same<T> for T {}
2530        fn exact<T: Same<Expected>>() {}
2531        exact::<Protocols>();
2532    }
2533}