vstd/contrib/exec_spec/
arith.rs1use crate::contrib::exec_spec::*;
31use crate::prelude::*;
32
33#[cfg(verus_keep_ghost)]
34macro_rules! truncating_cast {
35 ($e:expr, $t:ty) => {
36 #[verifier::truncate]
37 ($e as $t)
38 };
39}
40
41#[cfg(not(verus_keep_ghost))]
42macro_rules! truncating_cast {
43 ($e:expr, $t:ty) => {
44 ($e as $t)
45 };
46}
47
48verus! {
49
50pub trait ExecSpecFixedWidthArith: Sized {
51 spec fn spec_fixed_add(self, rhs: Self) -> Self;
52
53 spec fn spec_fixed_sub(self, rhs: Self) -> Self;
54
55 spec fn spec_fixed_mul(self, rhs: Self) -> Self;
56
57 fn exec_fixed_add(self, rhs: Self) -> (res: Self)
58 ensures
59 res == self.spec_fixed_add(rhs),
60 ;
61
62 fn exec_fixed_sub(self, rhs: Self) -> (res: Self)
63 ensures
64 res == self.spec_fixed_sub(rhs),
65 ;
66
67 fn exec_fixed_mul(self, rhs: Self) -> (res: Self)
68 ensures
69 res == self.spec_fixed_mul(rhs),
70 ;
71}
72
73macro_rules! impl_unsigned_fixed_width_arith {
74 ($($t:ty),*) => {
75 $(
76 verus! {
77 impl ExecSpecFixedWidthArith for $t {
78 open spec fn spec_fixed_add(self, rhs: $t) -> $t {
79 add(self, rhs)
80 }
81
82 open spec fn spec_fixed_sub(self, rhs: $t) -> $t {
83 sub(self, rhs)
84 }
85
86 open spec fn spec_fixed_mul(self, rhs: $t) -> $t {
87 mul(self, rhs)
88 }
89
90 #[inline(always)]
91 fn exec_fixed_add(self, rhs: $t) -> (res: $t) {
92 truncating_cast!(self as u128 + rhs as u128, $t)
93 }
94
95 #[inline(always)]
96 fn exec_fixed_sub(self, rhs: $t) -> (res: $t) {
97 truncating_cast!(self as i128 - rhs as i128, $t)
98 }
99
100 #[inline(always)]
101 fn exec_fixed_mul(self, rhs: $t) -> (res: $t) {
102 assert((self as int) * (rhs as int) <= (u64::MAX as int) * (u64::MAX as int))
103 by (nonlinear_arith)
104 requires
105 0 <= self <= u64::MAX,
106 0 <= rhs <= u64::MAX,
107 ;
108 truncating_cast!(self as u128 * rhs as u128, $t)
109 }
110 }
111 }
112 )*
113 };
114}
115
116macro_rules! impl_signed_fixed_width_arith {
117 ($($t:ty),*) => {
118 $(
119 verus! {
120 impl ExecSpecFixedWidthArith for $t {
121 open spec fn spec_fixed_add(self, rhs: $t) -> $t {
122 add(self, rhs)
123 }
124
125 open spec fn spec_fixed_sub(self, rhs: $t) -> $t {
126 sub(self, rhs)
127 }
128
129 open spec fn spec_fixed_mul(self, rhs: $t) -> $t {
130 mul(self, rhs)
131 }
132
133 #[inline(always)]
134 fn exec_fixed_add(self, rhs: $t) -> (res: $t) {
135 truncating_cast!(self as i128 + rhs as i128, $t)
136 }
137
138 #[inline(always)]
139 fn exec_fixed_sub(self, rhs: $t) -> (res: $t) {
140 truncating_cast!(self as i128 - rhs as i128, $t)
141 }
142
143 #[inline(always)]
144 fn exec_fixed_mul(self, rhs: $t) -> (res: $t) {
145 assert(i64::MIN * i64::MIN >= (self as int) * (rhs as int) >= i64::MIN
146 * i64::MAX) by (nonlinear_arith)
147 requires
148 i64::MIN <= self <= i64::MAX,
149 i64::MIN <= rhs <= i64::MAX,
150 ;
151 truncating_cast!(self as i128 * rhs as i128, $t)
152 }
153 }
154 }
155 )*
156 };
157}
158
159impl_unsigned_fixed_width_arith!(u8, u16, u32, u64, usize);
160
161impl_signed_fixed_width_arith!(i8, i16, i32, i64, isize);
162
163#[inline(always)]
164pub fn exec_add<T: ExecSpecFixedWidthArith>(a: T, b: T) -> (res: T)
165 ensures
166 res == a.spec_fixed_add(b),
167{
168 a.exec_fixed_add(b)
169}
170
171#[inline(always)]
172pub fn exec_sub<T: ExecSpecFixedWidthArith>(a: T, b: T) -> (res: T)
173 ensures
174 res == a.spec_fixed_sub(b),
175{
176 a.exec_fixed_sub(b)
177}
178
179#[inline(always)]
180pub fn exec_mul<T: ExecSpecFixedWidthArith>(a: T, b: T) -> (res: T)
181 ensures
182 res == a.spec_fixed_mul(b),
183{
184 a.exec_fixed_mul(b)
185}
186
187}