use crate::descriptor::encode::{encode_row_content, encode_trial_coordinates};
use crate::descriptor::types::{
AdmissionFacts, AdmissionGround, CanonicalRowBytes, CapsulePosture, CheckRef, ClaimRef,
Classification, ClassificationRefusal, DischargeAdmission, DoorRef, ExecutionSuite, Origin,
PopulationRef, ProducerFacts, ProjectionRef, ProposalId, ReplayAdmission, ReplayBearingGround,
ReplayRef, Role, Row, RowRefusal, SubjectRoute, Tag, TrialCoordinates, TrialKey,
};
use crate::identity::{ContentAddress, DomainTag, IdentityProfileVersion};
use std::collections::BTreeSet;
const TRIAL_KEY_DOMAIN: DomainTag =
DomainTag::declared("trial-key", IdentityProfileVersion::declared(1));
impl AdmissionGround {
#[must_use]
pub const fn capsule_posture(self) -> CapsulePosture {
match self {
Self::MutantKilled | Self::ClaimPinned => CapsulePosture::ReplayBearing,
Self::ObligationDischarged => CapsulePosture::NoCapsule,
}
}
}
impl ProposalId {
#[must_use]
pub const fn over(address: ContentAddress) -> Self {
Self(address)
}
}
crate::identity::content_address_reference! {
value ProposalId;
}
impl ReplayRef {
#[must_use]
pub(crate) const fn over(address: ContentAddress) -> Self {
Self(address)
}
}
crate::identity::content_address_reference! {
value ReplayRef;
}
impl Classification {
pub fn authored(roles: Vec<Role>, tags: Vec<Tag>) -> Result<Self, ClassificationRefusal> {
let mut parsed_roles = BTreeSet::new();
for role in roles {
if !parsed_roles.insert(role) {
return Err(ClassificationRefusal::DuplicateRole(role));
}
}
let mut parsed_tags = BTreeSet::new();
for tag in tags {
if !parsed_tags.insert(tag) {
return Err(ClassificationRefusal::DuplicateTag(tag));
}
}
Ok(Self {
roles: parsed_roles,
tags: parsed_tags,
})
}
#[must_use]
pub const fn roles(&self) -> &BTreeSet<Role> {
&self.roles
}
#[must_use]
pub const fn tags(&self) -> &BTreeSet<Tag> {
&self.tags
}
}
impl ProducerFacts {
#[must_use]
pub const fn emitted(door: DoorRef, projection: ProjectionRef) -> Self {
Self { door, projection }
}
#[must_use]
pub const fn door(self) -> DoorRef {
self.door
}
#[must_use]
pub const fn projection(self) -> ProjectionRef {
self.projection
}
}
impl AdmissionFacts {
#[must_use]
pub const fn stated(ground: AdmissionGround, destination: ExecutionSuite) -> Self {
Self {
ground,
destination,
}
}
#[must_use]
pub const fn ground(self) -> AdmissionGround {
self.ground
}
#[must_use]
pub const fn destination(self) -> ExecutionSuite {
self.destination
}
}
impl ReplayAdmission {
#[must_use]
pub(crate) const fn admitted(
proposal: ProposalId,
ground: ReplayBearingGround,
destination: ExecutionSuite,
replay: ReplayRef,
) -> Self {
Self {
proposal,
ground,
destination,
replay,
}
}
#[must_use]
pub const fn proposal(self) -> ProposalId {
self.proposal
}
#[must_use]
pub const fn ground(self) -> ReplayBearingGround {
self.ground
}
#[must_use]
pub const fn destination(self) -> ExecutionSuite {
self.destination
}
#[must_use]
pub const fn replay(self) -> ReplayRef {
self.replay
}
#[must_use]
pub fn admission(self) -> AdmissionFacts {
AdmissionFacts::stated(AdmissionGround::from(self.ground), self.destination)
}
}
impl DischargeAdmission {
#[must_use]
pub(crate) const fn admitted(proposal: ProposalId, destination: ExecutionSuite) -> Self {
Self {
proposal,
destination,
}
}
#[must_use]
pub const fn proposal(self) -> ProposalId {
self.proposal
}
#[must_use]
pub const fn destination(self) -> ExecutionSuite {
self.destination
}
#[must_use]
pub const fn admission(self) -> AdmissionFacts {
AdmissionFacts::stated(AdmissionGround::ObligationDischarged, self.destination)
}
}
impl CanonicalRowBytes {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl Row {
pub fn declared(
claim: ClaimRef,
execution_suite: ExecutionSuite,
classification: Classification,
subject: SubjectRoute,
check: CheckRef,
population: PopulationRef,
origin: Origin,
) -> Result<Self, RowRefusal> {
let canonical = encode_row_content(
claim,
execution_suite,
&classification,
subject,
check,
population,
origin,
)
.map_err(RowRefusal::NotEncoded)?;
let coordinates = TrialCoordinates::over(claim, subject, check, population);
let trial_key = TrialKey::over(coordinates);
Ok(Self {
coordinates,
trial_key,
execution_suite,
classification,
origin,
canonical: CanonicalRowBytes(canonical),
})
}
#[must_use]
pub const fn coordinates(&self) -> TrialCoordinates {
self.coordinates
}
#[must_use]
pub const fn claim(&self) -> ClaimRef {
self.coordinates.claim()
}
#[must_use]
pub const fn execution_suite(&self) -> ExecutionSuite {
self.execution_suite
}
#[must_use]
pub const fn classification(&self) -> &Classification {
&self.classification
}
#[must_use]
pub const fn roles(&self) -> &BTreeSet<Role> {
self.classification.roles()
}
#[must_use]
pub const fn tags(&self) -> &BTreeSet<Tag> {
self.classification.tags()
}
#[must_use]
pub const fn subject(&self) -> SubjectRoute {
self.coordinates.subject()
}
#[must_use]
pub const fn check(&self) -> CheckRef {
self.coordinates.check()
}
#[must_use]
pub const fn population(&self) -> PopulationRef {
self.coordinates.population()
}
#[must_use]
pub const fn origin(&self) -> Origin {
self.origin
}
#[must_use]
pub const fn canonical_bytes(&self) -> &CanonicalRowBytes {
&self.canonical
}
#[must_use]
pub const fn trial_key(&self) -> TrialKey {
self.trial_key
}
}
impl TrialCoordinates {
#[must_use]
pub const fn over(
claim: ClaimRef,
subject: SubjectRoute,
check: CheckRef,
population: PopulationRef,
) -> Self {
Self {
claim,
subject,
check,
population,
}
}
#[must_use]
pub const fn claim(self) -> ClaimRef {
self.claim
}
#[must_use]
pub const fn subject(self) -> SubjectRoute {
self.subject
}
#[must_use]
pub const fn check(self) -> CheckRef {
self.check
}
#[must_use]
pub const fn population(self) -> PopulationRef {
self.population
}
}
impl TrialKey {
#[must_use]
pub fn over(coordinates: TrialCoordinates) -> Self {
let preimage = encode_trial_coordinates(coordinates);
Self(ContentAddress::derived(TRIAL_KEY_DOMAIN, &preimage))
}
}
crate::identity::content_address_reference! {
value TrialKey;
}