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}