Skip to main content

blockworx_doc/
write_order.rs

1use serde::{Deserialize, Serialize};
2
3use crate::rev::Rev;
4
5/// An op's position within its commit — the final tiebreak of the write
6/// order. Revs are unique per *commit*, not per write: every op shares
7/// its commit's rev, so `Seq` is what keeps the order total over writes.
8#[derive(
9    Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default, Serialize, Deserialize,
10)]
11pub struct Seq(usize);
12
13impl Seq {
14    pub const FIRST: Seq = Seq(0);
15
16    pub const fn new(n: usize) -> Self {
17        Self(n)
18    }
19
20    pub const fn get(self) -> usize {
21        self.0
22    }
23}
24
25/// The register comparison key — the full total order on writes. `max`
26/// over it is the whole merge rule, self-contained: no assumptions about
27/// commit atomicity or delivery order are needed for convergence.
28#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)]
29pub struct WriteOrder {
30    pub rev: Rev,
31    pub seq: Seq,
32}
33
34impl WriteOrder {
35    pub const BOTTOM: WriteOrder = WriteOrder {
36        rev: Rev::ZERO,
37        seq: Seq::FIRST,
38    };
39
40    pub const fn new(rev: Rev, seq: Seq) -> Self {
41        WriteOrder { rev, seq }
42    }
43}
44
45impl Default for WriteOrder {
46    fn default() -> Self {
47        Self::BOTTOM
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    /// Two writes in one commit share a rev, so only the seq separates
56    /// them.
57    #[test]
58    fn one_commits_writes_are_ordered_by_seq() {
59        let first = WriteOrder::new(Rev::new(3), Seq::new(0));
60        let second = WriteOrder::new(Rev::new(3), Seq::new(1));
61        assert_eq!(
62            first.rev, second.rev,
63            "the fixture must share a rev or the seq isn't what's ordering them"
64        );
65        assert!(first < second);
66    }
67
68    /// Sequencing dominates position: a later commit's first write outranks
69    /// an earlier commit's last.
70    #[test]
71    fn the_rev_outranks_the_seq() {
72        let late_in_old = WriteOrder::new(Rev::new(5), Seq::new(9));
73        let first_in_new = WriteOrder::new(Rev::new(7), Seq::FIRST);
74        assert!(late_in_old < first_in_new);
75    }
76
77    #[test]
78    fn bottom_sorts_below_every_minted_order() {
79        assert!(WriteOrder::BOTTOM < WriteOrder::new(Rev::new(1), Seq::FIRST));
80    }
81}