Skip to main content

creusot_std/logic/ra/
update.rs

1#[cfg(creusot)]
2use crate::logic::such_that;
3use crate::{
4    logic::{Mapping, ra::RA},
5    prelude::*,
6};
7
8/// Perform an update on a resource.
9///
10/// This is used by [`Resource::update`](crate::ghost::resource::Resource::update)
11/// to specify how to update a resource.
12pub trait Update<R: RA> {
13    /// If the update is non-deterministic, it will pick a _choice_ of this type
14    /// for the update.
15    type Choice;
16
17    /// The premise of the update.
18    ///
19    /// This must be true for the resource before applying the update.
20    #[logic]
21    fn premise(self, from: R) -> bool;
22
23    /// The actual update performed.
24    ///
25    /// The content of the resource before the update is `from`. The update will
26    /// also choose some element `ch` of `Choice` to make the update with. The
27    /// return value will be the content of the resource after the update.
28    #[logic]
29    #[requires(self.premise(from))]
30    fn update(self, from: R, ch: Self::Choice) -> R;
31
32    /// Frame preservation.
33    ///
34    /// This is a lemma that must be proven by implementors to ensure that the
35    /// update is consistent.
36    ///
37    /// It states that for any valid composition of `self` with some `frame`
38    /// resource, we can find a `Choice` that, when applying the corresponding
39    /// update, is still a valid composition with `frame`.
40    #[logic]
41    #[requires(self.premise(from))]
42    #[requires(from.op(frame) != None)]
43    #[ensures(self.update(from, result).op(frame) != None)]
44    fn frame_preserving(self, from: R, frame: R) -> Self::Choice;
45}
46
47/// Apply a 'raw' update.
48///
49/// This changes the state of the resource from one value to another. The
50/// premise of this change is that no existing composition with the resource
51/// is invalidated.
52impl<R: RA> Update<R> for Snapshot<R> {
53    type Choice = ();
54
55    #[logic(open, inline)]
56    fn premise(self, from: R) -> bool {
57        pearlite! {
58            forall<y: R> from.op(y) != None ==> self.op(y) != None
59        }
60    }
61
62    #[logic(open, inline)]
63    #[requires(self.premise(from))]
64    fn update(self, from: R, _: ()) -> R {
65        *self
66    }
67
68    #[logic]
69    #[requires(self.premise(from))]
70    #[requires(from.op(frame) != None)]
71    #[ensures(self.update(from, result).op(frame) != None)]
72    fn frame_preserving(self, from: R, frame: R) {}
73}
74
75/// Apply a 'raw' non-deterministic update.
76///
77/// This changes the state of the resource to _one_ of the values of the
78/// mapping, non-deterministically.
79impl<R: RA, Choice> Update<R> for Snapshot<Mapping<Choice, R>> {
80    type Choice = Choice;
81
82    #[logic(open, inline)]
83    fn premise(self, from: R) -> bool {
84        pearlite! {
85            forall<y: R> from.op(y) != None ==>
86                exists<ch: Choice> self[ch].op(y) != None
87        }
88    }
89
90    #[logic(open, inline)]
91    #[requires(self.premise(from))]
92    fn update(self, from: R, ch: Choice) -> R {
93        self[ch]
94    }
95
96    #[logic]
97    #[requires(self.premise(from))]
98    #[requires(from.op(frame) != None)]
99    #[ensures(self.update(from, result).op(frame) != None)]
100    fn frame_preserving(self, from: R, frame: R) -> Choice {
101        such_that(|ch| self.update(from, ch).op(frame) != None)
102    }
103}
104
105/// Apply no update.
106impl<R: RA> Update<R> for () {
107    type Choice = ();
108
109    #[logic(open, inline)]
110    fn premise(self, _: R) -> bool {
111        true
112    }
113
114    #[logic(open, inline)]
115    fn update(self, from: R, _: ()) -> R {
116        from
117    }
118
119    #[logic]
120    #[requires(from.op(frame) != None)]
121    #[ensures(from.op(frame) != None)]
122    fn frame_preserving(self, from: R, frame: R) {}
123}
124
125/// Perform an update on an authority/fragment pair.
126///
127/// This is similar to [`Update`], but is instead used by
128/// [`Authority::update`](crate::ghost::resource::Authority::update) to
129/// simultaneously change the value of an authority/fragment pair.
130///
131/// Note that contrary to [`Update`], this has to be deterministic.
132pub trait LocalUpdate<R: RA>: Sized {
133    /// The premise of the update.
134    ///
135    /// This must be true for the authority and the fragment _before_ applying
136    /// the update.
137    #[logic]
138    fn premise(self, from_auth: R, from_frag: R) -> bool;
139
140    /// The update performed.
141    ///
142    /// This describe how to change the authority/fragment pair.
143    #[logic]
144    fn update(self, from_auth: R, from_frag: R) -> (R, R);
145
146    /// Frame preservation.
147    ///
148    /// This is a lemma that must be proven by implementors to ensure that the
149    /// update is consistent.
150    ///
151    /// It states that the 'missing piece' of the authority from the fragment is
152    /// still the same after the update.
153    #[logic]
154    #[requires(self.premise(from_auth, from_frag))]
155    #[requires(Some(from_frag).op(frame) == Some(Some(from_auth)))]
156    #[ensures({
157        let (to_auth, to_frag) = self.update(from_auth, from_frag);
158        Some(to_frag).op(frame) == Some(Some(to_auth))
159    })]
160    fn frame_preserving(self, from_auth: R, from_frag: R, frame: Option<R>);
161}
162
163/// Apply a 'raw' local update.
164///
165/// This will update the value of the authority/fragment to the provided pair.
166impl<R: RA> LocalUpdate<R> for Snapshot<(R, R)> {
167    #[logic(open, inline)]
168    fn premise(self, from_auth: R, from_frag: R) -> bool {
169        pearlite! {
170            forall<f: Option<R>>
171                Some(from_frag).op(f) == Some(Some(from_auth)) ==>
172                Some(self.1).op(f) == Some(Some(self.0))
173        }
174    }
175
176    #[logic(open, inline)]
177    fn update(self, _: R, _: R) -> (R, R) {
178        *self
179    }
180
181    #[logic]
182    #[allow(unused)]
183    #[requires(LocalUpdate::premise(self, from_auth, from_frag))]
184    #[requires(Some(from_frag).op(frame) == Some(Some(from_auth)))]
185    #[ensures({
186        let (to_auth, to_frag) = LocalUpdate::update(self, from_auth, from_frag);
187        Some(to_frag).op(frame) == Some(Some(to_auth))
188    })]
189    fn frame_preserving(self, from_auth: R, from_frag: R, frame: Option<R>) {}
190}
191
192/// Apply no update.
193impl<R: RA> LocalUpdate<R> for () {
194    #[logic(open, inline)]
195    fn premise(self, _: R, _: R) -> bool {
196        true
197    }
198
199    #[logic(open, inline)]
200    fn update(self, from_auth: R, from_frag: R) -> (R, R) {
201        (from_auth, from_frag)
202    }
203
204    #[logic]
205    #[requires(Some(frag).op(frame) == Some(Some(auth)))]
206    #[ensures(Some(frag).op(frame) == Some(Some(auth)))]
207    fn frame_preserving(self, auth: R, frag: R, frame: Option<R>) {}
208}