Skip to main content

made_core/entities/
published_ceremony_definition.rs

1//! [`PublishedCeremonyDefinition`] — a definition fixed to a content
2//! identity.
3//!
4//! An agent can already write a definition and run it. What publication
5//! adds is that the thing it ran can be named later and shown to be the
6//! same thing: an immutable version with a digest an instance binds to
7//! and an auditor recomputes.
8//!
9//! Running an ad-hoc definition stays possible and is not the same act.
10//! Investigation should not need a published version; governed reuse
11//! should not accept an unpublished one.
12
13use crate::error::DomainError;
14use crate::value_objects::{CeremonyDefinitionDigest, CeremonyName, CeremonyVersion};
15
16use super::CeremonyDefinition;
17
18/// A definition and the digest that identifies its content.
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct PublishedCeremonyDefinition {
21    definition: CeremonyDefinition,
22    digest: CeremonyDefinitionDigest,
23}
24
25impl PublishedCeremonyDefinition {
26    /// Fix a definition to its content identity.
27    ///
28    /// Only a definition can be sealed, and a `CeremonyDefinition`
29    /// cannot exist while invalid — so an unpublishable draft can never
30    /// reach this constructor.
31    pub fn seal(definition: CeremonyDefinition) -> Result<Self, DomainError> {
32        let digest = definition.digest()?;
33        Ok(Self { definition, digest })
34    }
35
36    #[must_use]
37    pub fn definition(&self) -> &CeremonyDefinition {
38        &self.definition
39    }
40
41    #[must_use]
42    pub fn digest(&self) -> CeremonyDefinitionDigest {
43        self.digest
44    }
45
46    #[must_use]
47    pub fn name(&self) -> &CeremonyName {
48        self.definition.name()
49    }
50
51    #[must_use]
52    pub fn version(&self) -> &CeremonyVersion {
53        self.definition.version()
54    }
55
56    #[must_use]
57    pub fn into_definition(self) -> CeremonyDefinition {
58        self.definition
59    }
60}
61
62/// What publishing did.
63///
64/// Publishing the same content twice is not a failure — a retried
65/// publication must be safe, or a caller that loses a response has no
66/// correct next move. Publishing *different* content under a version
67/// that is taken is a conflict, and like a revision conflict it is an
68/// outcome the caller must resolve rather than an error to swallow.
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub enum PublicationOutcome {
71    Published(PublishedCeremonyDefinition),
72    /// The identical definition was already published under this
73    /// version. Nothing changed, and nothing needed to.
74    AlreadyPublished(PublishedCeremonyDefinition),
75    /// The version is taken by different content. A published version
76    /// is immutable, so the answer is a new version, never an
77    /// overwrite.
78    VersionOccupied {
79        published: CeremonyDefinitionDigest,
80        offered: CeremonyDefinitionDigest,
81    },
82}
83
84impl PublicationOutcome {
85    #[must_use]
86    pub fn published(&self) -> Option<&PublishedCeremonyDefinition> {
87        match self {
88            Self::Published(published) | Self::AlreadyPublished(published) => Some(published),
89            Self::VersionOccupied { .. } => None,
90        }
91    }
92
93    #[must_use]
94    pub fn is_conflict(&self) -> bool {
95        matches!(self, Self::VersionOccupied { .. })
96    }
97
98    /// Whether this call is what put the definition there.
99    #[must_use]
100    pub fn is_new(&self) -> bool {
101        matches!(self, Self::Published(_))
102    }
103}