Skip to main content

made_core/entities/
ceremony_commit.rs

1//! [`CeremonyCommit`] — everything one step of a ceremony changes.
2//!
3//! State, audit and publication are three claims about the same moment.
4//! Saving them separately lets a process die between two of them and
5//! leave a journal that disagrees with the state, or a message that
6//! reports something that was never stored. They travel together so
7//! they can land together.
8
9use crate::entities::{AuditFact, CeremonyInstance};
10use crate::error::DomainError;
11use crate::value_objects::{ExpectedRevision, OutboxMessage};
12
13/// The unit that is committed, all of it or none of it.
14#[derive(Debug, Clone, PartialEq)]
15pub struct CeremonyCommit {
16    instance: CeremonyInstance,
17    expected_revision: ExpectedRevision,
18    facts: Vec<AuditFact>,
19    messages: Vec<OutboxMessage>,
20}
21
22impl CeremonyCommit {
23    /// Every fact must belong to the instance being committed.
24    ///
25    /// Rejected here rather than in the adapter: a commit that mixes
26    /// ceremonies has no correct interpretation, and every
27    /// implementation would otherwise have to discover that
28    /// independently.
29    pub fn new(
30        instance: CeremonyInstance,
31        expected_revision: ExpectedRevision,
32        facts: impl IntoIterator<Item = AuditFact>,
33        messages: impl IntoIterator<Item = OutboxMessage>,
34    ) -> Result<Self, DomainError> {
35        let facts = facts.into_iter().collect::<Vec<_>>();
36        if facts.iter().any(|fact| &fact.ceremony_id != instance.id()) {
37            return Err(DomainError::InvariantViolated {
38                reason: "a commit cannot carry audit facts from another ceremony",
39            });
40        }
41        Ok(Self {
42            instance,
43            expected_revision,
44            facts,
45            messages: messages.into_iter().collect(),
46        })
47    }
48
49    #[must_use]
50    pub fn instance(&self) -> &CeremonyInstance {
51        &self.instance
52    }
53
54    #[must_use]
55    pub fn expected_revision(&self) -> ExpectedRevision {
56        self.expected_revision
57    }
58
59    #[must_use]
60    pub fn facts(&self) -> &[AuditFact] {
61        &self.facts
62    }
63
64    #[must_use]
65    pub fn messages(&self) -> &[OutboxMessage] {
66        &self.messages
67    }
68
69    /// Consume the commit into the parts an adapter writes.
70    #[must_use]
71    pub fn into_parts(
72        self,
73    ) -> (
74        CeremonyInstance,
75        ExpectedRevision,
76        Vec<AuditFact>,
77        Vec<OutboxMessage>,
78    ) {
79        (
80            self.instance,
81            self.expected_revision,
82            self.facts,
83            self.messages,
84        )
85    }
86}