Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verus snapshot update #97

Merged
merged 1 commit into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions examples/verus-snapshot/source/vstd/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ pub struct InvCell<T> {
}

impl<T> InvCell<T> {
pub closed spec fn wf(&self) -> bool {
#[verifier::type_invariant]
closed spec fn wf(&self) -> bool {
&&& [email protected]() === (self.possible_values@, self.pcell)
}

Expand All @@ -321,7 +322,7 @@ impl<T> InvCell<T> {
requires
f(val),
ensures
cell.wf() && forall|v| f(v) <==> cell.inv(v),
forall|v| f(v) <==> cell.inv(v),
{
let (pcell, Tracked(perm)) = PCell::new(val);
let ghost possible_values = Set::new(f);
Expand All @@ -333,10 +334,13 @@ impl<T> InvCell<T> {
impl<T> InvCell<T> {
pub fn replace(&self, val: T) -> (old_val: T)
requires
self.wf() && self.inv(val),
self.inv(val),
ensures
self.inv(old_val),
{
proof {
use_type_invariant(self);
}
let r;
open_local_invariant!(self.perm_inv.borrow() => perm => {
r = self.pcell.replace(Tracked(&mut perm), val);
Expand All @@ -347,11 +351,12 @@ impl<T> InvCell<T> {

impl<T: Copy> InvCell<T> {
pub fn get(&self) -> (val: T)
requires
self.wf(),
ensures
self.inv(val),
{
proof {
use_type_invariant(self);
}
let r;
open_local_invariant!(self.perm_inv.borrow() => perm => {
r = *self.pcell.borrow(Tracked(&perm));
Expand Down
228 changes: 228 additions & 0 deletions examples/verus-snapshot/source/vstd/hash_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// altered from HashMap
use core::marker;
use std::borrow::Borrow;

#[allow(unused_imports)]
use super::pervasive::*;
use super::prelude::*;
#[allow(unused_imports)]
use super::set::*;
#[cfg(verus_keep_ghost)]
use super::std_specs::hash::obeys_key_model;
#[allow(unused_imports)]
use core::hash::Hash;
use std::collections::HashSet;

verus! {

#[verifier::ext_equal]
#[verifier::reject_recursive_types(Key)]
pub struct HashSetWithView<Key> where Key: View + Eq + Hash {
m: HashSet<Key>,
}

impl<Key> View for HashSetWithView<Key> where Key: View + Eq + Hash {
type V = Set<<Key as View>::V>;

closed spec fn view(&self) -> Self::V;
}

impl<Key> HashSetWithView<Key> where Key: View + Eq + Hash {
#[verifier::external_body]
pub fn new() -> (result: Self)
requires
obeys_key_model::<Key>(),
forall|k1: Key, k2: Key| k1@ == k2@ ==> k1 == k2,
ensures
result@ == Set::<<Key as View>::V>::empty(),
{
Self { m: HashSet::new() }
}

#[verifier::external_body]
pub fn with_capacity(capacity: usize) -> (result: Self)
requires
obeys_key_model::<Key>(),
forall|k1: Key, k2: Key| k1@ == k2@ ==> k1 == k2,
ensures
result@ == Set::<<Key as View>::V>::empty(),
{
Self { m: HashSet::with_capacity(capacity) }
}

#[verifier::external_body]
pub fn reserve(&mut self, additional: usize)
ensures
self@ == old(self)@,
{
self.m.reserve(additional);
}

pub open spec fn spec_len(&self) -> usize;

#[verifier::external_body]
#[verifier::when_used_as_spec(spec_len)]
pub fn len(&self) -> (result: usize)
ensures
result == [email protected](),
{
self.m.len()
}

#[verifier::external_body]
pub fn insert(&mut self, k: Key) -> (result: bool)
ensures
self@ == old(self)@.insert(k@) && result == !old(self)@.contains(k@),
{
self.m.insert(k)
}

#[verifier::external_body]
pub fn remove(&mut self, k: &Key) -> (result: bool)
ensures
self@ == old(self)@.remove(k@) && result == old(self)@.contains(k@),
{
self.m.remove(k)
}

#[verifier::external_body]
pub fn contains(&self, k: &Key) -> (result: bool)
ensures
result == [email protected](k@),
{
self.m.contains(k)
}

#[verifier::external_body]
pub fn get<'a>(&'a self, k: &Key) -> (result: Option<&'a Key>)
ensures
match result {
Some(v) => [email protected](k@) && v == &k,
None => [email protected](k@),
},
{
self.m.get(k)
}

#[verifier::external_body]
pub fn clear(&mut self)
ensures
self@ == Set::<<Key as View>::V>::empty(),
{
self.m.clear()
}
}

pub broadcast proof fn axiom_hash_set_with_view_spec_len<Key>(m: &HashSetWithView<Key>) where
Key: View + Eq + Hash,

ensures
#[trigger] m.spec_len() == [email protected](),
{
admit();
}

#[verifier::ext_equal]
pub struct StringHashSet {
m: HashSet<String>,
}

impl View for StringHashSet {
type V = Set<Seq<char>>;

closed spec fn view(&self) -> Self::V;
}

impl StringHashSet {
#[verifier::external_body]
pub fn new() -> (result: Self)
ensures
result@ == Set::<Seq<char>>::empty(),
{
Self { m: HashSet::new() }
}

#[verifier::external_body]
pub fn with_capacity(capacity: usize) -> (result: Self)
ensures
result@ == Set::<Seq<char>>::empty(),
{
Self { m: HashSet::with_capacity(capacity) }
}

#[verifier::external_body]
pub fn reserve(&mut self, additional: usize)
ensures
self@ == old(self)@,
{
self.m.reserve(additional);
}

pub open spec fn spec_len(&self) -> usize;

#[verifier::external_body]
#[verifier::when_used_as_spec(spec_len)]
pub fn len(&self) -> (result: usize)
ensures
result == [email protected](),
{
self.m.len()
}

#[verifier::external_body]
pub fn insert(&mut self, k: String) -> (result: bool)
ensures
self@ == old(self)@.insert(k@) && result == !old(self)@.contains(k@),
{
self.m.insert(k)
}

#[verifier::external_body]
pub fn remove(&mut self, k: &str) -> (result: bool)
ensures
self@ == old(self)@.remove(k@) && result == old(self)@.contains(k@),
{
self.m.remove(k)
}

#[verifier::external_body]
pub fn contains(&self, k: &str) -> (result: bool)
ensures
result == [email protected](k@),
{
self.m.contains(k)
}

#[verifier::external_body]
pub fn get<'a>(&'a self, k: &str) -> (result: Option<&'a String>)
ensures
match result {
Some(v) => [email protected](k@) && v@ == k@,
None => [email protected](k@),
},
{
self.m.get(k)
}

#[verifier::external_body]
pub fn clear(&mut self)
ensures
self@ == Set::<Seq<char>>::empty(),
{
self.m.clear()
}
}

pub broadcast proof fn axiom_string_hash_set_spec_len(m: &StringHashSet)
ensures
#[trigger] m.spec_len() == [email protected](),
{
admit();
}

pub broadcast group group_hash_set_axioms {
axiom_hash_set_with_view_spec_len,
axiom_string_hash_set_spec_len,
}

} // verus!
6 changes: 1 addition & 5 deletions examples/verus-snapshot/source/vstd/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,11 +528,7 @@ pub use open_atomic_invariant_internal;
/// boundaries, every `proof` and `exec` function has, as part of its specification,
/// the set of invariant namespaces that it might open.
///
/// UNDER CONSTRUCTION: right now the forms of these specifications are somewhat limited
/// and we expect to expand them.
///
/// The invariant set of a function can be specified by putting either
/// `opens_invariants none` or `opens_invariants any` in the function signature.
/// The invariant set of a function can be specified via the [`opens_invariants` clause](https://verus-lang.github.io/verus/guide/reference-opens-invariants.html).
/// The default for an `exec`-mode function is to open any, while the default
/// for a `proof`-mode function is to open none.
///
Expand Down
4 changes: 4 additions & 0 deletions examples/verus-snapshot/source/vstd/modes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ pub proof fn tracked_swap<V>(tracked a: &mut V, tracked b: &mut V)
unimplemented!();
}

/// Make any tracked object permanently shared and get a reference to it.
///
/// Tip: If you try to use this and run into problems relating to the introduction
/// of a lifetime variable, you want to try [`Shared`](crate::shared::Shared) instead.
#[verifier::external_body]
pub proof fn tracked_static_ref<V>(tracked v: V) -> (tracked res: &'static V)
ensures
Expand Down
14 changes: 12 additions & 2 deletions examples/verus-snapshot/source/vstd/raw_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ pub tracked struct PointsTo<T> {
// variant names like Uninit/Init.)
#[verifier::accept_recursive_types(T)]
pub ghost enum MemContents<T> {
/// Represents uninitialized memory
Uninit,
/// Represents initialized memory with the given value
Init(T),
}

Expand Down Expand Up @@ -169,20 +171,25 @@ impl<T> PointsTo<T> {
}

#[verifier::inline]
#[doc(verus_show_body)]
pub open spec fn is_init(&self) -> bool {
self.opt_value().is_init()
}

#[verifier::inline]
#[doc(verus_show_body)]
pub open spec fn is_uninit(&self) -> bool {
self.opt_value().is_uninit()
}

#[verifier::inline]
#[doc(verus_show_body)]
pub open spec fn value(&self) -> T {
self.opt_value().value()
}

/// Guarantee that the `PointsTo` for any non-zero-sized type points to a non-null address.
///
// ZST pointers *are* allowed to be null, so we need a precondition that size != 0.
// See https://doc.rust-lang.org/std/ptr/#safety
#[verifier::external_body]
Expand All @@ -195,8 +202,11 @@ impl<T> PointsTo<T> {
unimplemented!();
}

/// "De-initialize" the memory by setting it to MemContents::Uninit
/// This is actually a pure no-op; we're just forgetting that the contents are there.
/// "Forgets" about the value stored behind the pointer.
/// Updates the `PointsTo` value to [`MemContents::Uninit`](MemContents::Uninit).
/// Note that this is a `proof` function, i.e.,
/// it is operationally a no-op in executable code, even on the Rust Abstract Machine.
/// Only the proof-code representation changes.
#[verifier::external_body]
pub proof fn leak_contents(tracked &mut self)
ensures
Expand Down
Loading