use core::future::Future;
use core::marker::PhantomData;
use core::num::NonZeroU64;
use super::addressing::{Address, EndpointAddress, EstablishedActor, EstablishedRecipient};
use crate::next::Never;
use crate::{
ActionItem, Actions, Behavior, BehaviorAddr, BehaviorBase, ItemSettlement, Protocol,
SettledItem,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CreationId(NonZeroU64);
impl CreationId {
#[doc(hidden)]
#[must_use]
pub const fn get(self) -> u64 {
self.0.get()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct CreationSequence {
next: Option<NonZeroU64>,
}
impl CreationSequence {
#[must_use]
pub const fn new() -> Self {
Self {
next: Some(NonZeroU64::MIN),
}
}
pub fn issue(&mut self) -> Option<CreationId> {
let value = self.next?;
self.next = value.checked_add(1);
Some(CreationId(value))
}
}
impl Default for CreationSequence {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CreationKind {
Birth,
Replacement {
previous: CreationId,
},
}
impl CreationKind {
#[must_use]
pub const fn replacement(previous: CreationId) -> Self {
Self::Replacement { previous }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CreateChild<A: Address, New> {
id: CreationId,
child: New,
kind: CreationKind,
address: PhantomData<fn() -> A>,
}
impl<A: Address, New> CreateChild<A, New> {
#[must_use]
pub(crate) const fn from_parts(id: CreationId, child: New, kind: CreationKind) -> Self {
Self {
id,
child,
kind,
address: PhantomData,
}
}
#[must_use]
pub const fn birth(id: CreationId, child: New) -> Self {
Self::from_parts(id, child, CreationKind::Birth)
}
#[must_use]
pub const fn replacement(id: CreationId, previous: CreationId, child: New) -> Self {
Self::from_parts(id, child, CreationKind::replacement(previous))
}
#[must_use]
pub const fn id(&self) -> CreationId {
self.id
}
#[must_use]
pub const fn kind(&self) -> CreationKind {
self.kind
}
#[must_use]
pub const fn child(&self) -> &New {
&self.child
}
#[doc(hidden)]
#[must_use]
pub fn into_parts(self) -> (CreationId, New, CreationKind) {
(self.id, self.child, self.kind)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Creations<Item> {
items: Vec<Item>,
}
impl<Item> Creations<Item> {
#[must_use]
pub const fn empty() -> Self {
Self { items: Vec::new() }
}
#[must_use]
pub fn one(item: Item) -> Self {
Self { items: vec![item] }
}
#[must_use]
pub fn and(mut self, item: Item) -> Self {
self.items.push(item);
self
}
#[must_use]
pub fn map<Mapped>(self, mut map: impl FnMut(Item) -> Mapped) -> Creations<Mapped> {
Creations::from_items(self.items.into_iter().map(&mut map).collect())
}
#[must_use]
pub fn len(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub(crate) fn from_items(items: Vec<Item>) -> Self {
Self { items }
}
pub fn iter(&self) -> core::slice::Iter<'_, Item> {
self.items.iter()
}
}
impl<Item> Default for Creations<Item> {
fn default() -> Self {
Self::empty()
}
}
impl<Item> Extend<Item> for Creations<Item> {
fn extend<Items: IntoIterator<Item = Item>>(&mut self, items: Items) {
self.items.extend(items);
}
}
impl<Item> FromIterator<Item> for Creations<Item> {
fn from_iter<Items: IntoIterator<Item = Item>>(items: Items) -> Self {
Self::from_items(items.into_iter().collect())
}
}
impl<'a, Item> IntoIterator for &'a Creations<Item> {
type Item = &'a Item;
type IntoIter = core::slice::Iter<'a, Item>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<Item> IntoIterator for Creations<Item> {
type Item = Item;
type IntoIter = std::vec::IntoIter<Item>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
pub trait ChildRole<Parent: Behavior> {
type Child: Behavior;
type Position: ChildPosition<<Parent::Birth as BirthMode>::Child, Self::Child>;
}
pub trait ChildOccurrence<Parent: Behavior>: Sized {
#[doc(hidden)]
type Resolution: ChildOccurrenceResolution<Parent, Self>;
}
#[doc(hidden)]
pub struct DeclaredChildOccurrence;
#[doc(hidden)]
pub struct StructuralChildOccurrence<Position>(PhantomData<fn() -> Position>);
pub trait ResolveChildOccurrence<Occurrence>:
Behavior + sealed::ResolveChildOccurrence<Occurrence>
{
type Child: Behavior;
type Position: ChildPosition<<Self::Birth as BirthMode>::Child, Self::Child>;
}
impl<Emitter, Occurrence> ResolveChildOccurrence<Occurrence> for Emitter
where
Emitter: Behavior + BehaviorBase + sealed::ResolveChildOccurrence<Occurrence>,
Emitter::Base: Behavior,
Occurrence: ChildOccurrence<Emitter::Base>,
Occurrence::Resolution: ResolveChildOccurrenceDescriptor<Emitter, Occurrence>,
{
type Child =
<Occurrence::Resolution as ResolveChildOccurrenceDescriptor<Emitter, Occurrence>>::Child;
type Position =
<Occurrence::Resolution as ResolveChildOccurrenceDescriptor<Emitter, Occurrence>>::Position;
}
pub type ResolvedChild<Emitter, Occurrence> =
<Emitter as ResolveChildOccurrence<Occurrence>>::Child;
pub type ResolvedChildPosition<Emitter, Occurrence> =
<Emitter as ResolveChildOccurrence<Occurrence>>::Position;
pub type RoleChild<Parent, Role> = <Role as ChildRole<Parent>>::Child;
pub type RoleProtocol<Parent, Role> = <RoleChild<Parent, Role> as Behavior>::Protocol;
#[doc(hidden)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RoutedCreation<A: Address, New> {
creation: CreateChild<A, New>,
route: A::Nonce,
}
impl<A: Address, New> RoutedCreation<A, New> {
#[must_use]
pub const fn new(creation: CreateChild<A, New>, route: A::Nonce) -> Self {
Self { creation, route }
}
#[must_use]
pub const fn id(&self) -> CreationId {
self.creation.id()
}
#[must_use]
pub const fn kind(&self) -> CreationKind {
self.creation.kind()
}
#[must_use]
pub const fn route(&self) -> A::Nonce {
self.route
}
#[must_use]
pub fn into_parts(self) -> (CreateChild<A, New>, A::Nonce) {
(self.creation, self.route)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum AllocationRejection {
#[error("fresh actor-address allocation is exhausted")]
Exhausted,
#[error("the proposed actor address is already claimed")]
AddressAlreadyClaimed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum CreationRejection {
#[error("fresh allocation failed: {0}")]
Allocation(AllocationRejection),
#[error("child initialization failed")]
InitializationFailed,
#[error("the interpreter could not install and commit the child")]
EnvironmentFailed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[error("the creator child namespace is exhausted")]
pub struct ChildNamespaceExhausted;
impl<A, New> ActionItem for Creations<CreateChild<A, New>>
where
A: Address,
A::Nonce: Send,
New: Send,
{
type Accepted = Creations<RoutedCreation<A, New>>;
type Rejection = ChildNamespaceExhausted;
type Prerequisite = Never;
}
pub enum EstablishedCreation<P, Occurrence>
where
P: Protocol,
P::Addr: EndpointAddress,
{
Installed {
id: CreationId,
kind: CreationKind,
recipient: EstablishedRecipient<P>,
occurrence: PhantomData<fn() -> Occurrence>,
},
Rejected {
id: CreationId,
kind: CreationKind,
reason: CreationRejection,
occurrence: PhantomData<fn() -> Occurrence>,
},
}
impl<P, Occurrence> EstablishedCreation<P, Occurrence>
where
P: Protocol,
P::Addr: EndpointAddress,
{
#[must_use]
pub const fn installed(
id: CreationId,
kind: CreationKind,
recipient: EstablishedRecipient<P>,
) -> Self {
Self::Installed {
id,
kind,
recipient,
occurrence: PhantomData,
}
}
#[must_use]
pub const fn rejected(id: CreationId, kind: CreationKind, reason: CreationRejection) -> Self {
Self::Rejected {
id,
kind,
reason,
occurrence: PhantomData,
}
}
#[must_use]
pub const fn id(&self) -> CreationId {
match self {
Self::Installed { id, .. } | Self::Rejected { id, .. } => *id,
}
}
#[must_use]
pub const fn kind(&self) -> CreationKind {
match self {
Self::Installed { kind, .. } | Self::Rejected { kind, .. } => *kind,
}
}
pub fn into_recipient(self) -> Result<EstablishedRecipient<P>, CreationRejection> {
match self {
Self::Installed { recipient, .. } => Ok(recipient),
Self::Rejected { reason, .. } => Err(reason),
}
}
pub fn into_actor<Parent>(
self,
) -> Result<EstablishedActor<RoleChild<Parent, Occurrence>>, CreationRejection>
where
Parent: Behavior,
Occurrence: ChildRole<Parent>,
RoleChild<Parent, Occurrence>: Behavior<Protocol = P>,
{
self.into_recipient().map(EstablishedActor::from_recipient)
}
}
pub enum ChildCreationOutcome<C, Occurrence>
where
C: Behavior,
BehaviorAddr<C>: EndpointAddress,
{
Established {
established: EstablishedCreation<C::Protocol, Occurrence>,
},
InitializationRejected {
creation: RoutedCreation<BehaviorAddr<C>, C>,
error: C::Error,
},
HostRejected {
creation: RoutedCreation<BehaviorAddr<C>, C>,
initialization: Actions<BehaviorAddr<C>, C::Ph, C::Sends, C::Birth>,
reason: CreationRejection,
},
}
impl<C, Occurrence> ChildCreationOutcome<C, Occurrence>
where
C: Behavior,
BehaviorAddr<C>: EndpointAddress,
{
pub fn into_actor(self) -> Result<EstablishedActor<C>, Self> {
match self {
Self::Established {
established: EstablishedCreation::Installed { recipient, .. },
} => Ok(EstablishedActor::from_recipient(recipient)),
other => Err(other),
}
}
}
#[must_use = "a child-creation settlement must be admitted or retained"]
pub struct ChildCreationSettled<C, Occurrence>
where
C: Behavior,
BehaviorAddr<C>: EndpointAddress,
{
settlement: SettledItem<
RoutedCreation<BehaviorAddr<C>, C>,
ItemSettlement<
RoutedCreation<BehaviorAddr<C>, C>,
ChildCreationOutcome<C, Occurrence>,
CreationRejection,
Never,
>,
>,
}
impl<C, Occurrence> ChildCreationSettled<C, Occurrence>
where
C: Behavior,
BehaviorAddr<C>: EndpointAddress,
{
#[must_use]
pub const fn new(
settlement: SettledItem<
RoutedCreation<BehaviorAddr<C>, C>,
ItemSettlement<
RoutedCreation<BehaviorAddr<C>, C>,
ChildCreationOutcome<C, Occurrence>,
CreationRejection,
Never,
>,
>,
) -> Self {
Self { settlement }
}
#[must_use]
pub fn into_settlement(
self,
) -> SettledItem<
RoutedCreation<BehaviorAddr<C>, C>,
ItemSettlement<
RoutedCreation<BehaviorAddr<C>, C>,
ChildCreationOutcome<C, Occurrence>,
CreationRejection,
Never,
>,
> {
self.settlement
}
}
impl<C, Occurrence> core::fmt::Debug for ChildCreationSettled<C, Occurrence>
where
C: Behavior,
BehaviorAddr<C>: EndpointAddress,
{
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter
.debug_struct("ChildCreationSettled")
.finish_non_exhaustive()
}
}
#[doc(hidden)]
pub struct CreationCorrelation<P, Occurrence>
where
P: Protocol,
{
id: CreationId,
occurrence: PhantomData<fn() -> (P, Occurrence)>,
}
impl<P, Occurrence> CreationCorrelation<P, Occurrence>
where
P: Protocol,
{
#[must_use]
pub const fn new(id: CreationId) -> Self {
Self {
id,
occurrence: PhantomData,
}
}
#[must_use]
pub const fn id(self) -> CreationId {
self.id
}
}
impl<P, Occurrence> Copy for CreationCorrelation<P, Occurrence> where P: Protocol {}
impl<P, Occurrence> Clone for CreationCorrelation<P, Occurrence>
where
P: Protocol,
{
fn clone(&self) -> Self {
*self
}
}
impl<P, Occurrence> core::fmt::Debug for CreationCorrelation<P, Occurrence>
where
P: Protocol,
{
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter
.debug_tuple("CreationCorrelation")
.field(&self.id)
.finish()
}
}
impl<P, Occurrence> PartialEq for CreationCorrelation<P, Occurrence>
where
P: Protocol,
{
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<P, Occurrence> Eq for CreationCorrelation<P, Occurrence> where P: Protocol {}
pub struct ChildDelivery<P, Occurrence>
where
P: Protocol,
{
pub creation: CreationId,
pub message: P::Msg,
occurrence: PhantomData<fn() -> Occurrence>,
}
pub struct ChildInput<Child, Source, Input, Occurrence>
where
Child: Behavior,
{
pub creation: CreationId,
pub input: Input,
marker: PhantomData<fn() -> (Child, Source, Occurrence)>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ChildDeliveryReason {
MissingBinding,
ClosedRecipient,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ChildInputReason {
MissingBinding,
ClosedControlLane,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ChildReport<R> {
pub child: CreationId,
pub report: R,
}
impl<R> ChildReport<R> {
#[must_use]
pub const fn new(child: CreationId, report: R) -> Self {
Self { child, report }
}
}
impl<R> From<(CreationId, crate::ReportToParent<R>)> for ChildReport<R> {
fn from((child, request): (CreationId, crate::ReportToParent<R>)) -> Self {
Self::new(child, request.into_inner())
}
}
impl<Child, Source, Input, Occurrence> ChildInput<Child, Source, Input, Occurrence>
where
Child: Behavior,
Child::Event: crate::ChildInputIngress<Source, Input>,
{
#[must_use]
pub const fn after(creation: CreationId, input: Input) -> Self {
Self {
creation,
input,
marker: PhantomData,
}
}
}
impl<Child, Source, Input, Occurrence> Clone for ChildInput<Child, Source, Input, Occurrence>
where
Child: Behavior,
Input: Clone,
{
fn clone(&self) -> Self {
Self {
creation: self.creation,
input: self.input.clone(),
marker: PhantomData,
}
}
}
impl<P, Occurrence> ChildDelivery<P, Occurrence>
where
P: Protocol,
{
#[must_use]
pub const fn after(creation: CreationId, message: P::Msg) -> Self {
Self {
creation,
message,
occurrence: PhantomData,
}
}
}
impl<P, Occurrence> Clone for ChildDelivery<P, Occurrence>
where
P: Protocol,
P::Msg: Clone,
{
fn clone(&self) -> Self {
Self {
creation: self.creation,
message: self.message.clone(),
occurrence: PhantomData,
}
}
}
impl<P, Occurrence> ActionItem for ChildDelivery<P, Occurrence>
where
P: Protocol,
P::Msg: Send,
{
type Accepted = ();
type Rejection = ChildDeliveryReason;
type Prerequisite = CreationCorrelation<P, Occurrence>;
}
impl<Child, Source, Input, Occurrence> ActionItem for ChildInput<Child, Source, Input, Occurrence>
where
Child: Behavior,
Input: Send,
{
type Accepted = ();
type Rejection = ChildInputReason;
type Prerequisite = CreationCorrelation<Child::Protocol, Occurrence>;
}
pub trait EstablishChild<Occurrence, C>
where
C: Behavior,
BehaviorAddr<C>: EndpointAddress,
{
fn establish_child(
&mut self,
creation: RoutedCreation<BehaviorAddr<C>, C>,
) -> impl Future<
Output = ItemSettlement<
RoutedCreation<BehaviorAddr<C>, C>,
ChildCreationOutcome<C, Occurrence>,
CreationRejection,
Never,
>,
> + Send;
}
#[doc(hidden)]
pub trait ChildCreationProduct<A: Address, Occurrence>: Sized {
type Result;
}
pub trait DispatchBirth<A: Address, Host>: ChildCreationProduct<A, ChildHead> + Sized {
fn dispatch_birth(
self,
id: CreationId,
route: A::Nonce,
kind: CreationKind,
host: &mut Host,
) -> impl Future<
Output = ItemSettlement<
RoutedCreation<A, Self>,
<Self as ChildCreationProduct<A, ChildHead>>::Result,
CreationRejection,
Never,
>,
> + Send;
}
trait CreateSelectedChild<A: Address, Occurrence, Host>:
ChildCreationProduct<A, Occurrence> + Sized
{
fn dispatch_birth_at(
self,
id: CreationId,
route: A::Nonce,
kind: CreationKind,
host: &mut Host,
) -> impl Future<
Output = ItemSettlement<
RoutedCreation<A, Self>,
<Self as ChildCreationProduct<A, Occurrence>>::Result,
CreationRejection,
Never,
>,
> + Send;
}
impl<A, Child, Host> DispatchBirth<A, Host> for Child
where
A: Address,
Child: CreateSelectedChild<A, ChildHead, Host>,
{
fn dispatch_birth(
self,
id: CreationId,
route: A::Nonce,
kind: CreationKind,
host: &mut Host,
) -> impl Future<
Output = ItemSettlement<
RoutedCreation<A, Self>,
<Self as ChildCreationProduct<A, ChildHead>>::Result,
CreationRejection,
Never,
>,
> + Send {
self.dispatch_birth_at(id, route, kind, host)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ChildChoice<Head, Tail> {
Head(Head),
Tail(Tail),
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct ChildHead;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct ChildTail<Position>(PhantomData<fn() -> Position>);
pub trait ChildPosition<Children, Child: Behavior>: sealed::ChildPosition {}
impl sealed::ChildPosition for ChildHead {}
impl<Child: Behavior> ChildPosition<Child, Child> for ChildHead {}
impl<Head: Behavior, Tail> ChildPosition<ChildChoice<Head, Tail>, Head> for ChildHead {}
impl<Position> sealed::ChildPosition for ChildTail<Position> {}
impl<Head, Tail, Position, Child> ChildPosition<ChildChoice<Head, Tail>, Child>
for ChildTail<Position>
where
Child: Behavior,
Position: ChildPosition<Tail, Child>,
{
}
pub trait BirthNodeAppend<Tail>: sealed::BirthNode + Sized
where
Tail: sealed::BirthNode,
{
type Output: sealed::BirthNode;
fn append_prefix(self) -> Self::Output;
fn append_tail(tail: Tail) -> Self::Output;
#[must_use]
fn append_creations<A: Address>(
prefix: Creations<CreateChild<A, Self>>,
tail: Creations<CreateChild<A, Tail>>,
) -> Creations<CreateChild<A, Self::Output>> {
let mut combined = Vec::with_capacity(prefix.len() + tail.len());
combined.extend(prefix.into_iter().map(|creation| {
let (id, child, kind) = creation.into_parts();
CreateChild::from_parts(id, Self::append_prefix(child), kind)
}));
combined.extend(tail.into_iter().map(|creation| {
let (id, child, kind) = creation.into_parts();
CreateChild::from_parts(id, Self::append_tail(child), kind)
}));
Creations::from_items(combined)
}
}
impl<Tail> BirthNodeAppend<Tail> for Never
where
Tail: sealed::BirthNode,
{
type Output = Tail;
fn append_prefix(self) -> Self::Output {
match self {}
}
fn append_tail(tail: Tail) -> Self::Output {
tail
}
}
impl<Node> BirthNodeAppend<Never> for Node
where
Node: sealed::NonEmptyBirthNode,
{
type Output = Node;
fn append_prefix(self) -> Self::Output {
self
}
fn append_tail(tail: Never) -> Self::Output {
match tail {}
}
}
impl<Child, Tail> BirthNodeAppend<Tail> for Child
where
Child: Behavior,
Tail: sealed::NonEmptyBirthNode,
{
type Output = ChildChoice<Child, Tail>;
fn append_prefix(self) -> Self::Output {
ChildChoice::Head(self)
}
fn append_tail(tail: Tail) -> Self::Output {
ChildChoice::Tail(tail)
}
}
impl<Head, Rest, Tail> BirthNodeAppend<Tail> for ChildChoice<Head, Rest>
where
Head: Behavior,
Rest: sealed::BirthNode + BirthNodeAppend<Tail>,
Tail: sealed::NonEmptyBirthNode,
Rest::Output: sealed::BirthNode,
{
type Output = ChildChoice<Head, Rest::Output>;
fn append_prefix(self) -> Self::Output {
match self {
ChildChoice::Head(head) => ChildChoice::Head(head),
ChildChoice::Tail(rest) => ChildChoice::Tail(rest.append_prefix()),
}
}
fn append_tail(tail: Tail) -> Self::Output {
ChildChoice::Tail(Rest::append_tail(tail))
}
}
impl<Parent: Behavior> ChildOccurrence<Parent> for ChildHead {
type Resolution = StructuralChildOccurrence<Self>;
}
impl<Parent: Behavior, Position> ChildOccurrence<Parent> for ChildTail<Position> {
type Resolution = StructuralChildOccurrence<Self>;
}
#[doc(hidden)]
pub trait ChildOccurrenceResolution<Parent: Behavior, Occurrence>:
sealed::ChildOccurrenceDescriptor + sealed::OccurrenceResolution<Parent, Occurrence>
{
}
impl<Parent, Occurrence> ChildOccurrenceResolution<Parent, Occurrence> for DeclaredChildOccurrence
where
Parent: Behavior,
Occurrence: ChildRole<Parent>,
{
}
impl<Parent: Behavior> ChildOccurrenceResolution<Parent, ChildHead>
for StructuralChildOccurrence<ChildHead>
{
}
impl<Parent: Behavior, Position> ChildOccurrenceResolution<Parent, ChildTail<Position>>
for StructuralChildOccurrence<ChildTail<Position>>
{
}
#[doc(hidden)]
pub trait ResolveChildOccurrenceDescriptor<Emitter: Behavior, Occurrence>:
sealed::ChildOccurrenceDescriptor + sealed::ResolveDescriptor<Emitter, Occurrence>
{
type Child: Behavior;
type Position: ChildPosition<<Emitter::Birth as BirthMode>::Child, Self::Child>;
}
impl<Emitter, Occurrence, Position> ResolveChildOccurrenceDescriptor<Emitter, Occurrence>
for StructuralChildOccurrence<Position>
where
Emitter: Behavior,
<Emitter::Birth as BirthMode>::Child: BirthNodeAt<Position>,
Position: ChildPosition<
<Emitter::Birth as BirthMode>::Child,
<<Emitter::Birth as BirthMode>::Child as BirthNodeAt<Position>>::Child,
>,
{
type Child = <<Emitter::Birth as BirthMode>::Child as BirthNodeAt<Position>>::Child;
type Position = Position;
}
impl<Emitter, Occurrence> ResolveChildOccurrenceDescriptor<Emitter, Occurrence>
for DeclaredChildOccurrence
where
Emitter:
Behavior<Protocol = <<Emitter as BehaviorBase>::Base as Behavior>::Protocol> + BehaviorBase,
Emitter::Base: Behavior,
Occurrence: ChildRole<Emitter::Base>,
<Emitter::Birth as BirthMode>::Child:
BirthNodeAt<Occurrence::Position, Child = Occurrence::Child>,
Occurrence::Position: ChildPosition<<Emitter::Birth as BirthMode>::Child, Occurrence::Child>,
{
type Child = Occurrence::Child;
type Position = Occurrence::Position;
}
#[doc(hidden)]
pub trait BirthNodeAt<Position>: sealed::BirthNode {
type Child: Behavior;
}
impl<Child: Behavior> BirthNodeAt<ChildHead> for Child {
type Child = Child;
}
impl<Head: Behavior, Tail> BirthNodeAt<ChildHead> for ChildChoice<Head, Tail>
where
Tail: sealed::BirthNode,
{
type Child = Head;
}
impl<Head, Tail, Position> BirthNodeAt<ChildTail<Position>> for ChildChoice<Head, Tail>
where
Head: Behavior,
Tail: BirthNodeAt<Position>,
{
type Child = <Tail as BirthNodeAt<Position>>::Child;
}
pub trait ChildOccurrenceShape {
type Empty;
type Member<Occurrence, Child: Behavior, Tail>;
}
pub trait ChildOccurrenceProduct<Shape>: sealed::BirthNode
where
Shape: ChildOccurrenceShape,
{
type Product;
}
#[doc(hidden)]
pub trait ChildOccurrenceProductAt<Occurrence, Shape>: sealed::BirthNode
where
Shape: ChildOccurrenceShape,
{
type Product;
}
impl<Node, Shape> ChildOccurrenceProduct<Shape> for Node
where
Node: ChildOccurrenceProductAt<ChildHead, Shape>,
Shape: ChildOccurrenceShape,
{
type Product = <Node as ChildOccurrenceProductAt<ChildHead, Shape>>::Product;
}
impl<Occurrence, Shape, Child> ChildOccurrenceProductAt<Occurrence, Shape> for Child
where
Shape: ChildOccurrenceShape,
Child: Behavior,
{
type Product = Shape::Member<Occurrence, Child, Shape::Empty>;
}
impl<Occurrence, Shape, Head, Tail> ChildOccurrenceProductAt<Occurrence, Shape>
for ChildChoice<Head, Tail>
where
Shape: ChildOccurrenceShape,
Head: Behavior,
Tail: ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>,
{
type Product = Shape::Member<
Occurrence,
Head,
<Tail as ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>>::Product,
>;
}
impl<Occurrence, Shape> ChildOccurrenceProductAt<Occurrence, Shape> for Never
where
Shape: ChildOccurrenceShape,
{
type Product = Shape::Empty;
}
pub type ChildOccurrences<Node, Shape> = <Node as ChildOccurrenceProduct<Shape>>::Product;
mod sealed {
use super::{
Behavior, BehaviorBase, BirthMode, BirthNodeAt, ChildChoice, ChildHead, ChildOccurrence,
ChildRole, ChildTail, DeclaredChildOccurrence, Never, ResolveChildOccurrenceDescriptor,
StructuralChildOccurrence,
};
pub trait BirthNode {}
pub trait NonEmptyBirthNode: BirthNode {}
impl<Child: Behavior> BirthNode for Child {}
impl<Child: Behavior> NonEmptyBirthNode for Child {}
impl<Head, Tail> BirthNode for ChildChoice<Head, Tail>
where
Head: Behavior,
Tail: BirthNode,
{
}
impl<Head, Tail> NonEmptyBirthNode for ChildChoice<Head, Tail>
where
Head: Behavior,
Tail: BirthNode,
{
}
impl BirthNode for Never {}
pub trait ChildPosition {}
pub trait ChildProduct {}
pub trait ChildOccurrenceDescriptor {}
impl ChildOccurrenceDescriptor for DeclaredChildOccurrence {}
impl<Position> ChildOccurrenceDescriptor for StructuralChildOccurrence<Position> {}
pub trait OccurrenceResolution<Parent: Behavior, Occurrence> {}
impl<Parent, Occurrence> OccurrenceResolution<Parent, Occurrence> for DeclaredChildOccurrence
where
Parent: Behavior,
Occurrence: ChildRole<Parent>,
{
}
impl<Parent: Behavior> OccurrenceResolution<Parent, ChildHead>
for StructuralChildOccurrence<ChildHead>
{
}
impl<Parent: Behavior, Position> OccurrenceResolution<Parent, ChildTail<Position>>
for StructuralChildOccurrence<ChildTail<Position>>
{
}
pub trait ResolveDescriptor<Emitter: Behavior, Occurrence> {}
impl<Emitter, Occurrence, Position> ResolveDescriptor<Emitter, Occurrence>
for StructuralChildOccurrence<Position>
where
Emitter: Behavior,
<Emitter::Birth as BirthMode>::Child: BirthNodeAt<Position>,
{
}
impl<Emitter, Occurrence> ResolveDescriptor<Emitter, Occurrence> for DeclaredChildOccurrence
where
Emitter: Behavior<Protocol = <<Emitter as BehaviorBase>::Base as Behavior>::Protocol>
+ BehaviorBase,
Emitter::Base: Behavior,
Occurrence: ChildRole<Emitter::Base>,
<Emitter::Birth as BirthMode>::Child:
BirthNodeAt<Occurrence::Position, Child = Occurrence::Child>,
Occurrence::Position:
super::ChildPosition<<Emitter::Birth as BirthMode>::Child, Occurrence::Child>,
{
}
pub trait ResolveChildOccurrence<Occurrence> {}
impl<Emitter, Occurrence> ResolveChildOccurrence<Occurrence> for Emitter
where
Emitter: Behavior + BehaviorBase,
Emitter::Base: Behavior,
Occurrence: ChildOccurrence<Emitter::Base>,
Occurrence::Resolution: ResolveChildOccurrenceDescriptor<Emitter, Occurrence>,
{
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct NoChildren;
impl sealed::ChildProduct for NoChildren {}
pub struct ChildCons<A: Address, C, Earlier> {
creation: CreateChild<A, C>,
earlier: Earlier,
}
impl<A: Address, C, Earlier> sealed::ChildProduct for ChildCons<A, C, Earlier> {}
pub struct Children<A: Address, Product = NoChildren> {
product: Product,
address: PhantomData<fn() -> A>,
}
pub trait ChildProduct<A: Address>: sealed::ChildProduct + Sized {
type Choice: BirthNodeAppend<Never>;
#[doc(hidden)]
fn stage(self) -> Vec<CreateChild<A, Self::Choice>>;
}
impl<A: Address> ChildProduct<A> for NoChildren {
type Choice = Never;
fn stage(self) -> Vec<CreateChild<A, Self::Choice>> {
Vec::new()
}
}
impl<A, C, Earlier> ChildProduct<A> for ChildCons<A, C, Earlier>
where
A: Address,
C: Behavior,
C::Protocol: Protocol<Addr = A>,
Earlier: ChildProduct<A>,
{
type Choice = ChildChoice<C, Earlier::Choice>;
fn stage(self) -> Vec<CreateChild<A, Self::Choice>> {
let earlier = self.earlier.stage();
let mut creates = earlier
.into_iter()
.map(|creation| {
let (id, child, kind) = creation.into_parts();
CreateChild::from_parts(id, ChildChoice::Tail(child), kind)
})
.collect::<Vec<_>>();
let (id, child, kind) = self.creation.into_parts();
creates.push(CreateChild::from_parts(id, ChildChoice::Head(child), kind));
creates
}
}
impl<A: Address> Children<A, NoChildren> {
#[must_use]
pub const fn new() -> Self {
Self {
product: NoChildren,
address: PhantomData,
}
}
}
impl<A: Address> Default for Children<A, NoChildren> {
fn default() -> Self {
Self::new()
}
}
impl<A: Address, Product> Children<A, Product> {
#[must_use]
pub fn create<C>(self, creation: CreateChild<A, C>) -> Children<A, ChildCons<A, C, Product>>
where
C: Behavior,
C::Protocol: Protocol<Addr = A>,
{
Children {
product: ChildCons {
creation,
earlier: self.product,
},
address: PhantomData,
}
}
#[must_use]
pub fn child<C>(self, id: CreationId, child: C) -> Children<A, ChildCons<A, C, Product>>
where
C: Behavior,
C::Protocol: Protocol<Addr = A>,
{
self.create(CreateChild::birth(id, child))
}
}
impl<A, Product> Children<A, Product>
where
A: Address,
Product: ChildProduct<A>,
{
#[must_use]
pub fn into_creates(self) -> Creations<CreateChild<A, Product::Choice>> {
Creations::from_items(self.product.stage())
}
}
impl<A, Occurrence, Head, Tail> ChildCreationProduct<A, Occurrence> for ChildChoice<Head, Tail>
where
A: EndpointAddress,
Head: Behavior,
Head::Protocol: Protocol<Addr = A>,
Tail: ChildCreationProduct<A, ChildTail<Occurrence>>,
{
type Result = ChildChoice<
ChildCreationOutcome<Head, Occurrence>,
<Tail as ChildCreationProduct<A, ChildTail<Occurrence>>>::Result,
>;
}
impl<A, Occurrence, Head, Tail, Host> CreateSelectedChild<A, Occurrence, Host>
for ChildChoice<Head, Tail>
where
A: EndpointAddress,
A::Nonce: Send,
Head: Behavior + Send,
Head::Protocol: Protocol<Addr = A>,
Tail: CreateSelectedChild<A, ChildTail<Occurrence>, Host> + Send,
Host: EstablishChild<Occurrence, Head> + Send,
{
async fn dispatch_birth_at(
self,
id: CreationId,
route: A::Nonce,
kind: CreationKind,
host: &mut Host,
) -> ItemSettlement<
RoutedCreation<A, Self>,
<Self as ChildCreationProduct<A, Occurrence>>::Result,
CreationRejection,
Never,
> {
match self {
Self::Head(child) => {
let creation = RoutedCreation::new(CreateChild::from_parts(id, child, kind), route);
match host.establish_child(creation).await {
ItemSettlement::Accepted(receipt) => {
ItemSettlement::Accepted(ChildChoice::Head(receipt))
}
ItemSettlement::Rejected { item, reason } => {
let (creation, route) = item.into_parts();
let (id, child, kind) = creation.into_parts();
ItemSettlement::Rejected {
item: RoutedCreation::new(
CreateChild::from_parts(id, Self::Head(child), kind),
route,
),
reason,
}
}
ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
ItemSettlement::Corrupt { item, fault } => {
let (creation, route) = item.into_parts();
let (id, child, kind) = creation.into_parts();
ItemSettlement::Corrupt {
item: RoutedCreation::new(
CreateChild::from_parts(id, Self::Head(child), kind),
route,
),
fault,
}
}
}
}
Self::Tail(tail) => match tail.dispatch_birth_at(id, route, kind, host).await {
ItemSettlement::Accepted(receipt) => {
ItemSettlement::Accepted(ChildChoice::Tail(receipt))
}
ItemSettlement::Rejected { item, reason } => {
let (creation, route) = item.into_parts();
let (id, child, kind) = creation.into_parts();
ItemSettlement::Rejected {
item: RoutedCreation::new(
CreateChild::from_parts(id, Self::Tail(child), kind),
route,
),
reason,
}
}
ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
ItemSettlement::Corrupt { item, fault } => {
let (creation, route) = item.into_parts();
let (id, child, kind) = creation.into_parts();
ItemSettlement::Corrupt {
item: RoutedCreation::new(
CreateChild::from_parts(id, Self::Tail(child), kind),
route,
),
fault,
}
}
},
}
}
}
impl<A, Occurrence> ChildCreationProduct<A, Occurrence> for Never
where
A: Address,
{
type Result = Never;
}
impl<A, Occurrence, Host> CreateSelectedChild<A, Occurrence, Host> for Never
where
A: Address,
{
fn dispatch_birth_at(
self,
_id: CreationId,
_route: A::Nonce,
_kind: CreationKind,
_host: &mut Host,
) -> impl Future<
Output = ItemSettlement<
RoutedCreation<A, Self>,
<Self as ChildCreationProduct<A, Occurrence>>::Result,
CreationRejection,
Never,
>,
> + Send {
async move { match self {} }
}
}
impl<A, Occurrence, C> ChildCreationProduct<A, Occurrence> for C
where
A: EndpointAddress,
C: Behavior,
C::Protocol: Protocol<Addr = A>,
{
type Result = ChildCreationOutcome<C, Occurrence>;
}
impl<A, Occurrence, C, Host> CreateSelectedChild<A, Occurrence, Host> for C
where
A: EndpointAddress,
C: Behavior,
C::Protocol: Protocol<Addr = A>,
Host: EstablishChild<Occurrence, C>,
{
fn dispatch_birth_at(
self,
id: CreationId,
route: A::Nonce,
kind: CreationKind,
host: &mut Host,
) -> impl Future<
Output = ItemSettlement<
RoutedCreation<A, Self>,
<Self as ChildCreationProduct<A, Occurrence>>::Result,
CreationRejection,
Never,
>,
> + Send {
host.establish_child(RoutedCreation::new(
CreateChild::from_parts(id, self, kind),
route,
))
}
}
pub trait BirthMode {
type Child;
}
pub struct NoBirthProtocols;
pub struct BirthProtocol<P: Protocol, Tail> {
protocol: PhantomData<fn() -> P>,
tail: PhantomData<fn() -> Tail>,
}
pub struct BirthProtocolHead;
pub struct BirthProtocolTail<Position>(PhantomData<fn() -> Position>);
pub trait BirthProtocolAt<P: Protocol, Position> {}
impl<P: Protocol, Tail> BirthProtocolAt<P, BirthProtocolHead> for BirthProtocol<P, Tail> {}
impl<Head, Tail, P, Position> BirthProtocolAt<P, BirthProtocolTail<Position>>
for BirthProtocol<Head, Tail>
where
Head: Protocol,
P: Protocol,
Tail: BirthProtocolAt<P, Position>,
{
}
#[doc(hidden)]
pub trait BirthProtocolProduct {
type Append<Tail: BirthProtocolProduct>: BirthProtocolProduct;
}
impl BirthProtocolProduct for NoBirthProtocols {
type Append<Tail: BirthProtocolProduct> = Tail;
}
impl<P, Rest> BirthProtocolProduct for BirthProtocol<P, Rest>
where
P: Protocol,
Rest: BirthProtocolProduct,
{
type Append<Tail: BirthProtocolProduct> = BirthProtocol<P, Rest::Append<Tail>>;
}
pub trait BirthProtocols: Behavior {
type Protocols: BirthProtocolProduct;
}
impl<B> BirthProtocols for B
where
B: Behavior,
B::Birth: BirthModeProtocols,
{
type Protocols = BirthProtocol<B::Protocol, <B::Birth as BirthModeProtocols>::Protocols>;
}
#[doc(hidden)]
pub trait BirthModeProtocols {
type Protocols: BirthProtocolProduct;
}
impl<M> BirthModeProtocols for M
where
M: BirthMode,
M::Child: BirthNodeProtocols,
{
type Protocols = <M::Child as BirthNodeProtocols>::Protocols;
}
#[doc(hidden)]
pub trait BirthNodeProtocols {
type Protocols: BirthProtocolProduct;
}
impl<B> BirthNodeProtocols for B
where
B: BirthProtocols,
{
type Protocols = B::Protocols;
}
impl<Head, Tail> BirthNodeProtocols for ChildChoice<Head, Tail>
where
Head: BirthNodeProtocols,
Tail: BirthNodeProtocols,
{
type Protocols = <Head::Protocols as BirthProtocolProduct>::Append<Tail::Protocols>;
}
impl BirthNodeProtocols for Never {
type Protocols = NoBirthProtocols;
}
#[doc(hidden)]
pub trait BirthNodeLogicalHosts {
type LogicalHosts: BirthProtocolProduct;
}
impl<B> BirthNodeLogicalHosts for B
where
B: crate::LogicalHostRequirements,
{
type LogicalHosts = B::LogicalHosts;
}
impl<Head, Tail> BirthNodeLogicalHosts for ChildChoice<Head, Tail>
where
Head: BirthNodeLogicalHosts,
Tail: BirthNodeLogicalHosts,
{
type LogicalHosts = <Head::LogicalHosts as BirthProtocolProduct>::Append<Tail::LogicalHosts>;
}
impl BirthNodeLogicalHosts for Never {
type LogicalHosts = NoBirthProtocols;
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct NoBirths;
impl BirthMode for NoBirths {
type Child = Never;
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Births<C>(PhantomData<fn() -> C>);
impl<C> BirthMode for Births<C> {
type Child = C;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Actions, BehaviorActed, NoBirths, User};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct TestAddr(u64);
impl Address for TestAddr {
type Nonce = u64;
}
struct TestEndpoint<P>(PhantomData<fn() -> P>);
impl<P> Clone for TestEndpoint<P> {
fn clone(&self) -> Self {
*self
}
}
impl<P> Copy for TestEndpoint<P> {}
impl EndpointAddress for TestAddr {
type Established<P>
= TestEndpoint<P>
where
P: Protocol<Addr = Self>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Child;
struct SharedProtocol;
impl behavior::Protocol for SharedProtocol {
type Addr = TestAddr;
type Msg = u8;
}
struct Primary;
struct Fallback;
macro_rules! shared_protocol_behavior {
($behavior:ty, $birth:ty) => {
impl Behavior for $behavior {
type Protocol = SharedProtocol;
type Event = User<TestAddr, u8>;
type Sends = Vec<Never>;
type Ph = Never;
type Error = Never;
type Birth = $birth;
fn transition(
&mut self,
_: crate::ActiveTurn,
_: Self::Event,
) -> BehaviorActed<Self> {
Ok(Actions::cont())
}
}
};
}
shared_protocol_behavior!(Primary, Births<Child>);
shared_protocol_behavior!(Fallback, NoBirths);
impl behavior::Protocol for Child {
type Addr = TestAddr;
type Msg = u8;
}
impl Behavior for Child {
type Protocol = Self;
type Event = User<TestAddr, u8>;
type Sends = Vec<Never>;
type Ph = Never;
type Error = Never;
type Birth = NoBirths;
fn transition(&mut self, _: crate::ActiveTurn, _: Self::Event) -> BehaviorActed<Self> {
Ok(Actions::cont())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ChildPlan {
CreateChild,
RejectBeforeTransfer,
}
struct RecordingHost {
calls: usize,
observed: Vec<(CreationId, u64, CreationKind)>,
plan: ChildPlan,
}
#[derive(Debug, PartialEq, Eq)]
enum SharedCreation {
Primary(CreationId, u64),
Fallback(CreationId, u64),
}
#[derive(Default)]
struct SharedProtocolHost(Vec<SharedCreation>);
impl EstablishChild<ChildHead, Primary> for SharedProtocolHost {
async fn establish_child(
&mut self,
creation: RoutedCreation<TestAddr, Primary>,
) -> ItemSettlement<
RoutedCreation<TestAddr, Primary>,
ChildCreationOutcome<Primary, ChildHead>,
CreationRejection,
Never,
> {
let id = creation.id();
let kind = creation.kind();
let route = creation.route();
let (creation, _) = creation.into_parts();
let (_, _child, _) = creation.into_parts();
self.0.push(SharedCreation::Primary(id, route));
ItemSettlement::Accepted(ChildCreationOutcome::Established {
established: EstablishedCreation::installed(
id,
kind,
EstablishedRecipient::issued(TestEndpoint(PhantomData)),
),
})
}
}
impl EstablishChild<ChildTail<ChildHead>, Fallback> for SharedProtocolHost {
async fn establish_child(
&mut self,
creation: RoutedCreation<TestAddr, Fallback>,
) -> ItemSettlement<
RoutedCreation<TestAddr, Fallback>,
ChildCreationOutcome<Fallback, ChildTail<ChildHead>>,
CreationRejection,
Never,
> {
let id = creation.id();
let kind = creation.kind();
let route = creation.route();
let (creation, _) = creation.into_parts();
let (_, _child, _) = creation.into_parts();
self.0.push(SharedCreation::Fallback(id, route));
ItemSettlement::Accepted(ChildCreationOutcome::Established {
established: EstablishedCreation::installed(
id,
kind,
EstablishedRecipient::issued(TestEndpoint(PhantomData)),
),
})
}
}
impl EstablishChild<ChildHead, Child> for RecordingHost {
async fn establish_child(
&mut self,
creation: RoutedCreation<TestAddr, Child>,
) -> ItemSettlement<
RoutedCreation<TestAddr, Child>,
ChildCreationOutcome<Child, ChildHead>,
CreationRejection,
Never,
> {
self.calls += 1;
self.observed
.push((creation.id(), creation.route(), creation.kind()));
match self.plan {
ChildPlan::CreateChild => {
let id = creation.id();
let kind = creation.kind();
let (creation, _) = creation.into_parts();
let (_, _child, _) = creation.into_parts();
ItemSettlement::Accepted(ChildCreationOutcome::Established {
established: EstablishedCreation::installed(
id,
kind,
EstablishedRecipient::issued(TestEndpoint(PhantomData)),
),
})
}
ChildPlan::RejectBeforeTransfer => ItemSettlement::Rejected {
item: creation,
reason: CreationRejection::EnvironmentFailed,
},
}
}
}
fn host(plan: ChildPlan) -> RecordingHost {
RecordingHost {
calls: 0,
observed: Vec::new(),
plan,
}
}
fn assert_send<T: Send>(_: &T) {}
#[test]
fn empty_child_product_stages_no_creations() {
let creations = <NoChildren as ChildProduct<TestAddr>>::stage(NoChildren);
assert!(creations.is_empty());
}
#[test]
fn creation_values_preserve_ids_order_and_debug_identity() {
let mut sequence = CreationSequence::new();
let first = sequence.issue().expect("the first creation ID exists");
let second = sequence.issue().expect("the second creation ID exists");
assert_eq!(first.get(), 1);
assert_eq!(second.get(), 2);
let first_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(first);
let same_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(first);
let second_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(second);
assert_eq!(first_correlation, same_correlation);
assert_ne!(first_correlation, second_correlation);
assert_eq!(
format!("{first_correlation:?}"),
"CreationCorrelation(CreationId(1))"
);
let mut creations = Creations::one(1_u8);
creations.extend([2, 3]);
assert_eq!(creations.len(), 3);
assert!(!creations.is_empty());
assert_eq!(creations.iter().copied().collect::<Vec<_>>(), [1, 2, 3]);
assert_eq!(
(&creations).into_iter().copied().collect::<Vec<_>>(),
[1, 2, 3]
);
let collected: Creations<_> = [4_u8, 5].into_iter().collect();
assert_eq!(collected.len(), 2);
assert_eq!(collected.into_iter().collect::<Vec<_>>(), [4, 5]);
let returned = ChildCreationSettled::<Child, ChildHead>::new(SettledItem::Unattempted(
RoutedCreation::new(CreateChild::birth(first, Child), 17),
));
assert_eq!(format!("{returned:?}"), "ChildCreationSettled { .. }");
}
#[tokio::test]
async fn concrete_child_dispatches_once_with_exact_creation_and_route() {
let mut sequence = CreationSequence::new();
let previous = sequence.issue().expect("the previous ID exists");
let id = sequence.issue().expect("the replacement ID exists");
let mut host = host(ChildPlan::CreateChild);
let kind = CreationKind::replacement(previous);
let future = Child.dispatch_birth(id, 17, kind, &mut host);
assert_send(&future);
let result = future.await;
let ItemSettlement::Accepted(ChildCreationOutcome::Established { established }) = result
else {
panic!("expected the child to be created");
};
assert_eq!(established.id(), id);
assert_eq!(host.calls, 1);
assert_eq!(host.observed, [(id, 17, kind)]);
}
#[tokio::test]
async fn concrete_child_returns_the_exact_rejected_creation_without_retry() {
let mut sequence = CreationSequence::new();
let previous = sequence.issue().expect("the previous ID exists");
let id = sequence.issue().expect("the replacement ID exists");
let mut host = host(ChildPlan::RejectBeforeTransfer);
let kind = CreationKind::replacement(previous);
let future = Child.dispatch_birth(id, 23, kind, &mut host);
assert_send(&future);
let result = future.await;
let ItemSettlement::Rejected { item, reason } = result else {
panic!("expected refusal before child ownership transfer");
};
assert_eq!(
item,
RoutedCreation::new(CreateChild::replacement(id, previous, Child), 23)
);
assert_eq!(reason, CreationRejection::EnvironmentFailed);
assert_eq!(host.calls, 1);
assert_eq!(host.observed, [(id, 23, kind)]);
}
#[tokio::test]
async fn distinct_child_alternatives_preserve_one_canonical_protocol_identity() {
type Alternatives = ChildChoice<Primary, ChildChoice<Fallback, Never>>;
fn requires_shared_protocol<C: Behavior<Protocol = SharedProtocol>>() {}
requires_shared_protocol::<Primary>();
requires_shared_protocol::<Fallback>();
let mut sequence = CreationSequence::new();
let primary_id = sequence.issue().expect("the primary ID exists");
let fallback_id = sequence.issue().expect("the fallback ID exists");
let mut host = SharedProtocolHost::default();
let primary = Alternatives::Head(Primary)
.dispatch_birth(primary_id, 11, CreationKind::Birth, &mut host)
.await;
let fallback = Alternatives::Tail(ChildChoice::Head(Fallback))
.dispatch_birth(fallback_id, 17, CreationKind::Birth, &mut host)
.await;
let ItemSettlement::Accepted(ChildChoice::Head(ChildCreationOutcome::Established {
established: primary,
})) = primary
else {
panic!("expected the primary child result");
};
assert_eq!(primary.id(), primary_id);
let ItemSettlement::Accepted(ChildChoice::Tail(ChildChoice::Head(
ChildCreationOutcome::Established {
established: fallback,
},
))) = fallback
else {
panic!("expected the fallback child result");
};
assert_eq!(fallback.id(), fallback_id);
assert_eq!(
host.0,
[
SharedCreation::Primary(primary_id, 11),
SharedCreation::Fallback(fallback_id, 17),
]
);
}
#[test]
fn birth_protocol_projection_recurses_without_inspecting_send_lanes() {
type Protocols = <Primary as BirthProtocols>::Protocols;
type Expected = BirthProtocol<SharedProtocol, BirthProtocol<Child, NoBirthProtocols>>;
trait Same<T> {}
impl<T> Same<T> for T {}
fn exact<T: Same<Expected>>() {}
exact::<Protocols>();
}
}