1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use core::cmp::Ordering;
use core::marker::PhantomData;
use super::Scoped;
use crate::metis::{ScopedPeek, VersionVector};
impl Scoped<'_, VersionVector> {
/// The scoped causal verdict: [`VersionVector::partial_cmp`] on the two
/// restrictions.
///
/// Sound *within* the scope by PRD 0013's preservation law (if `a <= b`
/// globally then the restrictions agree), and inexpressible across scopes
/// by the brand. The polarity is the whole point: a `Some(Less)` here means
/// order *over the roster*, never order tout court, because restriction can
/// drop exactly the stations that witnessed a disagreement. Acting on this
/// verdict globally is the created-order hazard; for the verdict that does
/// escape lawfully, see [`concurrent_globally`](Self::concurrent_globally).
#[must_use]
pub fn partial_cmp_scoped(&self, other: &Self) -> Option<Ordering> {
self.value.partial_cmp(&other.value)
}
/// Whether this restriction strictly precedes `other`'s over the roster.
///
/// A scoped order verdict: sound within the scope, meaningless outside it.
/// This is order *over the roster*, never order tout court (PRD 0013); do
/// not act on it globally.
#[must_use]
pub fn happens_before(&self, other: &Self) -> bool {
self.value.happens_before(&other.value)
}
/// Whether the two restrictions are concurrent, a verdict that lawfully
/// escapes the scope unbranded.
///
/// Concurrency *reflects* globally (PRD 0013): concurrent restrictions
/// certify concurrent originals, because the two leading stations survive
/// in the roster. So unlike the order reads this returns a plain `bool`
/// with no brand: a caller may carry it out of the scope and act on it
/// globally. The converse still fails (concurrent originals may restrict to
/// ordered ones), which is exactly why the *order* reads stay branded.
#[must_use]
pub fn concurrent_globally(&self, other: &Self) -> bool {
self.value.concurrent(&other.value)
}
/// The scoped join: [`VersionVector::merge`] of the two restrictions,
/// staying in the scope.
///
/// Restriction is a lattice homomorphism (PRD 0013), so folding
/// restrictions equals restricting the fold; the result is branded, so it
/// never leaves the scope by accident.
#[must_use]
pub fn merge(&self, other: &Self) -> Self {
Self {
value: self.value.merge(&other.value),
_brand: PhantomData,
}
}
/// The scoped meet: [`VersionVector::meet`] of the two restrictions,
/// staying in the scope.
///
/// The order dual of [`merge`](Self::merge); restriction commutes with the
/// meet exactly (PRD 0013), so the fold stays scoped.
#[must_use]
pub fn meet(&self, other: &Self) -> Self {
Self {
value: self.value.meet(&other.value),
_brand: PhantomData,
}
}
/// Leaves the scope, forgetting where the verdicts were valid.
///
/// The named escape: dropping the brand returns the bare
/// [`VersionVector`], and with it any memory of the roster the evidence was
/// read over. The created-order hazard is exactly acting on a scoped order
/// verdict globally, so the escape is named for what it costs. Concurrency
/// verdicts do not need this door; [`concurrent_globally`](Self::concurrent_globally)
/// already hands back an unbranded `bool`.
#[must_use]
pub fn forget(self) -> VersionVector {
self.value
}
/// A borrowed, display-only read of the restriction, without escaping the
/// brand and without a reachable order.
///
/// # Why a wrapper, not `&VersionVector`
///
/// A bare `&VersionVector` reopens the exact hole the brand closes:
/// [`VersionVector`] is [`PartialOrd`], so `scope.restrict(&a).peek() <=
/// scope.restrict(&b).peek()` would quietly yield a *scoped* order verdict
/// through an *unbranded* reference, the created-order hazard walking out
/// the display door (PRD 0013). [`ScopedPeek`] carries the reference for
/// [`Debug`](core::fmt::Debug) rendering only: it has no [`PartialOrd`], no
/// [`Deref`](core::ops::Deref), and no accessor handing the inner reference
/// back, so the operators cannot be reached and the sound scoped order stays
/// where it belongs, in [`partial_cmp_scoped`](Self::partial_cmp_scoped) and
/// [`happens_before`](Self::happens_before). Two peeks compare *equal*
/// ([`PartialEq`]) but never *ordered*: equality carries no roster-forgetting
/// hazard, order does.
#[must_use]
pub const fn peek(&self) -> ScopedPeek<'_, VersionVector> {
ScopedPeek::new(&self.value)
}
}