creusot_std/invariant/subset.rs
1use crate::prelude::*;
2#[cfg(creusot)]
3use crate::resolve::structural_resolve;
4use core::ops::{Deref, DerefMut};
5
6/// A type implements `InhabitedInvariant` when its type invariant is inhabited.
7/// This is needed to define subset types.
8pub trait InhabitedInvariant: Invariant + Sized {
9 #[logic]
10 #[ensures(result.invariant())]
11 fn inhabits() -> Self;
12}
13
14/// A _subset_ type.
15///
16/// This the same as `T`, with one exception: the invariant for `T` will also
17/// be verified in logic.
18///
19/// # Example
20///
21/// ```
22/// # use creusot_std::{invariant::{InhabitedInvariant, Subset}, prelude::*};
23/// struct Pair(i32);
24/// impl Invariant for Pair {
25/// #[logic] fn invariant(self) -> bool { self.0 % 2 == 0 }
26/// }
27/// impl InhabitedInvariant for Pair {
28/// #[logic]
29/// #[ensures(result.invariant())]
30/// fn inhabits() -> Self { Self(0i32) }
31/// }
32///
33/// #[logic]
34/// fn pair_in_logic(x: Subset<Pair>) {
35/// proof_assert!(x.0 % 2 == 0);
36/// }
37/// ```
38#[repr(transparent)]
39#[opaque]
40pub struct Subset<T: InhabitedInvariant>(T);
41
42impl<T: InhabitedInvariant + DeepModel> DeepModel for Subset<T> {
43 type DeepModelTy = T::DeepModelTy;
44
45 #[logic(inline)]
46 fn deep_model(self) -> T::DeepModelTy {
47 pearlite! { self.inner().deep_model() }
48 }
49}
50
51impl<T: InhabitedInvariant> Subset<T> {
52 #[trusted]
53 #[logic(opaque)]
54 #[ensures(result.invariant())]
55 pub fn inner(self) -> T {
56 dead
57 }
58
59 /// Create a new element of `Subset<T>` in logic.
60 ///
61 /// As per the [documentation of Subset](Subset), the returned value will
62 /// satisfy `T`'s type invariant.
63 #[trusted]
64 #[logic(opaque)]
65 #[requires(x.invariant())]
66 #[ensures(result.inner() == x)]
67 pub fn new_logic(x: T) -> Self {
68 let _ = x;
69 dead
70 }
71
72 /// Characterize that `Subset<T>` indeed contains a `T` (and only a `T`).
73 ///
74 /// # Example
75 ///
76 /// ```
77 /// # use creusot_std::{invariant::Subset, prelude::*};
78 /// #[requires(x == y.inner())]
79 /// fn foo<T: InhabitedInvariant>(x: T, y: Subset<T>) {
80 /// let x = Subset::new(x);
81 /// let _ = snapshot!(Subset::<T>::inner_inj);
82 /// proof_assert!(x == y);
83 /// }
84 /// ```
85 #[trusted]
86 #[logic(opaque)]
87 #[requires(self.inner() == other.inner())]
88 #[ensures(self == other)]
89 pub fn inner_inj(self, other: Self) {}
90
91 /// Create a new element of `Subset<T>`.
92 ///
93 /// # Example
94 ///
95 /// ```
96 /// # use creusot_std::{invariant::{InhabitedInvariant, Subset}, prelude::*};
97 /// // Use the `Pair` type defined in `Subset`'s documentation
98 /// # struct Pair(i32);
99 /// # impl Invariant for Pair {
100 /// # #[logic] fn invariant(self) -> bool { self.0 % 2 == 0 } }
101 /// # impl InhabitedInvariant for Pair {
102 /// # #[logic] #[ensures(result.invariant())]
103 /// # fn inhabits() -> Self { Self(0i32) } }
104 ///
105 /// let p = Subset::new(Pair(0));
106 /// proof_assert!(p.inner().0 == 0i32);
107 /// ```
108 #[check(ghost)]
109 #[trusted]
110 #[ensures(result == Self::new_logic(x))]
111 pub fn new(x: T) -> Self {
112 Subset(x)
113 }
114
115 /// Unwrap the `Subset` to get the inner value.
116 ///
117 /// # Example
118 ///
119 /// ```
120 /// # use creusot_std::{invariant::{InhabitedInvariant, Subset}, prelude::*};
121 /// // Use the `Pair` type defined in `Subset`'s documentation
122 /// # struct Pair(i32);
123 /// # impl Invariant for Pair {
124 /// # #[logic] fn invariant(self) -> bool { self.0 % 2 == 0 } }
125 /// # impl InhabitedInvariant for Pair {
126 /// # #[logic] #[ensures(result.invariant())]
127 /// # fn inhabits() -> Self { Self(0i32) } }
128 ///
129 /// fn changes_pair(p: &mut Subset<Pair>) { /* ... */ }
130 ///
131 /// let mut p = Subset::new(Pair(0));
132 /// changes_pair(&mut p);
133 /// let inner = p.into_inner();
134 /// proof_assert!(inner.0 % 2 == 0);
135 /// ```
136 #[check(ghost)]
137 #[trusted]
138 #[ensures(result == self.inner())]
139 pub fn into_inner(self) -> T {
140 self.0
141 }
142}
143
144impl<T: InhabitedInvariant> Deref for Subset<T> {
145 type Target = T;
146
147 #[check(ghost)]
148 #[trusted]
149 #[ensures(*result == self.inner())]
150 fn deref(&self) -> &Self::Target {
151 &self.0
152 }
153}
154
155impl<T: InhabitedInvariant> DerefMut for Subset<T> {
156 #[check(ghost)]
157 #[trusted]
158 #[ensures(*result == self.inner())]
159 #[ensures(^result == (^self).inner())]
160 fn deref_mut(&mut self) -> &mut Self::Target {
161 &mut self.0
162 }
163}
164
165impl<T: InhabitedInvariant + Clone> Clone for Subset<T> {
166 #[ensures(T::clone.postcondition((&(self.inner()),), result.inner()))]
167 fn clone(&self) -> Self {
168 snapshot! { Self::inner_inj };
169 Self::new(self.deref().clone())
170 }
171}
172
173impl<T: InhabitedInvariant + Copy> Copy for Subset<T> {}
174
175impl<T: InhabitedInvariant> Resolve for Subset<T> {
176 #[logic(open, prophetic, inline)]
177 fn resolve(self) -> bool {
178 pearlite! { resolve(self.inner()) }
179 }
180
181 #[trusted]
182 #[logic(prophetic)]
183 #[requires(structural_resolve(self))]
184 #[ensures(self.resolve())]
185 fn resolve_coherence(self) {}
186}
187
188impl<T: InhabitedInvariant + DeepModel + PartialEq> PartialEq for Subset<T> {
189 #[trusted]
190 #[ensures(result == (self.deep_model() == rhs.deep_model()))]
191 fn eq(&self, rhs: &Self) -> bool {
192 self.0 == rhs.0
193 }
194}
195
196impl<T: InhabitedInvariant + DeepModel + Eq> Eq for Subset<T> {}