use alloc::{boxed::Box, string::String, vec::Vec};
use crate::algebra::{ResourceDimension, ResourceVector};
use super::{
AckGapReason, AckRegressionReason, AttachAttemptToken, AttachEnvelope, AttachSecret,
AttemptConflict, BindingEpoch, ClientDiscriminant, ClosureCheckedEnvelope, ConversationId,
Counter, DecodeClass, DeliverySeq, DetachAttemptToken, DetachEnvelope, EnrollmentEnvelope,
EnrollmentToken, Generation, IdentityCapacityScope, InvalidObserverEpochListReason,
InvalidObserverEpochReason, LeaveAttemptToken, LeaveEnvelope, MarkerAckEnvelope,
MarkerClosureCapacityExceeded, MarkerMismatchReason, MarkerNotDeliveredReason, ObserverEpoch,
ParticipantAckEnvelope, ParticipantId, ProtocolVersion, ReceiptCapacityScope,
ReceiptExpiryReason, RecordAdmissionEnvelope, ResponseEnvelope, SequenceBudget,
ServerDiscriminant,
};
pub use super::tags::{DetachAuthorityStateTag, LeaveAuthorityStateTag, ResourceDimensionTag};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParticipantTransportRejected {
pub reason: TransportRejectionReason,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TransportRejectionReason {
FrameTooLarge {
complete_frame_bytes: u64,
max_frame_bytes: u64,
},
DecodeFailed {
decode_class: DecodeClass,
},
UnsupportedVersion {
presented_version: ProtocolVersion,
supported_version: ProtocolVersion,
},
AuthenticationFailed,
ParticipantCapabilityRequired,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AttemptTokenBodyConflict {
CredentialAttach {
token: AttachAttemptToken,
conversation_id: ConversationId,
presented_participant_id: ParticipantId,
presented_generation: Generation,
presented_marker_delivery_seq: Option<DeliverySeq>,
conflict: AttemptConflict,
},
Leave {
token: LeaveAttemptToken,
conversation_id: ConversationId,
presented_participant_id: ParticipantId,
presented_generation: Generation,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConnectionConversationCapacityExceeded {
SemanticRequest {
request: ResponseEnvelope,
limit: u64,
},
ObserverRecovery {
conversation_id: ConversationId,
limit: u64,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConnectionConversationBindingOccupied {
Enrollment {
conversation_id: ConversationId,
enrollment_token: EnrollmentToken,
},
CredentialAttach {
conversation_id: ConversationId,
participant_id: ParticipantId,
capability_generation: Generation,
attach_attempt_token: AttachAttemptToken,
accept_marker_delivery_seq: Option<DeliverySeq>,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OrderAllocatingEnvelope {
Enrollment(EnrollmentEnvelope),
CredentialAttach(AttachEnvelope),
RecordAdmission(RecordAdmissionEnvelope),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ConversationOrderExhausted {
request: OrderAllocatingEnvelope,
high: u64,
order_remaining: u128,
reserved_claims: u128,
resulting_order_remaining: u128,
resulting_reserved_claims: u128,
}
impl ConversationOrderExhausted {
pub const REQUIRED_MAJORS: u64 = 1;
#[must_use]
pub const fn new(
request: OrderAllocatingEnvelope,
high: u64,
order_remaining: u128,
reserved_claims: u128,
resulting_order_remaining: u128,
resulting_reserved_claims: u128,
) -> Self {
Self {
request,
high,
order_remaining,
reserved_claims,
resulting_order_remaining,
resulting_reserved_claims,
}
}
#[must_use]
pub const fn request(&self) -> &OrderAllocatingEnvelope {
&self.request
}
#[must_use]
pub const fn counter(&self) -> Counter {
let _ = self;
Counter::TransactionOrder
}
#[must_use]
pub const fn high(&self) -> u64 {
self.high
}
#[must_use]
pub const fn next_value(&self) -> Option<u64> {
self.high.checked_add(1)
}
#[must_use]
pub const fn order_remaining(&self) -> u128 {
self.order_remaining
}
#[must_use]
pub const fn reserved_claims(&self) -> u128 {
self.reserved_claims
}
#[must_use]
pub const fn resulting_order_remaining(&self) -> u128 {
self.resulting_order_remaining
}
#[must_use]
pub const fn resulting_reserved_claims(&self) -> u128 {
self.resulting_reserved_claims
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ParticipantReferenceEnvelope {
CredentialAttach(AttachEnvelope),
Detach(DetachEnvelope),
ParticipantAck(ParticipantAckEnvelope),
Leave(LeaveEnvelope),
MarkerAck(MarkerAckEnvelope),
RecordAdmission(RecordAdmissionEnvelope),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BindingRequiredEnvelope {
Detach(DetachEnvelope),
ParticipantAck(ParticipantAckEnvelope),
Leave(LeaveEnvelope),
MarkerAck(MarkerAckEnvelope),
RecordAdmission(RecordAdmissionEnvelope),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParticipantUnknown {
pub request: ParticipantReferenceEnvelope,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NoBinding {
pub request: BindingRequiredEnvelope,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BindingStateView {
Bound {
current_binding_epoch: BindingEpoch,
},
Detached,
}
impl BindingStateView {
#[must_use]
pub const fn tag(self) -> super::BindingStateTag {
match self {
Self::Bound { .. } => super::BindingStateTag::Bound,
Self::Detached => super::BindingStateTag::Detached,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TerminalizedDetachCell {
conversation_id: ConversationId,
participant_id: ParticipantId,
capability_generation: Generation,
detach_attempt_token: DetachAttemptToken,
current_generation: Generation,
committed_binding_epoch: BindingEpoch,
binding_state: BindingStateView,
}
impl TerminalizedDetachCell {
pub(crate) const fn from_terminalized_state<V>(
state: &crate::lifecycle::TerminalizedDetach<V>,
conversation_id: ConversationId,
current_generation: Generation,
binding_state: BindingStateView,
) -> Self {
Self {
conversation_id,
participant_id: state.participant_id(),
capability_generation: state.request_generation(),
detach_attempt_token: state.token(),
current_generation,
committed_binding_epoch: state.committed_binding_epoch(),
binding_state,
}
}
#[allow(clippy::too_many_arguments)]
pub(super) const fn from_wire_decode(
_authority: super::server_codec::TerminalizedWireDecodeAuthority,
conversation_id: ConversationId,
participant_id: ParticipantId,
capability_generation: Generation,
detach_attempt_token: DetachAttemptToken,
current_generation: Generation,
committed_binding_epoch: BindingEpoch,
binding_state: BindingStateView,
) -> Self {
Self {
conversation_id,
participant_id,
capability_generation,
detach_attempt_token,
current_generation,
committed_binding_epoch,
binding_state,
}
}
#[cfg(test)]
pub(crate) const fn for_client_test(
conversation_id: ConversationId,
participant_id: ParticipantId,
capability_generation: Generation,
detach_attempt_token: DetachAttemptToken,
current_generation: Generation,
committed_binding_epoch: BindingEpoch,
binding_state: BindingStateView,
) -> Self {
Self {
conversation_id,
participant_id,
capability_generation,
detach_attempt_token,
current_generation,
committed_binding_epoch,
binding_state,
}
}
#[must_use]
pub const fn conversation_id(&self) -> ConversationId {
self.conversation_id
}
#[must_use]
pub const fn participant_id(&self) -> ParticipantId {
self.participant_id
}
#[must_use]
pub const fn capability_generation(&self) -> Generation {
self.capability_generation
}
#[must_use]
pub const fn detach_attempt_token(&self) -> DetachAttemptToken {
self.detach_attempt_token
}
#[must_use]
pub const fn current_generation(&self) -> Generation {
self.current_generation
}
#[must_use]
pub const fn committed_binding_epoch(&self) -> BindingEpoch {
self.committed_binding_epoch
}
#[must_use]
pub const fn binding_state(&self) -> BindingStateView {
self.binding_state
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DetachStaleAuthority {
Live {
conversation_id: ConversationId,
participant_id: ParticipantId,
capability_generation: Generation,
detach_attempt_token: DetachAttemptToken,
current_generation: Generation,
},
TerminalizedDetachCell(TerminalizedDetachCell),
}
impl DetachStaleAuthority {
#[must_use]
pub const fn authority_state_tag(&self) -> DetachAuthorityStateTag {
match self {
Self::Live { .. } => DetachAuthorityStateTag::Live,
Self::TerminalizedDetachCell(_) => DetachAuthorityStateTag::TerminalizedDetachCell,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LeaveStaleAuthority {
Live {
conversation_id: ConversationId,
participant_id: ParticipantId,
presented_generation: Generation,
leave_attempt_token: LeaveAttemptToken,
current_generation: Generation,
},
CommittedLeaveTombstone {
conversation_id: ConversationId,
participant_id: ParticipantId,
presented_generation: Generation,
leave_attempt_token: LeaveAttemptToken,
retired_generation: Generation,
},
}
impl LeaveStaleAuthority {
#[must_use]
pub const fn authority_state_tag(&self) -> LeaveAuthorityStateTag {
match self {
Self::Live { .. } => LeaveAuthorityStateTag::Live,
Self::CommittedLeaveTombstone { .. } => LeaveAuthorityStateTag::CommittedLeaveTombstone,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CommonStaleAuthorityEnvelope {
CredentialAttach(AttachEnvelope),
ParticipantAck(ParticipantAckEnvelope),
MarkerAck(MarkerAckEnvelope),
RecordAdmission(RecordAdmissionEnvelope),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StaleAuthority {
Live {
request: CommonStaleAuthorityEnvelope,
current_generation: Generation,
},
Detach(DetachStaleAuthority),
Leave(LeaveStaleAuthority),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Retired {
Enrollment {
request: EnrollmentEnvelope,
participant_id: ParticipantId,
retired_generation: Generation,
},
Participant {
request: ParticipantReferenceEnvelope,
retired_generation: Generation,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EnrollBound {
conversation_id: ConversationId,
token: EnrollmentToken,
participant_id: ParticipantId,
attach_secret: AttachSecret,
origin_binding_epoch: BindingEpoch,
receipt_expires_at: u128,
provenance_expires_at: u128,
}
impl EnrollBound {
#[must_use]
pub const fn new(
conversation_id: ConversationId,
token: EnrollmentToken,
participant_id: ParticipantId,
attach_secret: AttachSecret,
origin_binding_epoch: BindingEpoch,
receipt_expires_at: u128,
provenance_expires_at: u128,
) -> Option<Self> {
if origin_binding_epoch.capability_generation.get() == 1 {
Some(Self {
conversation_id,
token,
participant_id,
attach_secret,
origin_binding_epoch,
receipt_expires_at,
provenance_expires_at,
})
} else {
None
}
}
#[must_use]
pub const fn conversation_id(&self) -> ConversationId {
self.conversation_id
}
#[must_use]
pub const fn token(&self) -> EnrollmentToken {
self.token
}
#[must_use]
pub const fn participant_id(&self) -> ParticipantId {
self.participant_id
}
#[must_use]
pub const fn request_generation(&self) -> Option<Generation> {
None
}
#[must_use]
pub const fn capability_generation(&self) -> Generation {
self.origin_binding_epoch.capability_generation
}
#[must_use]
pub const fn attach_secret(&self) -> AttachSecret {
self.attach_secret
}
#[must_use]
pub const fn origin_binding_epoch(&self) -> BindingEpoch {
self.origin_binding_epoch
}
#[must_use]
pub const fn persisted_cursor(&self) -> DeliverySeq {
0
}
#[must_use]
pub const fn accepted_marker_delivery_seq(&self) -> Option<DeliverySeq> {
None
}
#[must_use]
pub const fn receipt_expires_at(&self) -> u128 {
self.receipt_expires_at
}
#[must_use]
pub const fn provenance_expires_at(&self) -> u128 {
self.provenance_expires_at
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EnrollmentKnown {
pub conversation_id: ConversationId,
pub token: EnrollmentToken,
pub participant_id: ParticipantId,
pub current_generation: Generation,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ReceiptExpired {
Enrollment {
conversation_id: ConversationId,
token: EnrollmentToken,
participant_id: ParticipantId,
result_generation: Generation,
current_generation: Generation,
reason: ReceiptExpiryReason,
},
CredentialAttach {
conversation_id: ConversationId,
token: AttachAttemptToken,
participant_id: ParticipantId,
presented_generation: Generation,
presented_marker_delivery_seq: Option<DeliverySeq>,
result_generation: Generation,
current_generation: Generation,
reason: ReceiptExpiryReason,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EnrollmentReceiptCapacityScope {
LiveReceiptServer,
ProvenanceServer,
ProvenanceConversation,
}
impl EnrollmentReceiptCapacityScope {
#[must_use]
pub const fn wire_scope(self) -> ReceiptCapacityScope {
match self {
Self::LiveReceiptServer => ReceiptCapacityScope::LiveReceiptServer,
Self::ProvenanceServer => ReceiptCapacityScope::ProvenanceServer,
Self::ProvenanceConversation => ReceiptCapacityScope::ProvenanceConversation,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ReceiptCapacityExceeded {
Enrollment {
request: EnrollmentEnvelope,
scope: EnrollmentReceiptCapacityScope,
limit: u64,
occupied: u64,
},
CredentialAttach {
request: AttachEnvelope,
scope: ReceiptCapacityScope,
limit: u64,
occupied: u64,
},
}
impl ReceiptCapacityExceeded {
pub const REQUESTED: u64 = 1;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IdentityCapacityExceeded {
pub request: EnrollmentEnvelope,
pub scope: IdentityCapacityScope,
pub limit: u64,
pub occupied: u64,
}
impl IdentityCapacityExceeded {
pub const REQUESTED: u64 = 1;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ObserverBackpressureState {
backpressure_epoch: ObserverEpoch,
observer_progress: DeliverySeq,
}
impl ObserverBackpressureState {
#[must_use]
pub const fn initial(observer_progress: DeliverySeq) -> Self {
Self {
backpressure_epoch: observer_progress,
observer_progress,
}
}
#[must_use]
pub const fn replay(
backpressure_epoch: ObserverEpoch,
observer_progress: DeliverySeq,
) -> Option<Self> {
if backpressure_epoch == observer_progress {
Some(Self {
backpressure_epoch,
observer_progress,
})
} else {
None
}
}
#[must_use]
pub const fn backpressure_epoch(self) -> ObserverEpoch {
self.backpressure_epoch
}
#[must_use]
pub const fn observer_progress(self) -> DeliverySeq {
self.observer_progress
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ObserverBackpressure {
Enrollment {
request: EnrollmentEnvelope,
state: ObserverBackpressureState,
},
CredentialAttach {
request: AttachEnvelope,
state: ObserverBackpressureState,
},
Detach {
request: DetachEnvelope,
committed_binding_epoch: BindingEpoch,
state: ObserverBackpressureState,
},
Leave {
request: LeaveEnvelope,
state: ObserverBackpressureState,
prior_terminal_cell_exists: bool,
},
RecordAdmission {
request: RecordAdmissionEnvelope,
state: ObserverBackpressureState,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SequenceAllocatingEnvelope {
Enrollment(EnrollmentEnvelope),
CredentialAttach(AttachEnvelope),
RecordAdmission(RecordAdmissionEnvelope),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ConversationSequenceExhausted {
pub request: SequenceAllocatingEnvelope,
pub sequence_budget: SequenceBudget,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AttachBound {
conversation_id: ConversationId,
token: AttachAttemptToken,
participant_id: ParticipantId,
request_generation: Generation,
attach_secret: AttachSecret,
origin_binding_epoch: BindingEpoch,
persisted_cursor: DeliverySeq,
accepted_marker_delivery_seq: Option<DeliverySeq>,
receipt_expires_at: u128,
provenance_expires_at: u128,
}
impl AttachBound {
#[must_use]
#[allow(clippy::too_many_arguments)]
pub const fn ordinary(
conversation_id: ConversationId,
token: AttachAttemptToken,
participant_id: ParticipantId,
request_generation: Generation,
attach_secret: AttachSecret,
origin_binding_epoch: BindingEpoch,
persisted_cursor: DeliverySeq,
receipt_expires_at: u128,
provenance_expires_at: u128,
) -> Option<Self> {
if !is_successor_generation(
request_generation,
origin_binding_epoch.capability_generation,
) {
return None;
}
Some(Self {
conversation_id,
token,
participant_id,
request_generation,
attach_secret,
origin_binding_epoch,
persisted_cursor,
accepted_marker_delivery_seq: None,
receipt_expires_at,
provenance_expires_at,
})
}
#[must_use]
#[allow(clippy::too_many_arguments)]
pub const fn fenced(
conversation_id: ConversationId,
token: AttachAttemptToken,
participant_id: ParticipantId,
request_generation: Generation,
attach_secret: AttachSecret,
origin_binding_epoch: BindingEpoch,
accepted_marker_delivery_seq: DeliverySeq,
receipt_expires_at: u128,
provenance_expires_at: u128,
) -> Option<Self> {
if !is_successor_generation(
request_generation,
origin_binding_epoch.capability_generation,
) {
return None;
}
Some(Self {
conversation_id,
token,
participant_id,
request_generation,
attach_secret,
origin_binding_epoch,
persisted_cursor: accepted_marker_delivery_seq,
accepted_marker_delivery_seq: Some(accepted_marker_delivery_seq),
receipt_expires_at,
provenance_expires_at,
})
}
#[must_use]
pub const fn conversation_id(&self) -> ConversationId {
self.conversation_id
}
#[must_use]
pub const fn token(&self) -> AttachAttemptToken {
self.token
}
#[must_use]
pub const fn participant_id(&self) -> ParticipantId {
self.participant_id
}
#[must_use]
pub const fn request_generation(&self) -> Generation {
self.request_generation
}
#[must_use]
pub const fn capability_generation(&self) -> Generation {
self.origin_binding_epoch.capability_generation
}
#[must_use]
pub const fn attach_secret(&self) -> AttachSecret {
self.attach_secret
}
#[must_use]
pub const fn origin_binding_epoch(&self) -> BindingEpoch {
self.origin_binding_epoch
}
#[must_use]
pub const fn persisted_cursor(&self) -> DeliverySeq {
self.persisted_cursor
}
#[must_use]
pub const fn accepted_marker_delivery_seq(&self) -> Option<DeliverySeq> {
self.accepted_marker_delivery_seq
}
#[must_use]
pub const fn receipt_expires_at(&self) -> u128 {
self.receipt_expires_at
}
#[must_use]
pub const fn provenance_expires_at(&self) -> u128 {
self.provenance_expires_at
}
}
const fn is_successor_generation(previous: Generation, successor: Generation) -> bool {
match previous.get().checked_add(1) {
Some(expected) => successor.get() == expected,
None => false,
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StaleOrUnknownReceipt {
pub conversation_id: ConversationId,
pub token: AttachAttemptToken,
pub participant_id: ParticipantId,
pub presented_generation: Generation,
pub presented_marker_delivery_seq: Option<DeliverySeq>,
pub current_generation: Generation,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AttachMarkerProof {
pub conversation_id: ConversationId,
pub token: AttachAttemptToken,
pub participant_id: ParticipantId,
pub capability_generation: Generation,
pub requested_marker_delivery_seq: DeliverySeq,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MarkerAckProof {
pub conversation_id: ConversationId,
pub participant_id: ParticipantId,
pub capability_generation: Generation,
pub requested_marker_delivery_seq: DeliverySeq,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MarkerProofRequest {
CredentialAttach(AttachMarkerProof),
MarkerAck(MarkerAckProof),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MarkerNotDelivered {
pub request: MarkerProofRequest,
pub reason: MarkerNotDeliveredReason,
pub expected_marker_delivery_seq: DeliverySeq,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MarkerMismatchBody {
BelowCursor {
current_cursor: DeliverySeq,
},
NoMarkerExpected,
ExpectedDifferentMarker {
expected_marker_delivery_seq: DeliverySeq,
},
}
impl MarkerMismatchBody {
#[must_use]
pub const fn reason(self) -> MarkerMismatchReason {
match self {
Self::BelowCursor { .. } => MarkerMismatchReason::BelowCursor,
Self::NoMarkerExpected => MarkerMismatchReason::NoMarkerExpected,
Self::ExpectedDifferentMarker { .. } => MarkerMismatchReason::ExpectedDifferentMarker,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MarkerMismatch {
pub request: MarkerProofRequest,
pub mismatch: MarkerMismatchBody,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ReceiptReplay {
Enrollment(EnrollBound),
CredentialAttach(AttachBound),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DetachCommitted {
conversation_id: ConversationId,
participant_id: ParticipantId,
detach_attempt_token: DetachAttemptToken,
committed_binding_epoch: BindingEpoch,
detached_delivery_seq: DeliverySeq,
}
impl DetachCommitted {
#[must_use]
pub const fn new(
conversation_id: ConversationId,
participant_id: ParticipantId,
detach_attempt_token: DetachAttemptToken,
committed_binding_epoch: BindingEpoch,
detached_delivery_seq: DeliverySeq,
) -> Self {
Self {
conversation_id,
participant_id,
detach_attempt_token,
committed_binding_epoch,
detached_delivery_seq,
}
}
#[must_use]
pub const fn conversation_id(&self) -> ConversationId {
self.conversation_id
}
#[must_use]
pub const fn participant_id(&self) -> ParticipantId {
self.participant_id
}
#[must_use]
pub const fn capability_generation(&self) -> Generation {
self.committed_binding_epoch.capability_generation
}
#[must_use]
pub const fn detach_attempt_token(&self) -> DetachAttemptToken {
self.detach_attempt_token
}
#[must_use]
pub const fn committed_binding_epoch(&self) -> BindingEpoch {
self.committed_binding_epoch
}
#[must_use]
pub const fn detached_delivery_seq(&self) -> DeliverySeq {
self.detached_delivery_seq
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DetachInProgress {
pub conversation_id: ConversationId,
pub participant_id: ParticipantId,
pub presented_token: DetachAttemptToken,
pub presented_generation: Generation,
pub committed_binding_epoch: BindingEpoch,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AckCommitted {
request: ParticipantAckEnvelope,
}
impl AckCommitted {
#[must_use]
pub const fn new(request: ParticipantAckEnvelope) -> Self {
Self { request }
}
#[must_use]
pub const fn request(&self) -> &ParticipantAckEnvelope {
&self.request
}
#[must_use]
pub const fn current_cursor(&self) -> DeliverySeq {
self.request.through_seq
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AckNoOp {
ParticipantAck(ParticipantAckEnvelope),
MarkerAck(MarkerAckEnvelope),
}
impl AckNoOp {
#[must_use]
pub const fn participant_ack(request: ParticipantAckEnvelope) -> Self {
Self::ParticipantAck(request)
}
#[must_use]
pub const fn marker_ack(request: MarkerAckEnvelope) -> Self {
Self::MarkerAck(request)
}
#[must_use]
pub const fn current_cursor(&self) -> DeliverySeq {
match self {
Self::ParticipantAck(request) => request.through_seq,
Self::MarkerAck(request) => request.marker_delivery_seq,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AckGap {
request: ParticipantAckEnvelope,
current_cursor: DeliverySeq,
}
impl AckGap {
#[must_use]
pub const fn new(request: ParticipantAckEnvelope, current_cursor: DeliverySeq) -> Option<Self> {
if request.through_seq > current_cursor {
Some(Self {
request,
current_cursor,
})
} else {
None
}
}
#[must_use]
pub const fn request(&self) -> &ParticipantAckEnvelope {
&self.request
}
#[must_use]
pub const fn current_cursor(&self) -> DeliverySeq {
self.current_cursor
}
#[must_use]
pub const fn reason(&self) -> AckGapReason {
let _ = self;
AckGapReason::NotContiguouslyAvailable
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AckRegression {
request: ParticipantAckEnvelope,
current_cursor: DeliverySeq,
}
impl AckRegression {
#[must_use]
pub const fn new(request: ParticipantAckEnvelope, current_cursor: DeliverySeq) -> Option<Self> {
if request.through_seq < current_cursor {
Some(Self {
request,
current_cursor,
})
} else {
None
}
}
#[must_use]
pub const fn request(&self) -> &ParticipantAckEnvelope {
&self.request
}
#[must_use]
pub const fn current_cursor(&self) -> DeliverySeq {
self.current_cursor
}
#[must_use]
pub const fn reason(&self) -> AckRegressionReason {
let _ = self;
AckRegressionReason::BelowCursor
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LeaveCommitted {
conversation_id: ConversationId,
leave_attempt_token: LeaveAttemptToken,
participant_id: ParticipantId,
retired_generation: Generation,
ended_binding_epoch: Option<BindingEpoch>,
prior_terminal_delivery_seq: Option<DeliverySeq>,
left_delivery_seq: DeliverySeq,
}
impl LeaveCommitted {
#[must_use]
#[allow(clippy::too_many_arguments)]
pub const fn new(
conversation_id: ConversationId,
leave_attempt_token: LeaveAttemptToken,
participant_id: ParticipantId,
retired_generation: Generation,
ended_binding_epoch: Option<BindingEpoch>,
prior_terminal_delivery_seq: Option<DeliverySeq>,
left_delivery_seq: DeliverySeq,
) -> Option<Self> {
if let Some(epoch) = ended_binding_epoch
&& epoch.capability_generation.get() != retired_generation.get()
{
return None;
}
if let Some(prior) = prior_terminal_delivery_seq
&& prior >= left_delivery_seq
{
return None;
}
Some(Self {
conversation_id,
leave_attempt_token,
participant_id,
retired_generation,
ended_binding_epoch,
prior_terminal_delivery_seq,
left_delivery_seq,
})
}
#[must_use]
pub const fn conversation_id(&self) -> ConversationId {
self.conversation_id
}
#[must_use]
pub const fn leave_attempt_token(&self) -> LeaveAttemptToken {
self.leave_attempt_token
}
#[must_use]
pub const fn participant_id(&self) -> ParticipantId {
self.participant_id
}
#[must_use]
pub const fn presented_generation(&self) -> Generation {
self.retired_generation
}
#[must_use]
pub const fn retired_generation(&self) -> Generation {
self.retired_generation
}
#[must_use]
pub const fn ended_binding_epoch(&self) -> Option<BindingEpoch> {
self.ended_binding_epoch
}
#[must_use]
pub const fn prior_terminal_delivery_seq(&self) -> Option<DeliverySeq> {
self.prior_terminal_delivery_seq
}
#[must_use]
pub const fn left_delivery_seq(&self) -> DeliverySeq {
self.left_delivery_seq
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MarkerAckCommitted {
request: MarkerAckEnvelope,
}
impl MarkerAckCommitted {
#[must_use]
pub const fn new(request: MarkerAckEnvelope) -> Self {
Self { request }
}
#[must_use]
pub const fn request(&self) -> &MarkerAckEnvelope {
&self.request
}
#[must_use]
pub const fn current_cursor(&self) -> DeliverySeq {
self.request.marker_delivery_seq
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RecordCommitted {
request: RecordAdmissionEnvelope,
delivery_seq: DeliverySeq,
}
impl RecordCommitted {
#[must_use]
pub const fn new(request: RecordAdmissionEnvelope, delivery_seq: DeliverySeq) -> Self {
Self {
request,
delivery_seq,
}
}
#[must_use]
pub const fn request(&self) -> &RecordAdmissionEnvelope {
&self.request
}
#[must_use]
pub const fn sender_participant_id(&self) -> ParticipantId {
self.request.participant_id
}
#[must_use]
pub const fn delivery_seq(&self) -> DeliverySeq {
self.delivery_seq
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RecordTooLarge {
pub request: RecordAdmissionEnvelope,
pub dimension: ResourceDimension,
pub encoded_record_charge: ResourceVector,
pub max_ordinary_record_charge: ResourceVector,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ObserverProgressStatus {
pub conversation_id: ConversationId,
pub refused_epoch: ObserverEpoch,
pub current_observer_progress: DeliverySeq,
pub armed: bool,
pub progressed: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ObserverRecoveryAccepted {
pub statuses: Vec<ObserverProgressStatus>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InvalidObserverEpoch {
ConversationUnknown {
conversation_id: ConversationId,
presented_epoch: ObserverEpoch,
},
EpochAhead {
conversation_id: ConversationId,
presented_epoch: ObserverEpoch,
current_observer_progress: DeliverySeq,
},
}
impl InvalidObserverEpoch {
#[must_use]
pub const fn reason(&self) -> InvalidObserverEpochReason {
match self {
Self::ConversationUnknown { .. } => InvalidObserverEpochReason::ConversationUnknown,
Self::EpochAhead { .. } => InvalidObserverEpochReason::EpochAhead,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InvalidObserverEpochList {
TooManyEntries {
presented_entries: u64,
max_entries: u64,
},
DuplicateConversation {
conversation_id: ConversationId,
first_index: u64,
duplicate_index: u64,
},
}
impl InvalidObserverEpochList {
#[must_use]
pub const fn reason(&self) -> InvalidObserverEpochListReason {
match self {
Self::TooManyEntries { .. } => InvalidObserverEpochListReason::TooManyEntries,
Self::DuplicateConversation { .. } => {
InvalidObserverEpochListReason::DuplicateConversation
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ServerValue {
ParticipantTransportRejected(ParticipantTransportRejected),
AttemptTokenBodyConflict(AttemptTokenBodyConflict),
ConnectionConversationCapacityExceeded(ConnectionConversationCapacityExceeded),
ConnectionConversationBindingOccupied(ConnectionConversationBindingOccupied),
ConversationOrderExhausted(Box<ConversationOrderExhausted>),
ParticipantUnknown(ParticipantUnknown),
NoBinding(NoBinding),
StaleAuthority(StaleAuthority),
Retired(Retired),
MarkerClosureCapacityExceeded(Box<MarkerClosureCapacityExceeded>),
EnrollBound(EnrollBound),
EnrollmentKnown(EnrollmentKnown),
ReceiptExpired(ReceiptExpired),
ReceiptCapacityExceeded(ReceiptCapacityExceeded),
IdentityCapacityExceeded(IdentityCapacityExceeded),
ObserverBackpressure(ObserverBackpressure),
ConversationSequenceExhausted(Box<ConversationSequenceExhausted>),
AttachBound(AttachBound),
StaleOrUnknownReceipt(StaleOrUnknownReceipt),
MarkerNotDelivered(MarkerNotDelivered),
MarkerMismatch(MarkerMismatch),
Bound(ReceiptReplay),
UnboundReceipt(ReceiptReplay),
DetachCommitted(DetachCommitted),
DetachInProgress(DetachInProgress),
AckCommitted(AckCommitted),
AckNoOp(AckNoOp),
AckGap(AckGap),
AckRegression(AckRegression),
LeaveCommitted(LeaveCommitted),
MarkerAckCommitted(MarkerAckCommitted),
RecordCommitted(RecordCommitted),
RecordTooLarge(RecordTooLarge),
ObserverRecoveryAccepted(ObserverRecoveryAccepted),
InvalidObserverEpoch(InvalidObserverEpoch),
InvalidObserverEpochList(InvalidObserverEpochList),
}
impl ServerValue {
#[must_use]
pub const fn discriminant(&self) -> ServerDiscriminant {
match self {
Self::ParticipantTransportRejected(_) => {
ServerDiscriminant::ParticipantTransportRejected
}
Self::AttemptTokenBodyConflict(_) => ServerDiscriminant::AttemptTokenBodyConflict,
Self::ConnectionConversationCapacityExceeded(value) => match value {
ConnectionConversationCapacityExceeded::SemanticRequest { .. } => {
ServerDiscriminant::ConnectionConversationCapacityExceeded
}
ConnectionConversationCapacityExceeded::ObserverRecovery { .. } => {
ServerDiscriminant::ObserverRecoveryConnectionCapacityExceeded
}
},
Self::ConnectionConversationBindingOccupied(_) => {
ServerDiscriminant::ConnectionConversationBindingOccupied
}
Self::ConversationOrderExhausted(_) => ServerDiscriminant::ConversationOrderExhausted,
Self::ParticipantUnknown(_) => ServerDiscriminant::ParticipantUnknown,
Self::NoBinding(_) => ServerDiscriminant::NoBinding,
Self::StaleAuthority(_) => ServerDiscriminant::StaleAuthority,
Self::Retired(_) => ServerDiscriminant::Retired,
Self::MarkerClosureCapacityExceeded(_) => {
ServerDiscriminant::MarkerClosureCapacityExceeded
}
Self::EnrollBound(_) => ServerDiscriminant::EnrollBound,
Self::EnrollmentKnown(_) => ServerDiscriminant::EnrollmentKnown,
Self::ReceiptExpired(_) => ServerDiscriminant::ReceiptExpired,
Self::ReceiptCapacityExceeded(_) => ServerDiscriminant::ReceiptCapacityExceeded,
Self::IdentityCapacityExceeded(_) => ServerDiscriminant::IdentityCapacityExceeded,
Self::ObserverBackpressure(_) => ServerDiscriminant::ObserverBackpressure,
Self::ConversationSequenceExhausted(_) => {
ServerDiscriminant::ConversationSequenceExhausted
}
Self::AttachBound(_) => ServerDiscriminant::AttachBound,
Self::StaleOrUnknownReceipt(_) => ServerDiscriminant::StaleOrUnknownReceipt,
Self::MarkerNotDelivered(_) => ServerDiscriminant::MarkerNotDelivered,
Self::MarkerMismatch(_) => ServerDiscriminant::MarkerMismatch,
Self::Bound(_) => ServerDiscriminant::Bound,
Self::UnboundReceipt(_) => ServerDiscriminant::UnboundReceipt,
Self::DetachCommitted(_) => ServerDiscriminant::DetachCommitted,
Self::DetachInProgress(_) => ServerDiscriminant::DetachInProgress,
Self::AckCommitted(_) => ServerDiscriminant::AckCommitted,
Self::AckNoOp(_) => ServerDiscriminant::AckNoOp,
Self::AckGap(_) => ServerDiscriminant::AckGap,
Self::AckRegression(_) => ServerDiscriminant::AckRegression,
Self::LeaveCommitted(_) => ServerDiscriminant::LeaveCommitted,
Self::MarkerAckCommitted(_) => ServerDiscriminant::MarkerAckCommitted,
Self::RecordCommitted(_) => ServerDiscriminant::RecordCommitted,
Self::RecordTooLarge(_) => ServerDiscriminant::RecordTooLarge,
Self::ObserverRecoveryAccepted(_) => ServerDiscriminant::ObserverRecoveryAccepted,
Self::InvalidObserverEpoch(_) => ServerDiscriminant::InvalidObserverEpoch,
Self::InvalidObserverEpochList(_) => ServerDiscriminant::InvalidObserverEpochList,
}
}
#[must_use]
#[allow(clippy::too_many_lines)]
pub const fn originating_request(&self) -> Option<ClientDiscriminant> {
match self {
Self::ParticipantTransportRejected(_)
| Self::ObserverRecoveryAccepted(_)
| Self::InvalidObserverEpoch(_)
| Self::InvalidObserverEpochList(_) => None,
Self::AttemptTokenBodyConflict(value) => Some(match value {
AttemptTokenBodyConflict::CredentialAttach { .. } => {
ClientDiscriminant::CredentialAttachRequest
}
AttemptTokenBodyConflict::Leave { .. } => ClientDiscriminant::LeaveRequest,
}),
Self::ConnectionConversationCapacityExceeded(value) => match value {
ConnectionConversationCapacityExceeded::SemanticRequest { request, .. } => {
Some(request.originating_request())
}
ConnectionConversationCapacityExceeded::ObserverRecovery { .. } => None,
},
Self::ConnectionConversationBindingOccupied(value) => Some(match value {
ConnectionConversationBindingOccupied::Enrollment { .. } => {
ClientDiscriminant::EnrollmentRequest
}
ConnectionConversationBindingOccupied::CredentialAttach { .. } => {
ClientDiscriminant::CredentialAttachRequest
}
}),
Self::ConversationOrderExhausted(value) => Some(match value.request() {
OrderAllocatingEnvelope::Enrollment(_) => ClientDiscriminant::EnrollmentRequest,
OrderAllocatingEnvelope::CredentialAttach(_) => {
ClientDiscriminant::CredentialAttachRequest
}
OrderAllocatingEnvelope::RecordAdmission(_) => ClientDiscriminant::RecordAdmission,
}),
Self::ParticipantUnknown(value) => Some(participant_reference_origin(&value.request)),
Self::NoBinding(value) => Some(binding_required_origin(&value.request)),
Self::StaleAuthority(value) => Some(stale_authority_origin(value)),
Self::Retired(value) => Some(match value {
Retired::Enrollment { .. } => ClientDiscriminant::EnrollmentRequest,
Retired::Participant { request, .. } => participant_reference_origin(request),
}),
Self::MarkerClosureCapacityExceeded(value) => Some(match &value.request {
ClosureCheckedEnvelope::Enrollment(_) => ClientDiscriminant::EnrollmentRequest,
ClosureCheckedEnvelope::CredentialAttach(_) => {
ClientDiscriminant::CredentialAttachRequest
}
ClosureCheckedEnvelope::Leave(_) => ClientDiscriminant::LeaveRequest,
ClosureCheckedEnvelope::RecordAdmission(_) => ClientDiscriminant::RecordAdmission,
}),
Self::EnrollBound(_) | Self::EnrollmentKnown(_) | Self::IdentityCapacityExceeded(_) => {
Some(ClientDiscriminant::EnrollmentRequest)
}
Self::ReceiptExpired(value) => Some(match value {
ReceiptExpired::Enrollment { .. } => ClientDiscriminant::EnrollmentRequest,
ReceiptExpired::CredentialAttach { .. } => {
ClientDiscriminant::CredentialAttachRequest
}
}),
Self::ReceiptCapacityExceeded(value) => Some(match value {
ReceiptCapacityExceeded::Enrollment { .. } => ClientDiscriminant::EnrollmentRequest,
ReceiptCapacityExceeded::CredentialAttach { .. } => {
ClientDiscriminant::CredentialAttachRequest
}
}),
Self::ObserverBackpressure(value) => Some(match value {
ObserverBackpressure::Enrollment { .. } => ClientDiscriminant::EnrollmentRequest,
ObserverBackpressure::CredentialAttach { .. } => {
ClientDiscriminant::CredentialAttachRequest
}
ObserverBackpressure::Detach { .. } => ClientDiscriminant::DetachRequest,
ObserverBackpressure::Leave { .. } => ClientDiscriminant::LeaveRequest,
ObserverBackpressure::RecordAdmission { .. } => ClientDiscriminant::RecordAdmission,
}),
Self::ConversationSequenceExhausted(value) => Some(match &value.request {
SequenceAllocatingEnvelope::Enrollment(_) => ClientDiscriminant::EnrollmentRequest,
SequenceAllocatingEnvelope::CredentialAttach(_) => {
ClientDiscriminant::CredentialAttachRequest
}
SequenceAllocatingEnvelope::RecordAdmission(_) => {
ClientDiscriminant::RecordAdmission
}
}),
Self::AttachBound(_) | Self::StaleOrUnknownReceipt(_) => {
Some(ClientDiscriminant::CredentialAttachRequest)
}
Self::MarkerNotDelivered(value) => Some(marker_proof_origin(&value.request)),
Self::MarkerMismatch(value) => Some(marker_proof_origin(&value.request)),
Self::Bound(value) | Self::UnboundReceipt(value) => Some(match value {
ReceiptReplay::Enrollment(_) => ClientDiscriminant::EnrollmentRequest,
ReceiptReplay::CredentialAttach(_) => ClientDiscriminant::CredentialAttachRequest,
}),
Self::DetachCommitted(_) | Self::DetachInProgress(_) => {
Some(ClientDiscriminant::DetachRequest)
}
Self::AckCommitted(_) | Self::AckGap(_) | Self::AckRegression(_) => {
Some(ClientDiscriminant::ParticipantAck)
}
Self::AckNoOp(value) => Some(match value {
AckNoOp::ParticipantAck(_) => ClientDiscriminant::ParticipantAck,
AckNoOp::MarkerAck(_) => ClientDiscriminant::MarkerAck,
}),
Self::LeaveCommitted(_) => Some(ClientDiscriminant::LeaveRequest),
Self::MarkerAckCommitted(_) => Some(ClientDiscriminant::MarkerAck),
Self::RecordCommitted(_) | Self::RecordTooLarge(_) => {
Some(ClientDiscriminant::RecordAdmission)
}
}
}
}
const fn participant_reference_origin(
request: &ParticipantReferenceEnvelope,
) -> ClientDiscriminant {
match request {
ParticipantReferenceEnvelope::CredentialAttach(_) => {
ClientDiscriminant::CredentialAttachRequest
}
ParticipantReferenceEnvelope::Detach(_) => ClientDiscriminant::DetachRequest,
ParticipantReferenceEnvelope::ParticipantAck(_) => ClientDiscriminant::ParticipantAck,
ParticipantReferenceEnvelope::Leave(_) => ClientDiscriminant::LeaveRequest,
ParticipantReferenceEnvelope::MarkerAck(_) => ClientDiscriminant::MarkerAck,
ParticipantReferenceEnvelope::RecordAdmission(_) => ClientDiscriminant::RecordAdmission,
}
}
const fn binding_required_origin(request: &BindingRequiredEnvelope) -> ClientDiscriminant {
match request {
BindingRequiredEnvelope::Detach(_) => ClientDiscriminant::DetachRequest,
BindingRequiredEnvelope::ParticipantAck(_) => ClientDiscriminant::ParticipantAck,
BindingRequiredEnvelope::Leave(_) => ClientDiscriminant::LeaveRequest,
BindingRequiredEnvelope::MarkerAck(_) => ClientDiscriminant::MarkerAck,
BindingRequiredEnvelope::RecordAdmission(_) => ClientDiscriminant::RecordAdmission,
}
}
const fn stale_authority_origin(value: &StaleAuthority) -> ClientDiscriminant {
match value {
StaleAuthority::Live { request, .. } => match request {
CommonStaleAuthorityEnvelope::CredentialAttach(_) => {
ClientDiscriminant::CredentialAttachRequest
}
CommonStaleAuthorityEnvelope::ParticipantAck(_) => ClientDiscriminant::ParticipantAck,
CommonStaleAuthorityEnvelope::MarkerAck(_) => ClientDiscriminant::MarkerAck,
CommonStaleAuthorityEnvelope::RecordAdmission(_) => ClientDiscriminant::RecordAdmission,
},
StaleAuthority::Detach(_) => ClientDiscriminant::DetachRequest,
StaleAuthority::Leave(_) => ClientDiscriminant::LeaveRequest,
}
}
const fn marker_proof_origin(request: &MarkerProofRequest) -> ClientDiscriminant {
match request {
MarkerProofRequest::CredentialAttach(_) => ClientDiscriminant::CredentialAttachRequest,
MarkerProofRequest::MarkerAck(_) => ClientDiscriminant::MarkerAck,
}
}
pub const PARTICIPANT_CAPABILITY: &str = "participant-v1";
#[must_use]
pub const fn attempt_operation(value: &AttemptTokenBodyConflict) -> super::AttemptOperation {
match value {
AttemptTokenBodyConflict::CredentialAttach { .. } => {
super::AttemptOperation::CredentialAttachRequest
}
AttemptTokenBodyConflict::Leave { .. } => super::AttemptOperation::LeaveRequest,
}
}
#[must_use]
pub fn capability_string() -> String {
String::from(PARTICIPANT_CAPABILITY)
}