use super::operation_event::{
AttachedOperation, BindingFateOperation, ConversationOperation, DetachedOperation,
EnrolledOperation, LeftOperation, NonzeroDebtAckOperation,
};
use super::{
AttachCommit, CommittedDetachTransition, ConversationCommit, ConversationDecision,
ConversationEvent, ConversationRefusal, ConversationRefusalReason, EnrollmentCommit,
IdentityState, LeaveCommit, NonzeroParticipantAckCommit, OrdinaryBindingFate,
ParticipantConversation, RecoveredBindingFate,
};
use alloc::boxed::Box;
#[derive(Debug, PartialEq, Eq)]
pub struct AggregateOperationCommit<T> {
shell: ConversationCommit,
operation: T,
}
impl<T> AggregateOperationCommit<T> {
#[must_use]
pub const fn event(&self) -> &ConversationEvent {
self.shell.event()
}
#[must_use]
pub fn commit(self) -> (ParticipantConversation, T) {
(self.shell.commit(), self.operation)
}
#[must_use]
pub fn abort(self) -> (ParticipantConversation, T) {
(self.shell.abort(), self.operation)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct AggregateOperationRefusal<T> {
refusal: ConversationRefusal,
operation: T,
}
impl<T> AggregateOperationRefusal<T> {
#[must_use]
pub const fn reason(&self) -> ConversationRefusalReason {
self.refusal.reason()
}
#[must_use]
pub fn into_parts(self) -> (ParticipantConversation, T) {
(self.refusal.into_conversation(), self.operation)
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum AggregateOperationDecision<T> {
Commit(AggregateOperationCommit<T>),
Refused(AggregateOperationRefusal<T>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AggregateOperationFaultReason {
DetachTerminalCellMismatch,
LeaveIdentityNotRetired,
}
#[derive(Debug, PartialEq, Eq)]
pub struct AggregateOperationFault<T> {
shell: ParticipantConversation,
operation: T,
reason: AggregateOperationFaultReason,
}
impl<T> AggregateOperationFault<T> {
#[must_use]
pub const fn reason(&self) -> AggregateOperationFaultReason {
self.reason
}
#[must_use]
pub fn into_parts(self) -> (ParticipantConversation, T) {
(self.shell, self.operation)
}
}
pub type AggregateOperationResult<T> =
Result<AggregateOperationDecision<T>, Box<AggregateOperationFault<T>>>;
const fn decide<T>(
conversation: ParticipantConversation,
operation: ConversationOperation,
payload: T,
) -> AggregateOperationDecision<T> {
match conversation.decide_operation(operation) {
ConversationDecision::Commit(shell) => {
AggregateOperationDecision::Commit(AggregateOperationCommit {
shell,
operation: payload,
})
}
ConversationDecision::Refused(refusal) => {
AggregateOperationDecision::Refused(AggregateOperationRefusal {
refusal,
operation: payload,
})
}
}
}
#[must_use]
pub const fn decide_enrolled_operation<F>(
conversation: ParticipantConversation,
commit: EnrollmentCommit<F>,
) -> AggregateOperationDecision<EnrollmentCommit<F>> {
let body = EnrolledOperation::new(&commit);
decide(conversation, ConversationOperation::Enrolled(body), commit)
}
#[must_use]
pub const fn decide_attached_operation<F, V>(
conversation: ParticipantConversation,
commit: AttachCommit<F, V>,
) -> AggregateOperationDecision<AttachCommit<F, V>> {
let body = AttachedOperation::new(&commit);
decide(conversation, ConversationOperation::Attached(body), commit)
}
pub fn decide_detached_operation<EF, V>(
conversation: ParticipantConversation,
transition: CommittedDetachTransition<EF, V>,
) -> AggregateOperationResult<CommittedDetachTransition<EF, V>> {
let Some(body) = DetachedOperation::new(&transition) else {
return Err(Box::new(AggregateOperationFault {
shell: conversation,
operation: transition,
reason: AggregateOperationFaultReason::DetachTerminalCellMismatch,
}));
};
Ok(decide(
conversation,
ConversationOperation::Detached(body),
transition,
))
}
pub fn decide_left_operation<EF, V, LF>(
conversation: ParticipantConversation,
commit: LeaveCommit<EF, V, LF>,
) -> AggregateOperationResult<LeaveCommit<EF, V, LF>> {
let body = match commit.identity() {
IdentityState::Retired(retired) => LeftOperation::new(retired),
IdentityState::Live(_) => {
return Err(Box::new(AggregateOperationFault {
shell: conversation,
operation: commit,
reason: AggregateOperationFaultReason::LeaveIdentityNotRetired,
}));
}
};
Ok(decide(
conversation,
ConversationOperation::Left(body),
commit,
))
}
#[must_use]
pub const fn decide_ordinary_binding_fate_operation(
conversation: ParticipantConversation,
fate: OrdinaryBindingFate,
) -> AggregateOperationDecision<OrdinaryBindingFate> {
let body = BindingFateOperation::from_ordinary(&fate);
decide(conversation, ConversationOperation::BindingFate(body), fate)
}
#[must_use]
pub const fn decide_recovered_binding_fate_operation(
conversation: ParticipantConversation,
fate: RecoveredBindingFate,
) -> AggregateOperationDecision<RecoveredBindingFate> {
let body = BindingFateOperation::from_recovered(&fate);
decide(conversation, ConversationOperation::BindingFate(body), fate)
}
#[must_use]
pub fn decide_nonzero_debt_ack_operation(
conversation: ParticipantConversation,
commit: Box<NonzeroParticipantAckCommit>,
) -> AggregateOperationDecision<Box<NonzeroParticipantAckCommit>> {
let body = NonzeroDebtAckOperation::new(&commit);
decide(
conversation,
ConversationOperation::NonzeroDebtAck(body),
commit,
)
}