Skip to main content

creusot_std/logic/ra/
sum.rs

1#[cfg(creusot)]
2use crate::logic::such_that;
3use crate::{
4    logic::ra::{
5        RA,
6        update::{LocalUpdate, Update},
7    },
8    prelude::*,
9};
10
11/// The 'sum' (or 'either') Resource Algebra.
12///
13/// This represents a resource that is in two possible states. Combining a `Left` with
14/// a `Right` is invalid.
15pub enum Sum<T, U> {
16    Left(T),
17    Right(U),
18}
19
20impl<R1: RA, R2: RA> RA for Sum<R1, R2> {
21    #[logic(open)]
22    fn op(self, other: Self) -> Option<Self> {
23        match (self, other) {
24            (Self::Left(x), Self::Left(y)) => x.op(y).map_logic(|l| Self::Left(l)),
25            (Self::Right(x), Self::Right(y)) => x.op(y).map_logic(|r| Self::Right(r)),
26            _ => None,
27        }
28    }
29
30    #[logic(open)]
31    #[ensures(match result {
32        Some(c) => factor.op(c) == Some(self),
33        None => forall<c: Self> factor.op(c) != Some(self),
34    })]
35    fn factor(self, factor: Self) -> Option<Self> {
36        match (self, factor) {
37            (Self::Left(x), Self::Left(y)) => x.factor(y).map_logic(|l| Self::Left(l)),
38            (Self::Right(x), Self::Right(y)) => x.factor(y).map_logic(|r| Self::Right(r)),
39            _ => None,
40        }
41    }
42
43    #[logic(open, inline)]
44    #[ensures(result == (self == other))]
45    fn eq(self, other: Self) -> bool {
46        match (self, other) {
47            (Sum::Left(s), Sum::Left(o)) => s.eq(o),
48            (Sum::Right(s), Sum::Right(o)) => s.eq(o),
49            _ => false,
50        }
51    }
52
53    #[logic(law)]
54    #[ensures(a.op(b) == b.op(a))]
55    fn commutative(a: Self, b: Self) {}
56
57    #[logic]
58    #[ensures(a.op(b).and_then_logic(|ab: Self| ab.op(c)) == b.op(c).and_then_logic(|bc| a.op(bc)))]
59    fn associative(a: Self, b: Self, c: Self) {}
60
61    #[logic(open)]
62    fn core(self) -> Option<Self> {
63        match self {
64            Self::Left(x) => x.core().map_logic(|l| Self::Left(l)),
65            Self::Right(x) => x.core().map_logic(|r| Self::Right(r)),
66        }
67    }
68
69    #[logic]
70    #[requires(self.core() != None)]
71    #[ensures({
72        let c = self.core().unwrap_logic();
73        c.op(c) == Some(c)
74    })]
75    #[ensures(self.core().unwrap_logic().op(self) == Some(self))]
76    fn core_idemp(self) {
77        let _ = R1::core_idemp;
78        let _ = R2::core_idemp;
79    }
80
81    #[logic]
82    #[requires(i.op(i) == Some(i))]
83    #[requires(i.op(self) == Some(self))]
84    #[ensures(match self.core() {
85        Some(c) => i.incl(c),
86        None => false,
87    })]
88    fn core_is_maximal_idemp(self, i: Self) {
89        match (self, i) {
90            (Sum::Left(s), Sum::Left(i)) => s.core_is_maximal_idemp(i),
91            (Sum::Right(s), Sum::Right(i)) => s.core_is_maximal_idemp(i),
92            _ => (),
93        }
94    }
95}
96
97/// Apply an [update](Update) to the left side of a [`Sum`].
98///
99/// This requires the resource to be in the `Left` state.
100///
101/// # Example
102///
103/// ```
104/// use creusot_std::{
105///     ghost::resource::Resource,
106///     logic::ra::{
107///         excl::{Excl, ExclUpdate},
108///         sum::{Sum, SumUpdateL},
109///     },
110///     prelude::*,
111/// };
112///
113/// let mut res: Ghost<Resource<Sum<Excl<Int>, Excl<()>>>> =
114///     Resource::alloc(snapshot!(Sum::Left(Excl(1))));
115/// ghost! { res.update(SumUpdateL(ExclUpdate(snapshot!(2)))) };
116/// proof_assert!(res@ == Sum::Left(Excl(2)));
117/// ```
118pub struct SumUpdateL<U>(pub U);
119
120impl<R1: RA, R2: RA, U: Update<R1>> Update<Sum<R1, R2>> for SumUpdateL<U> {
121    type Choice = U::Choice;
122
123    #[logic(open, inline)]
124    fn premise(self, from: Sum<R1, R2>) -> bool {
125        match from {
126            Sum::Left(from) => self.0.premise(from),
127            Sum::Right(_) => false,
128        }
129    }
130
131    #[logic(open, inline)]
132    #[requires(self.premise(from))]
133    fn update(self, from: Sum<R1, R2>, ch: U::Choice) -> Sum<R1, R2> {
134        match from {
135            Sum::Left(from) => Sum::Left(self.0.update(from, ch)),
136            x => x, /* Dummy */
137        }
138    }
139
140    #[logic]
141    #[requires(self.premise(from))]
142    #[requires(from.op(frame) != None)]
143    #[ensures(self.update(from, result).op(frame) != None)]
144    fn frame_preserving(self, from: Sum<R1, R2>, frame: Sum<R1, R2>) -> U::Choice {
145        match (from, frame) {
146            (Sum::Left(from), Sum::Left(frame)) => self.0.frame_preserving(from, frame),
147            _ => such_that(|_| true),
148        }
149    }
150}
151
152/// Apply an [update](Update) to the right side of a [`Sum`].
153///
154/// This requires the resource to be in the `Right` state.
155///
156/// # Example
157///
158/// ```
159/// use creusot_std::{
160///     ghost::resource::Resource,
161///     logic::ra::{
162///         excl::{Excl, ExclUpdate},
163///         sum::{Sum, SumUpdateR},
164///     },
165///     prelude::*,
166/// };
167///
168/// let mut res: Ghost<Resource<Sum<Excl<()>, Excl<Int>>>> =
169///     Resource::alloc(snapshot!(Sum::Right(Excl(1))));
170/// ghost! { res.update(SumUpdateR(ExclUpdate(snapshot!(2)))) };
171/// proof_assert!(res@ == Sum::Right(Excl(2)));
172/// ```
173pub struct SumUpdateR<U>(pub U);
174
175impl<R: RA, U: Update<R>, V: RA> Update<Sum<V, R>> for SumUpdateR<U> {
176    type Choice = U::Choice;
177
178    #[logic(open, inline)]
179    fn premise(self, from: Sum<V, R>) -> bool {
180        match from {
181            Sum::Right(from) => self.0.premise(from),
182            Sum::Left(_) => false,
183        }
184    }
185
186    #[logic(open, inline)]
187    #[requires(self.premise(from))]
188    fn update(self, from: Sum<V, R>, ch: U::Choice) -> Sum<V, R> {
189        match from {
190            Sum::Right(from) => Sum::Right(self.0.update(from, ch)),
191            x => x, /* Dummy */
192        }
193    }
194
195    #[logic]
196    #[requires(self.premise(from))]
197    #[requires(from.op(frame) != None)]
198    #[ensures(self.update(from, result).op(frame) != None)]
199    fn frame_preserving(self, from: Sum<V, R>, frame: Sum<V, R>) -> U::Choice {
200        match (from, frame) {
201            (Sum::Right(from), Sum::Right(frame)) => self.0.frame_preserving(from, frame),
202            _ => such_that(|_| true),
203        }
204    }
205}
206
207/// Apply an [update](LocalUpdate) to the [`Left`](Sum::Left) variant of an
208/// authority/fragment pair of [`Sum`]s.
209///
210/// This requires either the authority or the fragment to be in the `Left` state
211/// (the other will be implied as they must always be in the same state).
212pub struct SumLocalUpdateL<U>(pub U);
213
214impl<R1: RA, R2: RA, U: LocalUpdate<R1>> LocalUpdate<Sum<R1, R2>> for SumLocalUpdateL<U> {
215    #[logic(open, inline)]
216    fn premise(self, from_auth: Sum<R1, R2>, from_frag: Sum<R1, R2>) -> bool {
217        match (from_auth, from_frag) {
218            (Sum::Left(from_auth), Sum::Left(from_frag)) => self.0.premise(from_auth, from_frag),
219            (Sum::Right(_), Sum::Right(_)) => false,
220            _ => true,
221        }
222    }
223
224    #[logic(open, inline)]
225    fn update(self, from_auth: Sum<R1, R2>, from_frag: Sum<R1, R2>) -> (Sum<R1, R2>, Sum<R1, R2>) {
226        match (from_auth, from_frag) {
227            (Sum::Left(from_auth), Sum::Left(from_frag)) => {
228                let (to_auth, to_frag) = self.0.update(from_auth, from_frag);
229                (Sum::Left(to_auth), Sum::Left(to_frag))
230            }
231            _ => such_that(|_| true),
232        }
233    }
234
235    #[logic]
236    #[requires(self.premise(from_auth, from_frag))]
237    #[requires(Some(from_frag).op(frame) == Some(Some(from_auth)))]
238    #[ensures({
239        let (to_auth, to_frag) = self.update(from_auth, from_frag);
240        Some(to_frag).op(frame) == Some(Some(to_auth))
241    })]
242    fn frame_preserving(
243        self,
244        from_auth: Sum<R1, R2>,
245        from_frag: Sum<R1, R2>,
246        frame: Option<Sum<R1, R2>>,
247    ) {
248        match (from_auth, from_frag, frame) {
249            (Sum::Left(from_auth), Sum::Left(from_frag), Some(Sum::Left(frame))) => {
250                self.0.frame_preserving(from_auth, from_frag, Some(frame))
251            }
252            (Sum::Left(from_auth), Sum::Left(from_frag), None) => {
253                self.0.frame_preserving(from_auth, from_frag, None)
254            }
255            _ => (),
256        }
257    }
258}
259
260/// Apply an [update](LocalUpdate) to the [`Right`](Sum::Right) variant of an
261/// authority/fragment pair of [`Sum`]s.
262///
263/// This requires either the authority or the fragment to be in the `Right` state
264/// (the other will be implied as they must always be in the same state).
265pub struct SumLocalUpdateR<U>(pub U);
266
267impl<R1: RA, R2: RA, U: LocalUpdate<R2>> LocalUpdate<Sum<R1, R2>> for SumLocalUpdateR<U> {
268    #[logic(open, inline)]
269    fn premise(self, from_auth: Sum<R1, R2>, from_frag: Sum<R1, R2>) -> bool {
270        match (from_auth, from_frag) {
271            (Sum::Right(from_auth), Sum::Right(from_frag)) => self.0.premise(from_auth, from_frag),
272            (Sum::Left(_), Sum::Left(_)) => false,
273            _ => true,
274        }
275    }
276
277    #[logic(open, inline)]
278    fn update(self, from_auth: Sum<R1, R2>, from_frag: Sum<R1, R2>) -> (Sum<R1, R2>, Sum<R1, R2>) {
279        match (from_auth, from_frag) {
280            (Sum::Right(from_auth), Sum::Right(from_frag)) => {
281                let (to_auth, to_frag) = self.0.update(from_auth, from_frag);
282                (Sum::Right(to_auth), Sum::Right(to_frag))
283            }
284            _ => such_that(|_| true),
285        }
286    }
287
288    #[logic]
289    #[requires(self.premise(from_auth, from_frag))]
290    #[requires(Some(from_frag).op(frame) == Some(Some(from_auth)))]
291    #[ensures({
292        let (to_auth, to_frag) = self.update(from_auth, from_frag);
293        Some(to_frag).op(frame) == Some(Some(to_auth))
294    })]
295    fn frame_preserving(
296        self,
297        from_auth: Sum<R1, R2>,
298        from_frag: Sum<R1, R2>,
299        frame: Option<Sum<R1, R2>>,
300    ) {
301        match (from_auth, from_frag, frame) {
302            (Sum::Right(from_auth), Sum::Right(from_frag), Some(Sum::Right(frame))) => {
303                self.0.frame_preserving(from_auth, from_frag, Some(frame))
304            }
305            (Sum::Right(from_auth), Sum::Right(from_frag), None) => {
306                self.0.frame_preserving(from_auth, from_frag, None)
307            }
308            _ => (),
309        }
310    }
311}