Strings
Verus supports reasoning about Rust String
and &str
:
fn get_char() {
let x = "hello world";
proof {
reveal_strlit("hello world");
}
assert(x@.len() == 11);
let val = x.get_char(0);
assert('h' === val);
}
By default a string literal is treated as opaque,
fn opaque_by_default() {
let x = "hello world";
assert(x@.len() == 11); // FAILS
}
this code results in a failed assertion:
error: assertion failed
--> ../examples/guide/strings.rs:21:12
|
21 | assert(x@.len() == 11); // FAILS
| ^^^^^^^^^^^^^^ assertion failed
which can be fixed by using reveal_strlit
(like in the
example at the top).
However, comparing for equality does not require revealing literals:
fn literal_eq() {
let x = "hello world";
let y = "hello world";
assert(x@ == y@);
}
A string literal is a &str
and its view is a Seq<char>
,
fn str_view() {
let x = "hello world";
let ghost y: Seq<char> = x@;
}
whose value is unkown until the literal is revealed.
One can of course specify information about the view in, e.g., a function precondition (or some other predicate);
fn subrange<'a>(s: &str)
requires
s@ =~= "Hello"@,
{
assert(s@.subrange(0, 1) == "H"@);
}
however, we need to reveal both literals to obtain information about their views in this case:
fn subrange<'a>(s: &str)
requires s@ =~= "Hello"@,
{
proof {
reveal_strlit("Hello");
reveal_strlit("H");
}
assert(s@.subrange(0, 1) =~= "H"@);
}
Operating on strings currently requires the operations defined in vstd::strings
documented here.
An important predicate for &str
and String
is is_ascii
,
which enables efficient slicing, for example:
fn test() {
let a = String::from_str(("ABC"));
proof {
reveal_strlit("ABC");
}
assert(a.is_ascii());
let b = a.as_str().substring_ascii(2, 3);
proof {
reveal_strlit("C");
}
assert(b@ =~= ("C")@);
}