vest_lib/core/exec/
output.rs1#[cfg(feature = "alloc")]
3use alloc::vec::Vec;
4use vstd::prelude::*;
5
6verus! {
7
8pub assume_specification<T>[ <[T]>::split_at_mut_unchecked ](slice: &mut [T], mid: usize) -> (ret: (
12 &mut [T],
13 &mut [T],
14))
15 requires
16 mid <= old(slice)@.len(),
17 ensures
18 ret.0@ == old(slice)@[0..mid],
19 ret.1@ == old(slice)@[mid..],
20 final(slice)@ == final(ret.0)@ + final(ret.1)@,
21;
22
23pub trait OutputBuf: View<V = Seq<u8>> {
28 spec fn fits(&self, len: nat) -> bool;
30
31 broadcast proof fn lemma_fits_mono(&self, shorter: nat, longer: nat)
33 requires
34 shorter <= longer,
35 self.fits(longer),
36 ensures
37 #![all_triggers]
38 self.fits(shorter),
39 ;
40
41 #[verifier::prophetic]
46 spec fn same_destination(&self, other: &Self) -> bool;
47
48 broadcast proof fn lemma_same_destination_reflexive(&self)
50 ensures
51 #[trigger] self.same_destination(self),
52 ;
53
54 broadcast proof fn lemma_same_destination_transitive(&self, middle: &Self, last: &Self)
56 requires
57 self.same_destination(middle),
58 middle.same_destination(last),
59 ensures
60 #![all_triggers]
61 self.same_destination(last),
62 ;
63
64 fn write_byte(&mut self, byte: u8)
66 requires
67 old(self).fits(1),
68 ensures
69 final(self)@ == old(self)@.push(byte),
70 forall|n| old(self).fits(1 + n) <==> #[trigger] final(self).fits(n),
71 old(self).same_destination(final(self)),
72 ;
73
74 fn write_bytes(&mut self, bytes: &[u8])
76 requires
77 old(self).fits(bytes@.len()),
78 ensures
79 final(self)@ == old(self)@ + bytes@,
80 forall|n| old(self).fits(bytes@.len() + n) <==> #[trigger] final(self).fits(n),
81 old(self).same_destination(final(self)),
82 {
83 broadcast use OutputBuf::lemma_same_destination_reflexive;
84
85 let ghost initial_view = self@;
86 for byte in iter: bytes.iter()
87 invariant
88 self@ == initial_view + bytes@[0..iter.index()],
89 old(self).fits(bytes@.len()),
90 forall|n| old(self).fits(iter.index() as nat + n) <==> #[trigger] self.fits(n),
91 old(self).same_destination(self),
92 {
93 broadcast use OutputBuf::lemma_same_destination_transitive;
94
95 proof {
96 old(self).lemma_fits_mono(iter.index() as nat + 1, bytes@.len());
97 assert(self.fits(1));
98 }
99 self.write_byte(*byte);
100 }
101 }
102
103 fn write_array<const N: usize>(&mut self, bytes: &[u8; N])
108 requires
109 old(self).fits(bytes@.len()),
110 ensures
111 final(self)@ == old(self)@ + bytes@,
112 forall|n| old(self).fits(bytes@.len() + n) <==> #[trigger] final(self).fits(n),
113 old(self).same_destination(final(self)),
114 {
115 self.write_bytes(bytes)
116 }
117}
118
119pub struct OutputSlice<'a> {
123 pub obuf: &'a mut [u8],
124 pub pos: usize,
125}
126
127impl View for OutputSlice<'_> {
128 type V = Seq<u8>;
129
130 open spec fn view(&self) -> Self::V {
131 self.obuf@[0..self.pos]
132 }
133}
134
135impl<'a> OutputSlice<'a> {
136 #[verifier::prophetic]
138 pub open spec fn final_destination(&self) -> Seq<u8> {
139 final(self.obuf)@
140 }
141
142 pub fn new(obuf: &'a mut [u8]) -> (output: Self)
144 ensures
145 output@ == Seq::empty(),
146 output.fits(old(obuf)@.len()),
147 forall|len: nat| #[trigger] output.fits(len) == (len <= old(obuf)@.len()),
148 output.final_destination() == final(obuf)@,
149 {
150 Self { obuf, pos: 0 }
151 }
152}
153
154impl OutputBuf for OutputSlice<'_> {
155 open spec fn fits(&self, len: nat) -> bool {
156 self.pos as nat + len <= self.obuf@.len()
157 }
158
159 proof fn lemma_fits_mono(&self, shorter: nat, longer: nat) {
160 }
161
162 #[verifier::prophetic]
163 open spec fn same_destination(&self, other: &Self) -> bool {
164 self.final_destination() == other.final_destination()
165 }
166
167 proof fn lemma_same_destination_reflexive(&self) {
168 }
169
170 proof fn lemma_same_destination_transitive(&self, _middle: &Self, _last: &Self) {
171 }
172
173 fn write_byte(&mut self, byte: u8) {
174 assert(self.pos < self.obuf.len());
175 self.obuf[self.pos] = byte;
176 self.pos += 1;
177 }
178
179 #[inline(always)]
180 fn write_array<const N: usize>(&mut self, bytes: &[u8; N]) {
181 let ghost old_view = self@;
182 let old_pos = self.pos;
183 assert(old_pos + N <= self.obuf.len());
184 {
185 let (_prefix, rest) = unsafe { self.obuf.split_at_mut_unchecked(old_pos) };
186 let (destination, _suffix) = unsafe { rest.split_at_mut_unchecked(N) };
187 destination.copy_from_slice(bytes);
188 }
189 self.pos = old_pos + N;
190 assert(self@ == old_view + bytes@);
191 }
192
193 #[inline(always)]
194 fn write_bytes(&mut self, bytes: &[u8]) {
195 let ghost old_view = self@;
196 let old_pos = self.pos;
197 let len = bytes.len();
198 assert(old_pos + len <= self.obuf.len());
199 {
200 let (_prefix, rest) = unsafe { self.obuf.split_at_mut_unchecked(old_pos) };
206 let (destination, _suffix) = unsafe { rest.split_at_mut_unchecked(len) };
207 destination.copy_from_slice(bytes);
208 }
209 self.pos = old_pos + len;
210 assert(self@ == old_view + bytes@);
211 }
212}
213
214#[cfg(feature = "alloc")]
215impl OutputBuf for Vec<u8> {
216 open spec fn fits(&self, _len: nat) -> bool {
217 true
218 }
219
220 proof fn lemma_fits_mono(&self, _shorter: nat, _longer: nat) {
221 }
222
223 #[verifier::prophetic]
224 open spec fn same_destination(&self, _other: &Self) -> bool {
225 true
226 }
227
228 proof fn lemma_same_destination_reflexive(&self) {
229 }
230
231 proof fn lemma_same_destination_transitive(&self, _middle: &Self, _last: &Self) {
232 }
233
234 fn write_byte(&mut self, byte: u8) {
235 self.push(byte);
236 }
237
238 fn write_bytes(&mut self, bytes: &[u8]) {
239 self.extend_from_slice(bytes);
240 }
241}
242
243pub broadcast group outbuf_lemmas {
244 OutputBuf::lemma_fits_mono,
245 OutputBuf::lemma_same_destination_reflexive,
246 OutputBuf::lemma_same_destination_transitive,
247}
248
249}