Skip to content

Commit a8751f2

Browse files
authored
vstd: slice range index mut writeback (#2744)
1 parent 4891526 commit a8751f2

3 files changed

Lines changed: 484 additions & 3 deletions

File tree

source/rust_verify_test/tests/slices.rs

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,319 @@ test_verify_one_file! {
237237
} => Err(err) => assert_fails(err, 8)
238238
}
239239

240+
test_verify_one_file! {
241+
#[test] test_slice_index_range_to verus_code! {
242+
use std::ops::Index;
243+
use vstd::prelude::*;
244+
245+
fn range_to(s: &[u8]) {
246+
assume(s.len() == 5);
247+
let x = &s[..3];
248+
assert(x@ == s@.subrange(0, 3));
249+
assert(x@ == s@.subrange(0, 4)); // FAILS
250+
}
251+
252+
fn range_to_bounds(s: &[u8]) {
253+
assume(s.len() == 5);
254+
let x = &s[..7]; // FAILS
255+
}
256+
257+
fn range_to_index(s: &[u8]) {
258+
assume(s.len() == 5);
259+
let x = s.index(..3);
260+
assert(x@ == s@.subrange(0, 3));
261+
assert(x@ == s@.subrange(0, 4)); // FAILS
262+
}
263+
264+
fn range_to_index_bounds(s: &[u8]) {
265+
assume(s.len() == 5);
266+
let x = s.index(..7); // FAILS
267+
}
268+
} => Err(err) => assert_fails(err, 4)
269+
}
270+
271+
test_verify_one_file! {
272+
#[test] test_slice_index_range_from verus_code! {
273+
use vstd::prelude::*;
274+
275+
fn range_from(s: &[u8]) {
276+
assume(s.len() == 5);
277+
let x = &s[2..];
278+
assert(x@ == s@.subrange(2, 5));
279+
assert(x@ == s@.subrange(1, 5)); // FAILS
280+
}
281+
282+
fn range_from_bounds(s: &[u8]) {
283+
assume(s.len() == 5);
284+
let x = &s[7..]; // FAILS
285+
}
286+
} => Err(err) => assert_fails(err, 2)
287+
}
288+
289+
test_verify_one_file! {
290+
#[test] test_slice_index_range_to_inclusive verus_code! {
291+
use vstd::prelude::*;
292+
293+
fn range_to_inclusive(s: &[u8]) {
294+
assume(s.len() == 5);
295+
let x = &s[..=3];
296+
assert(x@ == s@.subrange(0, 4));
297+
assert(x@ == s@.subrange(0, 3)); // FAILS
298+
}
299+
300+
fn range_to_inclusive_bounds(s: &[u8]) {
301+
assume(s.len() == 5);
302+
let x = &s[..=5]; // FAILS
303+
}
304+
} => Err(err) => assert_fails(err, 2)
305+
}
306+
307+
test_verify_one_file! {
308+
#[test] test_slice_index_range_full verus_code! {
309+
use vstd::prelude::*;
310+
311+
fn range_full(s: &[u8]) {
312+
assume(s.len() == 5);
313+
let x = &s[..];
314+
assert(x@ == s@);
315+
assert(x@.len() == 4); // FAILS
316+
}
317+
} => Err(err) => assert_one_fails(err)
318+
}
319+
320+
test_verify_one_file! {
321+
#[test] test_slice_index_range_inclusive verus_code! {
322+
use vstd::prelude::*;
323+
324+
fn range_inclusive(s: &[u8]) {
325+
assume(s.len() == 5);
326+
let x = &s[1..=3];
327+
assert(x@ == s@.subrange(1, 4));
328+
assert(x@ == s@.subrange(1, 3)); // FAILS
329+
}
330+
331+
fn range_inclusive_bounds(s: &[u8]) {
332+
assume(s.len() == 5);
333+
let x = &s[1..=5]; // FAILS
334+
}
335+
} => Err(err) => assert_fails(err, 2)
336+
}
337+
338+
test_verify_one_file! {
339+
#[test] test_slice_get_ranges verus_code! {
340+
use vstd::prelude::*;
341+
342+
fn range_get(s: &[u8]) {
343+
assume(s.len() == 5);
344+
let some = s.get(1..3);
345+
assert(some.is_some());
346+
assert(some.unwrap()@ == s@.subrange(1, 3));
347+
let none = s.get(1..7);
348+
assert(none.is_none());
349+
}
350+
351+
fn range_to_get(s: &[u8]) {
352+
assume(s.len() == 5);
353+
let some = s.get(..3);
354+
assert(some.is_some());
355+
assert(some.unwrap()@ == s@.subrange(0, 3));
356+
let none = s.get(..7);
357+
assert(none.is_none());
358+
}
359+
360+
fn range_from_get(s: &[u8]) {
361+
assume(s.len() == 5);
362+
let some = s.get(2..);
363+
assert(some.is_some());
364+
assert(some.unwrap()@ == s@.subrange(2, 5));
365+
let none = s.get(7..);
366+
assert(none.is_none());
367+
}
368+
369+
fn range_to_inclusive_get(s: &[u8]) {
370+
assume(s.len() == 5);
371+
let some = s.get(..=3);
372+
assert(some.is_some());
373+
assert(some.unwrap()@ == s@.subrange(0, 4));
374+
let none = s.get(..=7);
375+
assert(none.is_none());
376+
}
377+
378+
fn range_full_get(s: &[u8]) {
379+
assume(s.len() == 5);
380+
let some = s.get(..);
381+
assert(some.is_some());
382+
assert(some.unwrap()@ == s@);
383+
}
384+
385+
fn range_inclusive_get(s: &[u8]) {
386+
assume(s.len() == 5);
387+
let some = s.get(1..=3);
388+
assert(some.is_some());
389+
assert(some.unwrap()@ == s@.subrange(1, 4));
390+
let none = s.get(1..=7);
391+
assert(none.is_none());
392+
}
393+
394+
fn range_get_wrong_fails(s: &[u8]) {
395+
assume(s.len() == 5);
396+
let some = s.get(1..3);
397+
assert(some.unwrap()@ == s@.subrange(1, 4)); // FAILS
398+
}
399+
} => Err(err) => assert_one_fails(err)
400+
}
401+
402+
// Checks the mutable-indexing form (`&mut s[range]`) via the returned
403+
// sub-slice's own view, both before and after writing through it.
404+
test_verify_one_file! {
405+
#[test] test_slice_index_mut_ranges verus_code! {
406+
use vstd::prelude::*;
407+
408+
fn range_index_mut(s: &mut [u8]) {
409+
assume(s.len() == 5);
410+
let sub = &mut s[1..3];
411+
assert(sub@ == old(s)@.subrange(1, 3));
412+
sub[0] = 99;
413+
sub[1] = 88;
414+
assert(sub@ == seq![99, 88]);
415+
}
416+
417+
fn range_to_index_mut(s: &mut [u8]) {
418+
assume(s.len() == 5);
419+
let sub = &mut s[..3];
420+
assert(sub@ == old(s)@.subrange(0, 3));
421+
sub[0] = 99;
422+
assert(sub@[0] == 99);
423+
}
424+
425+
fn range_from_index_mut(s: &mut [u8]) {
426+
assume(s.len() == 5);
427+
let sub = &mut s[2..];
428+
assert(sub@ == old(s)@.subrange(2, 5));
429+
sub[0] = 99;
430+
assert(sub@[0] == 99);
431+
}
432+
433+
fn range_to_inclusive_index_mut(s: &mut [u8]) {
434+
assume(s.len() == 5);
435+
let sub = &mut s[..=3];
436+
assert(sub@ == old(s)@.subrange(0, 4));
437+
sub[3] = 99;
438+
assert(sub@[3] == 99);
439+
}
440+
441+
fn range_full_index_mut(s: &mut [u8]) {
442+
assume(s.len() == 5);
443+
let sub = &mut s[..];
444+
assert(sub@ == old(s)@);
445+
sub[4] = 99;
446+
assert(sub@[4] == 99);
447+
}
448+
449+
fn range_inclusive_index_mut(s: &mut [u8]) {
450+
assume(s.len() == 5);
451+
let sub = &mut s[1..=3];
452+
assert(sub@ == old(s)@.subrange(1, 4));
453+
sub[0] = 99;
454+
assert(sub@[0] == 99);
455+
}
456+
} => Ok(())
457+
}
458+
459+
test_verify_one_file! {
460+
#[test] test_slice_index_mut_ranges_fails verus_code! {
461+
use vstd::prelude::*;
462+
463+
fn range_index_mut_wrong(s: &mut [u8]) {
464+
assume(s.len() == 5);
465+
let sub = &mut s[1..3];
466+
sub[0] = 99;
467+
assert(sub@[0] == 5); // FAILS
468+
}
469+
470+
fn range_index_mut_wrong_len(s: &mut [u8]) {
471+
assume(s.len() == 5);
472+
let sub = &mut s[1..3];
473+
assert(sub@.len() == 3); // FAILS: 1..3 has length 2, not 3
474+
}
475+
} => Err(err) => assert_fails(err, 2)
476+
}
477+
478+
// Writing through a range-indexed mutable sub-slice reborrow, then observing
479+
// the *original* slice's own view after the reborrow's last use.
480+
test_verify_one_file! {
481+
#[test] test_slice_index_mut_range_writeback verus_code! {
482+
use vstd::prelude::*;
483+
484+
fn range_writeback(s: &mut [u8])
485+
requires old(s)@.len() == 5,
486+
ensures final(s)@ == old(s)@.update(1, 99).update(2, 88),
487+
{
488+
let sub = &mut s[1..3];
489+
sub[0] = 99;
490+
sub[1] = 88;
491+
}
492+
493+
fn range_to_writeback(s: &mut [u8])
494+
requires old(s)@.len() == 5,
495+
ensures final(s)@ == old(s)@.update(0, 99).update(1, 88),
496+
{
497+
let sub = &mut s[..2];
498+
sub[0] = 99;
499+
sub[1] = 88;
500+
}
501+
502+
fn range_from_writeback(s: &mut [u8])
503+
requires old(s)@.len() == 5,
504+
ensures final(s)@ == old(s)@.update(3, 99).update(4, 88),
505+
{
506+
let sub = &mut s[3..];
507+
sub[0] = 99;
508+
sub[1] = 88;
509+
}
510+
511+
fn range_to_inclusive_writeback(s: &mut [u8])
512+
requires old(s)@.len() == 5,
513+
ensures final(s)@ == old(s)@.update(0, 99).update(1, 88),
514+
{
515+
let sub = &mut s[..=1];
516+
sub[0] = 99;
517+
sub[1] = 88;
518+
}
519+
520+
fn range_full_writeback(s: &mut [u8])
521+
requires old(s)@.len() == 5,
522+
ensures final(s)@ == old(s)@.update(0, 99).update(4, 88),
523+
{
524+
let sub = &mut s[..];
525+
sub[0] = 99;
526+
sub[4] = 88;
527+
}
528+
529+
fn range_inclusive_writeback(s: &mut [u8])
530+
requires old(s)@.len() == 5,
531+
ensures final(s)@ == old(s)@.update(1, 99).update(3, 88),
532+
{
533+
let sub = &mut s[1..=3];
534+
sub[0] = 99;
535+
sub[2] = 88;
536+
}
537+
} => Ok(())
538+
}
539+
540+
test_verify_one_file! {
541+
#[test] test_slice_index_mut_range_writeback_fails verus_code! {
542+
use vstd::prelude::*;
543+
544+
fn range_writeback_wrong_value(s: &mut [u8]) {
545+
assume(s.len() == 5);
546+
let sub = &mut s[1..3];
547+
sub[0] = 99;
548+
assert(s@[1] == 5); // FAILS
549+
}
550+
} => Err(err) => assert_one_fails(err)
551+
}
552+
240553
test_verify_one_file! {
241554
#[test] test_array_index verus_code! {
242555
use std::ops::Index;

0 commit comments

Comments
 (0)