Struct creusot_contracts::logic::FMap
source · pub struct FMap<K, V: ?Sized>(/* private fields */);
Expand description
A finite map type usable in pearlite and ghost!
blocks.
If you need an infinite map, see Mapping
.
§Ghost
Since std::collections::HashMap
and std::collections::BTreeMap
have finite
capacity, this could cause some issues in ghost code:
ghost! {
let mut map = HashMap::new();
for _ in 0..=usize::MAX as u128 + 1 {
map.insert(0, 0); // cannot fail, since we are in a ghost block
}
proof_assert!(map.len() <= usize::MAX@); // by definition
proof_assert!(map.len() > usize::MAX@); // uh-oh
}
This type is designed for this use-case, with no restriction on the capacity.
Implementations§
source§impl<K, V: ?Sized> FMap<K, V>
impl<K, V: ?Sized> FMap<K, V>
Logical definitions
sourcepub fn empty() -> Self
pub fn empty() -> Self
Returns the empty map.
logic ⚠
ensures
result.len() == 0
ensures
result.view() == Mapping::cst(None)
sourcepub fn len(self) -> Int
pub fn len(self) -> Int
The number of elements in the map, also called its length.
logic ⚠
ensures
result >= 0
sourcepub fn view(self) -> Mapping<K, Option<SizedW<V>>>
pub fn view(self) -> Mapping<K, Option<SizedW<V>>>
View of the map
This represents the actual content of the map: other methods are specified relative to this.
logic ⚠
ensures
forall<m1: Self, m2: Self> m1 != m2 ==> Self::view(m1) != Self::view(m2)
sourcepub fn insert(self, k: K, v: V) -> Self
pub fn insert(self, k: K, v: V) -> Self
Returns a new map, where the key-value pair (k, v)
have been inserted.
logic ⚠
ensures
result.view() == self.view().set(k, Some(v.make_sized()))
ensures
self.contains(k) ==> result.len() == self.len()
ensures
!self.contains(k) ==> result.len() == self.len() + 1
sourcepub fn remove(self, k: K) -> Self
pub fn remove(self, k: K) -> Self
Returns a new map, where the key k
is no longer present.
logic ⚠
ensures
result.view() == self.view().set(k, None)
ensures
result.len() == if self.contains(k) {self.len() - 1} else {self.len()}
sourcepub fn get(self, k: K) -> Option<V>where
V: Sized,
pub fn get(self, k: K) -> Option<V>where
V: Sized,
Get the value associated with key k
in the map.
If no value is present, returns None
.
logic
match self.get_unsized(k) { None => None, Some(x) => Some(*x), }
sourcepub fn get_unsized(self, k: K) -> Option<SizedW<V>>
pub fn get_unsized(self, k: K) -> Option<SizedW<V>>
Same as Self::get
, but can handle unsized values.
logic
self.view().get(k)
sourcepub fn lookup(self, k: K) -> Vwhere
V: Sized,
pub fn lookup(self, k: K) -> Vwhere
V: Sized,
Get the value associated with key k
in the map.
If no value is present, the returned value is meaningless.
logic
*self.lookup_unsized(k)
sourcepub fn lookup_unsized(self, k: K) -> SizedW<V>
pub fn lookup_unsized(self, k: K) -> SizedW<V>
Same as Self::lookup
, but can handle unsized values.
logic
unwrap(self.get_unsized(k))
sourcepub fn contains(self, k: K) -> bool
pub fn contains(self, k: K) -> bool
Returns true
if the map contains a value for the specified key.
logic
self.get_unsized(k) != None
sourcepub fn is_empty(self) -> bool
pub fn is_empty(self) -> bool
Returns true
if the map contains no elements.
logic
self.ext_eq(FMap::empty())
sourcepub fn disjoint(self, other: Self) -> bool
pub fn disjoint(self, other: Self) -> bool
Returns true
if the two maps have no key in common.
logic
pearlite! {forall<k: K> !self.contains(k) || !other.contains(k)}
sourcepub fn subset(self, other: Self) -> bool
pub fn subset(self, other: Self) -> bool
Returns true
if all key-value pairs in self
are also in other
.
logic
pearlite! { forall<k: K> self.contains(k) ==> other.get_unsized(k) == self.get_unsized(k) }
sourcepub fn union(self, other: Self) -> Self
pub fn union(self, other: Self) -> Self
Returns a new map, which is the union of self
and other
.
If self
and other
are not disjoint
, the result is unspecified.
logic ⚠
requires
self.disjoint(other)
ensures
forall<k: K> result.get_unsized(k) == if self.contains(k) { self.get_unsized(k) } else if other.contains(k) { other.get_unsized(k) } else { None }
ensures
result.len() == self.len() + other.len()
sourcepub fn subtract_keys(self, other: Self) -> Self
pub fn subtract_keys(self, other: Self) -> Self
Returns a new map, that contains all the key-value pairs of self
such that the
key is not in other
.
logic ⚠
ensures
forall<k: K> result.get_unsized(k) == if other.contains(k) { None } else { self.get_unsized(k) }
sourcepub fn subtract(self, other: Self) -> Self
pub fn subtract(self, other: Self) -> Self
Same as Self::subtract_keys
, but the result is meaningless if other
is not
a subset
of self
.
In return, this gives more guarantees than Self::subtract_keys
.
logic
self.subtract_keys(other)
requires
other.subset(self)
ensures
result.disjoint(other)
ensures
other.union(result).ext_eq(self)
ensures
forall<k: K> result.get_unsized(k) == if other.contains(k) { None } else { self.get_unsized(k) }
sourcepub fn ext_eq(self, other: Self) -> bool
pub fn ext_eq(self, other: Self) -> bool
Extensional equality.
Returns true
if self
and other
contain exactly the same key-value pairs.
This is in fact equivalent with normal equality.
logic
self.view() == other.view()
ensures
result ==> self == other
ensures
(forall<k: K> self.get_unsized(k) == other.get_unsized(k)) ==> result
source§impl<K, V: ?Sized> FMap<K, V>
impl<K, V: ?Sized> FMap<K, V>
Ghost definitions
sourcepub fn new() -> GhostBox<Self>
pub fn new() -> GhostBox<Self>
Create a new, empty map on the ghost heap.
pure
ensures
result.is_empty()
sourcepub fn len_ghost(&self) -> Int
pub fn len_ghost(&self) -> Int
Returns the number of elements in the map.
If you need to get the length in pearlite, consider using len
.
§Example
use creusot_contracts::{logic::FMap, *};
let mut map = FMap::new();
ghost! {
let len1 = map.len_ghost();
map.insert_ghost(1, 21);
map.insert_ghost(1, 42);
map.insert_ghost(2, 50);
let len2 = map.len_ghost();
proof_assert!(len1 == 0);
proof_assert!(len2 == 2);
};
pure
ensures
result == self.len()
sourcepub fn contains_ghost(&self, key: &K) -> bool
pub fn contains_ghost(&self, key: &K) -> bool
Returns true if the map contains a value for the specified key.
§Example
use creusot_contracts::{logic::FMap, *};
let mut map = FMap::new();
ghost! {
map.insert_ghost(1, 42);
let (b1, b2) = (map.contains_ghost(&1), map.contains_ghost(&2));
proof_assert!(b1);
proof_assert!(!b2);
};
pure
ensures
result == self.contains(*key)
sourcepub fn get_ghost(&self, key: &K) -> Option<&V>
pub fn get_ghost(&self, key: &K) -> Option<&V>
Returns a reference to the value corresponding to the key.
§Example
use creusot_contracts::{logic::FMap, *};
let mut map = FMap::new();
ghost! {
map.insert_ghost(1, 2);
let x1 = map.get_ghost(&1);
let x2 = map.get_ghost(&2);
proof_assert!(x1 == Some(&2));
proof_assert!(x2 == None);
};
pure
ensures
if self.contains(*key) { match result { None => false, Some(r) => *self.lookup_unsized(*key) == *r, } } else { result == None }
sourcepub fn get_mut_ghost(&mut self, key: &K) -> Option<&mut V>
pub fn get_mut_ghost(&mut self, key: &K) -> Option<&mut V>
Returns a mutable reference to the value corresponding to the key.
§Example
use creusot_contracts::{logic::FMap, *};
let mut map = FMap::new();
ghost! {
map.insert_ghost(1, 21);
if let Some(x) = map.get_mut_ghost(&1) {
*x = 42;
}
proof_assert!(map.lookup(1i32) == 42i32);
};
pure
ensures
if self.contains(*key) { match result { None => false, Some(r) => (^self).contains(*key) && *(*self).lookup_unsized(*key) == *r && *(^self).lookup_unsized(*key) == ^r, } } else { result == None && *self == ^self }
ensures
forall<k: K> k != *key ==> (*self).get_unsized(k) == (^self).get_unsized(k)
ensures
(*self).len() == (^self).len()
sourcepub fn insert_ghost(&mut self, key: K, value: V) -> Option<V>where
V: Sized,
pub fn insert_ghost(&mut self, key: K, value: V) -> Option<V>where
V: Sized,
Inserts a key-value pair into the map.
If the map did not have this key present, None
is returned.
§Example
use creusot_contracts::{logic::FMap, *};
let mut map = FMap::new();
ghost! {
let res1 = map.insert_ghost(37, 41);
proof_assert!(res1 == None);
proof_assert!(map.is_empty() == false);
let res2 = map.insert_ghost(37, 42);
proof_assert!(res2 == Some(41));
proof_assert!(map.lookup(37i32) == 42i32);
};
pure
ensures
^self == (*self).insert(key, value)
ensures
result == (*self).get(key)
sourcepub fn insert_ghost_unsized(&mut self, key: K, value: Box<V>) -> Option<Box<V>>
pub fn insert_ghost_unsized(&mut self, key: K, value: Box<V>) -> Option<Box<V>>
Same as Self::insert_ghost
, but for unsized values.
pure
ensures
^self == (*self).insert(key, *value)
ensures
result == (*self).get_unsized(key)
sourcepub fn remove_ghost(&mut self, key: &K) -> Option<V>where
V: Sized,
pub fn remove_ghost(&mut self, key: &K) -> Option<V>where
V: Sized,
Removes a key from the map, returning the value at the key if the key was previously in the map.
§Example
use creusot_contracts::{logic::FMap, *};
let mut map = FMap::new();
let res = ghost! {
map.insert_ghost(1, 42);
let res1 = map.remove_ghost(&1);
let res2 = map.remove_ghost(&1);
proof_assert!(res1 == Some(42i32));
proof_assert!(res2 == None);
};
pure
ensures
^self == (*self).remove(*key)
ensures
result == (*self).get(*key)
sourcepub fn remove_ghost_unsized(&mut self, key: &K) -> Option<Box<V>>
pub fn remove_ghost_unsized(&mut self, key: &K) -> Option<Box<V>>
Same as Self::remove_ghost
, but for unsized values.
pure
ensures
^self == (*self).remove(*key)
ensures
result == (*self).get_unsized(*key)
Trait Implementations§
source§impl<K, V> IndexLogic<K> for FMap<K, V>
impl<K, V> IndexLogic<K> for FMap<K, V>
impl<K: Clone + Copy, V: Clone + Copy> Copy for FMap<K, V>
Auto Trait Implementations§
impl<K, V> Freeze for FMap<K, V>where
V: ?Sized,
impl<K, V> !RefUnwindSafe for FMap<K, V>
impl<K, V> !Send for FMap<K, V>
impl<K, V> !Sync for FMap<K, V>
impl<K, V> !Unpin for FMap<K, V>
impl<K, V> !UnwindSafe for FMap<K, V>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<T> CloneToUninit for Twhere
T: Copy,
impl<T> CloneToUninit for Twhere
T: Copy,
source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<T> MakeSized for Twhere
T: ?Sized,
impl<T> MakeSized for Twhere
T: ?Sized,
source§fn make_sized(&self) -> Box<T>
fn make_sized(&self) -> Box<T>
logic ⚠
ensures
*result == *self