Skip to main content

made_core/value_objects/audit/
stream_version.rs

1use serde::{Deserialize, Serialize};
2
3use super::AuditSequence;
4
5/// How many events a ceremony's stream holds.
6///
7/// A stream that does not exist yet is at [`StreamVersion::EMPTY`];
8/// after that the version is the sequence of the last record, since
9/// sequences start at 1 and are contiguous. A command is decided
10/// against a version and appended with it as the expectation, which is
11/// what lets a store refuse a write decided against a stream that has
12/// since moved on.
13///
14/// Not a [`super::AuditSequence`]: a sequence names a record, and there
15/// is no record for an empty stream.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
17#[serde(transparent)]
18pub struct StreamVersion(u64);
19
20impl StreamVersion {
21    /// The version of a stream nothing has been appended to.
22    pub const EMPTY: Self = Self(0);
23
24    #[must_use]
25    pub const fn new(value: u64) -> Self {
26        Self(value)
27    }
28
29    /// The version a stream reaches once `sequence` is its last record.
30    #[must_use]
31    pub fn from_sequence(sequence: AuditSequence) -> Self {
32        Self(sequence.value())
33    }
34
35    #[must_use]
36    pub fn value(self) -> u64 {
37        self.0
38    }
39
40    /// The version after one more event. Saturates rather than
41    /// wrapping, as sequences do.
42    #[must_use]
43    pub fn next(self) -> Self {
44        Self(self.0.saturating_add(1))
45    }
46
47    #[must_use]
48    pub fn is_empty(self) -> bool {
49        self == Self::EMPTY
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn an_empty_stream_is_at_version_zero() {
59        assert_eq!(StreamVersion::EMPTY.value(), 0);
60        assert!(StreamVersion::EMPTY.is_empty());
61        assert!(!StreamVersion::EMPTY.next().is_empty());
62    }
63
64    #[test]
65    fn the_version_after_the_first_record_is_its_sequence() {
66        assert_eq!(
67            StreamVersion::from_sequence(AuditSequence::FIRST),
68            StreamVersion::EMPTY.next()
69        );
70        assert_eq!(
71            StreamVersion::from_sequence(AuditSequence::new(7).unwrap()).value(),
72            7
73        );
74    }
75
76    #[test]
77    fn versions_order_by_length() {
78        assert!(StreamVersion::EMPTY < StreamVersion::new(1));
79        assert!(StreamVersion::new(2) < StreamVersion::new(10));
80    }
81}