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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
extern crate alloc;
use BTreeSet;
use Vec;
use PhantomData;
use ;
pub use ScopedPeek;
pub use Scoped;
/// A restriction scope: an invariant lifetime brand tied to one sub-roster,
/// inside which restricted evidence may be compared, and outside of which the
/// comparison does not typecheck.
///
/// A scope is opened by [`with_scope`], which mints a fresh, invariant lifetime
/// `'brand` and hands the body a `Scope<'brand>`. Restricting a vector or a
/// have-set through the scope yields a [`Scoped`] value carrying that same
/// brand, so two values born under different scopes never unify: comparing
/// evidence restricted under different rosters is a compile error, not a
/// discipline the caller must remember.
///
/// The brand is the type-level form of PRD 0013's *created-order hazard*.
/// Restriction preserves order but does not reflect it, so an order verdict on
/// restrictions is order *over the roster*, never order tout court; a caller
/// that compares restrictions from two different rosters and acts as if the
/// verdict were global has fabricated a happens-before out of forgetting. The
/// scope makes that fabrication uncompilable rather than merely documented.
/// Opens a restriction scope over `roster` and runs `body` inside it.
///
/// The brand is fresh and invariant per invocation: the `for<'brand>` bound
/// forces `body` to accept *any* lifetime the caller of `with_scope` picks, so
/// the concrete `'brand` cannot be named outside and two scopes' values never
/// unify. Comparing evidence restricted under different rosters is therefore a
/// compile error. A [`Scoped`] value also cannot be returned out of `body`
/// while still branded, because its type mentions `'brand`; the lawful exit is
/// [`Scoped::forget`], which drops the brand and hands back a plain value.
///
/// # Type-level proof obligations
///
/// Two scopes' values do not unify, so a cross-scope comparison fails to
/// compile:
///
/// ```compile_fail
/// use minerva::metis::{with_scope, VersionVector};
///
/// let a = VersionVector::new();
/// let b = VersionVector::new();
/// with_scope([1u32], |outer| {
/// let ra = outer.restrict(&a);
/// with_scope([1u32], |inner| {
/// let rb = inner.restrict(&b);
/// // `ra` is branded by `outer`, `rb` by `inner`: the brands are
/// // distinct invariant lifetimes, so this does not typecheck.
/// let _ = ra.happens_before(&rb);
/// });
/// });
/// ```
///
/// A branded value cannot escape its scope: the brand cannot outlive the body:
///
/// ```compile_fail
/// use minerva::metis::{with_scope, Scoped, VersionVector};
///
/// let v = VersionVector::new();
/// // The return type would have to mention the scope's `'brand`, which is
/// // not nameable outside, so this does not typecheck.
/// let escaped: Scoped<'_, VersionVector> =
/// with_scope([1u32], |scope| scope.restrict(&v));
/// let _ = escaped;
/// ```
///
/// Escaping is lawful only after [`Scoped::forget`], which drops the brand:
///
/// ```
/// use minerva::metis::{with_scope, VersionVector};
///
/// let v = VersionVector::new();
/// let forgotten: VersionVector = with_scope([1u32], |scope| scope.restrict(&v).forget());
/// assert_eq!(forgotten, VersionVector::new());
/// ```
///
/// # The intended flow
///
/// Open a scope, restrict two vectors, read a scoped order verdict (sound over
/// the roster), read the concurrency verdict that lawfully escapes unbranded,
/// then forget deliberately when leaving:
///
/// ```
/// use minerva::metis::{with_scope, VersionVector};
///
/// let mut a = VersionVector::new();
/// a.observe(1, 3);
/// a.observe(2, 1);
/// let mut b = VersionVector::new();
/// b.observe(1, 1);
/// b.observe(2, 4);
/// // Globally concurrent: each leads the other on a station.
/// assert!(a.concurrent(&b));
///
/// let (ordered_in_scope, concurrent_globally, forgotten) = with_scope([1u32], |scope| {
/// let ra = scope.restrict(&a);
/// let rb = scope.restrict(&b);
/// // Over station 1 alone, `b` precedes `a`: a verdict sound only here.
/// let ordered = rb.happens_before(&ra);
/// // Concurrency reflects globally, so this bool lawfully leaves the scope.
/// let concurrent = ra.concurrent_globally(&rb);
/// // Leaving forgets where the verdict was valid; the name is the warning.
/// (ordered, concurrent, ra.forget())
/// });
///
/// assert!(ordered_in_scope); // order over the roster, never order tout court
/// assert!(!concurrent_globally); // these restrictions are ordered, not concurrent
/// assert_eq!(forgotten, a.restrict([1u32]));
/// ```