Skip to main content

vstd/
string.rs

1#![feature(rustc_attrs)]
2#![allow(unused_imports)]
3
4#[cfg(all(feature = "alloc", not(verus_verify_core)))]
5use alloc::str::Chars;
6#[cfg(all(feature = "alloc", not(verus_verify_core)))]
7use alloc::string::{self, String, ToString};
8#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
9use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
10#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
11use core::slice::SliceIndex;
12
13use super::prelude::*;
14use super::seq::Seq;
15use super::slice::*;
16#[cfg(all(verus_keep_ghost, feature = "alloc", not(verus_verify_core)))]
17use super::std_specs::fmt::DisplaySpec;
18#[cfg(verus_keep_ghost)]
19#[cfg(all(feature = "alloc", not(verus_verify_core)))]
20use super::std_specs::iter::IteratorSpec;
21#[cfg(verus_keep_ghost)]
22use super::std_specs::range::{
23    ExRange, RangeBoundsSpec, slice_range_end, slice_range_start, slice_range_valid,
24    spec_range_inclusive_is_empty,
25};
26use super::utf8::*;
27use super::view::*;
28
29#[cfg(verus_keep_ghost)]
30#[cfg(not(verus_verify_core))]
31use super::std_specs::cmp::PartialEqSpecImpl;
32
33verus! {
34
35broadcast use {super::seq::group_seq_lemmas, super::slice::group_slice_axioms};
36
37#[cfg(not(verus_verify_core))]
38impl View for str {
39    type V = Seq<char>;
40
41    uninterp spec fn view(&self) -> Seq<char>;
42}
43
44#[cfg(not(verus_verify_core))]
45impl DeepView for str {
46    type V = Seq<char>;
47
48    open spec fn deep_view(&self) -> Seq<char> {
49        self.view()
50    }
51}
52
53#[cfg(verus_keep_ghost)]
54#[cfg(not(verus_verify_core))]
55impl PartialEqSpecImpl for str {
56    open spec fn obeys_eq_spec() -> bool {
57        true
58    }
59
60    open spec fn eq_spec(&self, other: &str) -> bool {
61        self@ == other@
62    }
63}
64
65#[cfg(not(verus_verify_core))]
66pub trait StringSliceAdditionalSpecFns {
67    spec fn spec_bytes(&self) -> Seq<u8>;
68}
69
70#[cfg(not(verus_verify_core))]
71impl StringSliceAdditionalSpecFns for str {
72    open spec fn spec_bytes(&self) -> Seq<u8> {
73        encode_utf8(self@)
74    }
75}
76
77#[cfg(not(verus_verify_core))]
78pub open spec fn is_ascii(s: &str) -> bool {
79    is_ascii_chars(s@)
80}
81
82#[cfg(not(verus_verify_core))]
83pub broadcast proof fn is_ascii_spec_bytes(s: &str)
84    ensures
85        #[trigger] is_ascii(s) ==> #[trigger] s.spec_bytes() =~= Seq::new(
86            s@.len(),
87            |i| s@.index(i) as u8,
88        ),
89{
90    if (is_ascii(s)) {
91        is_ascii_chars_encode_utf8(s@);
92    }
93}
94
95#[cfg(not(verus_verify_core))]
96pub broadcast proof fn is_ascii_concat(s1: &str, s2: &str, s3: &str)
97    requires
98        s1@ =~= s2@ + s3@,
99    ensures
100        #![trigger s2@ + s3@, is_ascii(s1), is_ascii(s2), is_ascii(s3)]
101        is_ascii(s1) <==> is_ascii(s2) && is_ascii(s3),
102{
103    broadcast use is_ascii_chars_concat;
104
105    if (is_ascii(s1)) {
106        is_ascii_chars_concat(s1@, s2@, s3@);
107    }
108}
109
110#[cfg(not(verus_verify_core))]
111#[verifier::when_used_as_spec(is_ascii)]
112pub assume_specification[ str::is_ascii ](s: &str) -> (b: bool)
113    ensures
114        b == is_ascii(s),
115;
116
117#[cfg(all(feature = "alloc", not(verus_verify_core)))]
118use crate::alloc::borrow::ToOwned;
119
120#[cfg(all(feature = "alloc", not(verus_verify_core)))]
121pub assume_specification[ str::to_owned ](s: &str) -> (res: String)
122    ensures
123        s@ == res@,
124;
125
126#[cfg(not(verus_verify_core))]
127pub assume_specification[ str::as_bytes ](s: &str) -> (b: &[u8])
128    ensures
129        b@ == s.spec_bytes(),
130    opens_invariants none
131    no_unwind
132;
133
134#[cfg(not(verus_verify_core))]
135#[verifier::allow_in_spec]
136pub assume_specification[ str::len ](s: &str) -> usize
137    returns
138        s.spec_bytes().len() as usize,
139    opens_invariants none
140    no_unwind
141;
142
143#[cfg(not(verus_verify_core))]
144#[verifier::allow_in_spec]
145pub assume_specification[ str::is_empty ](s: &str) -> bool
146    returns
147        s@.len() == 0,
148    opens_invariants none
149    no_unwind
150;
151
152#[cfg(not(verus_verify_core))]
153#[verifier::allow_in_spec]
154pub assume_specification[ str::is_char_boundary ](s: &str, index: usize) -> bool
155    returns
156        is_char_boundary(s.spec_bytes(), index as int),
157;
158
159#[cfg(not(verus_verify_core))]
160pub assume_specification[ str::split_at ](s: &str, mid: usize) -> (res: (&str, &str))
161    requires
162        is_char_boundary(s.spec_bytes(), mid as int),
163    ensures
164        res.0.spec_bytes() =~= s.spec_bytes()[..mid],
165        res.1.spec_bytes() =~= s.spec_bytes()[mid..],
166;
167
168#[cfg(not(verus_verify_core))]
169pub assume_specification[ str::from_utf8_unchecked ](v: &[u8]) -> (res: &str)
170    requires
171        valid_utf8(v@),
172    ensures
173        res.spec_bytes() =~= v@,
174;
175
176#[cfg(all(feature = "alloc", not(verus_verify_core)))]
177pub uninterp spec fn to_string_from_display_ensures<T: core::fmt::Display + ?Sized>(
178    t: &T,
179    s: String,
180) -> bool;
181
182#[cfg(all(feature = "alloc", not(verus_verify_core)))]
183pub broadcast proof fn to_string_from_display_ensures_for_str(t: &str, res: String)
184    ensures
185        #[trigger] to_string_from_display_ensures::<str>(t, res) <==> (t@ == res@),
186{
187    admit();
188}
189
190#[cfg(all(feature = "alloc", not(verus_verify_core)))]
191pub assume_specification<T: core::fmt::Display + ?Sized>[ <T as ToString>::to_string ](
192    t: &T,
193) -> (res: String)
194    requires
195        forall|f: &core::fmt::Formatter<'_>| t.fmt_req(f),
196    ensures
197        to_string_from_display_ensures::<T>(t, res),
198;
199
200#[cfg(not(verus_verify_core))]
201#[verifier::external]
202pub trait StrSliceExecFns {
203    fn unicode_len(&self) -> usize;
204
205    fn get_char(&self, i: usize) -> char;
206
207    fn substring_ascii<'a>(&'a self, from: usize, to: usize) -> &'a str;
208
209    fn substring_char<'a>(&'a self, from: usize, to: usize) -> &'a str;
210
211    fn get_ascii(&self, i: usize) -> u8;
212
213    #[cfg(feature = "alloc")]
214    fn as_bytes_vec(&self) -> alloc::vec::Vec<u8>;
215}
216
217#[cfg(not(verus_verify_core))]
218impl StrSliceExecFns for str {
219    /// The len() function in rust returns the byte length.
220    /// It is more useful to talk about the length of characters and therefore this function was added.
221    /// Please note that this function counts the unicode variation selectors as characters.
222    /// Warning: O(n)
223    #[verifier::external_body]
224    fn unicode_len(&self) -> (l: usize)
225        ensures
226            l as nat == self@.len(),
227    {
228        self.chars().count()
229    }
230
231    /// Warning: O(n) not O(1) due to unicode decoding needed
232    #[verifier::external_body]
233    fn get_char(&self, i: usize) -> (c: char)
234        requires
235            i < self@.len(),
236        ensures
237            self@.index(i as int) == c,
238    {
239        self.chars().nth(i).unwrap()
240    }
241
242    #[verifier::external_body]
243    fn substring_ascii<'a>(&'a self, from: usize, to: usize) -> (ret: &'a str)
244        requires
245            self.is_ascii(),
246            from <= to <= self@.len(),
247        ensures
248            ret@ == self@[from..to],
249            ret.is_ascii(),
250    {
251        // Range::index panics if from > to or from > self@.len()
252        &self[from..to]
253    }
254
255    #[verifier::external_body]
256    fn substring_char<'a>(&'a self, from: usize, to: usize) -> (ret: &'a str)
257        requires
258            from <= to <= self@.len(),
259        ensures
260            ret@ == self@[from..to],
261    {
262        let mut char_pos = 0;
263        let mut byte_start = None;
264        let mut byte_end = None;
265        let mut byte_pos = 0;
266        let mut it = self.chars();
267        loop {
268            if char_pos == from {
269                byte_start = Some(byte_pos);
270            }
271            if char_pos == to {
272                byte_end = Some(byte_pos);
273                break;
274            }
275            if let Some(c) = it.next() {
276                char_pos += 1;
277                byte_pos += c.len_utf8();
278            } else {
279                break;
280            }
281        }
282        let byte_start = byte_start.unwrap();
283        let byte_end = byte_end.unwrap();
284        // Range::index panics if from > to or from > self@.len()
285        &self[byte_start..byte_end]
286    }
287
288    fn get_ascii(&self, i: usize) -> (b: u8)
289        requires
290            self.is_ascii(),
291            i < self@.len(),
292        ensures
293            self@.index(i as int) as u8 == b,
294    {
295        broadcast use is_ascii_spec_bytes;
296        // panics if i is not a valid index
297
298        self.as_bytes()[i]
299    }
300
301    #[cfg(feature = "alloc")]
302    fn as_bytes_vec(&self) -> (ret: alloc::vec::Vec<u8>)
303        ensures
304            ret@ == self.spec_bytes(),
305    {
306        slice_to_vec(self.as_bytes())
307    }
308}
309
310#[cfg(not(verus_verify_core))]
311pub uninterp spec fn strlit_view_id(s: Seq<char>) -> int;
312
313/// Distinct string literals have provably distinct views.
314#[cfg(not(verus_verify_core))]
315pub broadcast axiom fn axiom_new_strlit_view_id(id: int)
316    ensures
317        strlit_view_id(#[trigger] strslice_new_strlit(id).view()) == id,
318;
319
320#[cfg(not(verus_verify_core))]
321pub broadcast axiom fn axiom_str_literal_len<'a>(s: &'a str)
322    ensures
323        #[trigger] s@.len() == strslice_len(s),
324;
325
326#[cfg(not(verus_verify_core))]
327pub broadcast axiom fn axiom_str_literal_get_char<'a>(s: &'a str, i: int)
328    ensures
329        #[trigger] s@.index(i) == strslice_get_char(s, i),
330;
331
332#[cfg(all(not(feature = "alloc"), not(verus_verify_core)))]
333pub broadcast group group_string_axioms {
334    axiom_new_strlit_view_id,
335    axiom_str_literal_len,
336    axiom_str_literal_get_char,
337    is_ascii_spec_bytes,
338    is_ascii_concat,
339}
340
341#[cfg(all(feature = "alloc", not(verus_verify_core)))]
342pub broadcast group group_string_axioms {
343    axiom_new_strlit_view_id,
344    axiom_str_literal_len,
345    axiom_str_literal_get_char,
346    to_string_from_display_ensures_for_str,
347    is_ascii_spec_bytes,
348    is_ascii_concat,
349}
350
351#[cfg(all(feature = "alloc", not(verus_verify_core)))]
352impl View for String {
353    type V = Seq<char>;
354
355    uninterp spec fn view(&self) -> Seq<char>;
356}
357
358#[cfg(all(feature = "alloc", not(verus_verify_core)))]
359impl DeepView for String {
360    type V = Seq<char>;
361
362    open spec fn deep_view(&self) -> Seq<char> {
363        self.view()
364    }
365}
366
367#[cfg(verus_keep_ghost)]
368#[cfg(all(feature = "alloc", not(verus_verify_core)))]
369impl PartialEqSpecImpl for String {
370    open spec fn obeys_eq_spec() -> bool {
371        true
372    }
373
374    open spec fn eq_spec(&self, other: &String) -> bool {
375        self@ == other@
376    }
377}
378
379#[cfg(all(feature = "alloc", not(verus_verify_core)))]
380#[verifier::external_type_specification]
381#[verifier::external_body]
382pub struct ExString(String);
383
384#[cfg(all(feature = "alloc", not(verus_verify_core)))]
385pub open spec fn string_is_ascii(s: &String) -> bool {
386    is_ascii_chars(s@)
387}
388
389#[cfg(all(feature = "alloc", not(verus_verify_core)))]
390pub assume_specification<'a>[ String::as_str ](s: &'a String) -> (res: &'a str)
391    ensures
392        res@ == s@,
393    opens_invariants none
394    no_unwind
395;
396
397// same as above
398#[cfg(all(feature = "alloc", not(verus_verify_core)))]
399pub assume_specification<'a>[ <String as core::ops::Deref>::deref ](s: &'a String) -> (res: &'a str)
400    ensures
401        res@ == s@,
402;
403
404#[cfg(all(feature = "alloc", not(verus_verify_core)))]
405pub assume_specification[ <String as Clone>::clone ](s: &String) -> (res: String)
406    ensures
407        res == s,
408;
409
410#[cfg(all(feature = "alloc", not(verus_verify_core)))]
411pub assume_specification[ <String as PartialEq>::eq ](s: &String, other: &String) -> (res: bool)
412    ensures
413        res == (s@ == other@),
414;
415
416#[cfg(all(feature = "alloc", not(verus_verify_core)))]
417pub assume_specification[ String::new ]() -> (res: String)
418    ensures
419        res@ == Seq::<char>::empty(),
420;
421
422#[cfg(all(feature = "alloc", not(verus_verify_core)))]
423pub assume_specification[ String::push ](s: &mut String, c: char)
424    ensures
425        final(s)@ == old(s)@.push(c),
426;
427
428#[cfg(all(feature = "alloc", not(verus_verify_core)))]
429pub assume_specification[ String::pop ](s: &mut String) -> (res: Option<char>)
430    ensures
431        old(s)@.len() == 0 ==> res is None && final(s)@ == old(s)@,
432        old(s)@.len() > 0 ==> res == Some(old(s)@.last()) && final(s)@ == old(s)@.drop_last(),
433;
434
435#[cfg(all(feature = "alloc", not(verus_verify_core)))]
436pub assume_specification[ String::push_str ](s: &mut String, other: &str)
437    ensures
438        final(s)@ == old(s)@ + other@,
439;
440
441#[cfg(all(feature = "alloc", not(verus_verify_core)))]
442pub assume_specification[ String::is_empty ](s: &String) -> (res: bool)
443    ensures
444        res == (s@.len() == 0),
445    opens_invariants none
446    no_unwind
447;
448
449#[cfg(all(feature = "alloc", not(verus_verify_core)))]
450pub assume_specification[ String::clear ](s: &mut String)
451    ensures
452        final(s)@ == Seq::<char>::empty(),
453;
454
455#[cfg(all(feature = "alloc", not(verus_verify_core)))]
456pub assume_specification[ <String as core::default::Default>::default ]() -> (r: String)
457    ensures
458        r@ == Seq::<char>::empty(),
459;
460
461#[cfg(all(feature = "alloc", not(verus_verify_core)))]
462pub trait StringExecFnsIsAscii: Sized {
463    fn is_ascii(&self) -> bool;
464}
465
466#[cfg(all(feature = "alloc", not(verus_verify_core)))]
467impl StringExecFnsIsAscii for String {
468    #[inline(always)]
469    #[verifier::when_used_as_spec(string_is_ascii)]
470    fn is_ascii(&self) -> (ret: bool)
471        ensures
472            ret == string_is_ascii(self),
473    {
474        self.as_str().is_ascii()
475    }
476}
477
478#[cfg(all(feature = "alloc", not(verus_verify_core)))]
479#[verifier::external]
480pub trait StringExecFns: Sized {
481    fn from_str<'a>(s: &'a str) -> String;
482
483    fn append<'a, 'b>(&'a mut self, other: &'b str);
484
485    fn concat<'b>(self, other: &'b str) -> String;
486}
487
488#[cfg(all(feature = "alloc", not(verus_verify_core)))]
489impl StringExecFns for String {
490    #[verifier::external_body]
491    fn from_str<'a>(s: &'a str) -> (ret: String)
492        ensures
493            s@ == ret@,
494    {
495        s.to_string()
496    }
497
498    #[verifier::external_body]
499    fn append<'a, 'b>(&'a mut self, other: &'b str)
500        ensures
501            final(self)@ == old(self)@ + other@,
502    {
503        *self += other;
504    }
505
506    #[verifier::external_body]
507    fn concat<'b>(self, other: &'b str) -> (ret: String)
508        ensures
509            ret@ == self@ + other@,
510    {
511        self + other
512    }
513}
514
515// The `chars` method of a `str` returns an iterator of type `Chars`,
516// so we specify that type here.
517#[verifier::external_type_specification]
518#[verifier::external_body]
519#[cfg(all(feature = "alloc", not(verus_verify_core)))]
520pub struct ExChars<'a>(Chars<'a>);
521
522// To allow reasoning about the "contents" of the string iterator, without using
523// a prophecy, we need a function that gives us the underlying sequence of the original string.
524#[cfg(feature = "alloc")]
525pub uninterp spec fn into_iter_elts<'a>(i: Chars<'a>) -> Seq<char>;
526
527#[cfg(feature = "alloc")]
528pub assume_specification[ str::chars ](s: &str) -> (iter: Chars<'_>)
529    ensures
530        IteratorSpec::remaining(&iter) == s@,
531        IteratorSpec::decrease(&iter) is Some,
532;
533
534#[cfg(verus_keep_ghost)]
535#[cfg(feature = "alloc")]
536impl<'a> super::std_specs::iter::IteratorSpecImpl for Chars<'a> {
537    open spec fn obeys_prophetic_iter_laws(&self) -> bool {
538        true
539    }
540
541    uninterp spec fn remaining(&self) -> Seq<Self::Item>;
542
543    #[verifier::prophetic]
544    open spec fn produces(&self) -> Seq<bool> {
545        Seq::new(IteratorSpec::remaining(self).len(), |i: int| true)
546    }
547
548    uninterp spec fn decrease(&self) -> Option<nat>;
549
550    open spec fn peek(&self, index: int) -> Option<Self::Item> {
551        if 0 <= index < into_iter_elts(*self).len() {
552            Some(into_iter_elts(*self)[index])
553        } else {
554            None
555        }
556    }
557}
558
559// There are various types you can use to index into a `str` to get a
560// slice, i.e., to implement `SliceIndex<str>`. Here we indicate, for
561// any such type (e.g., `Range<usize>`), whether an index of that
562// type is valid when applied to a given `&str`.
563#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
564pub open spec fn str_slice_in_bounds<R: RangeBoundsSpec<usize>>(range: &R, s: &str) -> bool {
565    &&& slice_range_valid(range, s.spec_bytes().len())
566    &&& is_char_boundary(s.spec_bytes(), slice_range_start(range))
567    &&& is_char_boundary(s.spec_bytes(), slice_range_end(range, s.spec_bytes().len()))
568}
569
570// There are various types you can use to index into a `str` to get a
571// slice, i.e., to implement `SliceIndex<str>`. Here we indicate, for
572// any such type (e.g., `Range<usize>`), the semantics of immutably
573// indexing a string.
574#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
575pub open spec fn str_slice_index_postcondition<R: RangeBoundsSpec<usize>>(
576    range: &R,
577    s: Seq<u8>,
578    r: Seq<u8>,
579) -> bool {
580    r == s[slice_range_start(range)..slice_range_end(range, s.len())]
581}
582
583// There are various types you can use to index into a `str` to get a
584// slice, i.e., to implement `SliceIndex<str>`. Here we indicate, for
585// any such type (e.g., `Range<usize>`), the semantics of mutably
586// indexing a string.
587#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
588pub open spec fn str_slice_index_mut_postcondition<R: RangeBoundsSpec<usize>>(
589    range: &R,
590    old_s: Seq<u8>,
591    final_s: Seq<u8>,
592    r: Seq<u8>,
593    final_r: Seq<u8>,
594) -> bool {
595    let start = slice_range_start(range);
596    let end = slice_range_end(range, old_s.len());
597    &&& r == old_s[start..end]
598    &&& final_s.len() == old_s.len()
599    &&& final_s[..start] == old_s[..start]
600    &&& final_s[start..end] == final_r
601    &&& final_s[end..old_s.len()] == old_s[end..]
602}
603
604#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
605impl super::slice::SliceIndexSpecImpl<str> for (Bound<usize>, Bound<usize>) {
606    open spec fn in_bounds(&self, s: &str) -> bool {
607        str_slice_in_bounds(self, s)
608    }
609
610    open spec fn index_postcondition(&self, s: &str, r: &str) -> bool {
611        str_slice_index_postcondition(self, s.spec_bytes(), r.spec_bytes())
612    }
613
614    open spec fn index_mut_postcondition(
615        &self,
616        old_slice: &str,
617        final_slice: &str,
618        immediate_output: &str,
619        final_output: &str,
620    ) -> bool {
621        str_slice_index_mut_postcondition(
622            self,
623            old_slice.spec_bytes(),
624            final_slice.spec_bytes(),
625            immediate_output.spec_bytes(),
626            final_output.spec_bytes(),
627        )
628    }
629}
630
631#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
632pub assume_specification[ <(Bound<usize>, Bound<usize>) as SliceIndex<str>>::get ](
633    i: (Bound<usize>, Bound<usize>),
634    s: &str,
635) -> (r: Option<&str>)
636;
637
638#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
639pub assume_specification[ <(Bound<usize>, Bound<usize>) as SliceIndex<str>>::index ](
640    i: (Bound<usize>, Bound<usize>),
641    s: &str,
642) -> (r: &str)
643;
644
645#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
646pub assume_specification[ <(Bound<usize>, Bound<usize>) as SliceIndex<str>>::get_mut ](
647    i: (Bound<usize>, Bound<usize>),
648    s: &mut str,
649) -> (r: Option<&mut str>)
650;
651
652#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
653pub assume_specification[ <(Bound<usize>, Bound<usize>) as SliceIndex<str>>::index_mut ](
654    i: (Bound<usize>, Bound<usize>),
655    s: &mut str,
656) -> (r: &mut str)
657;
658
659#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
660impl super::slice::SliceIndexSpecImpl<str> for Range<usize> {
661    open spec fn in_bounds(&self, s: &str) -> bool {
662        str_slice_in_bounds(self, s)
663    }
664
665    open spec fn index_postcondition(&self, s: &str, r: &str) -> bool {
666        str_slice_index_postcondition(self, s.spec_bytes(), r.spec_bytes())
667    }
668
669    open spec fn index_mut_postcondition(
670        &self,
671        old_slice: &str,
672        final_slice: &str,
673        immediate_output: &str,
674        final_output: &str,
675    ) -> bool {
676        str_slice_index_mut_postcondition(
677            self,
678            old_slice.spec_bytes(),
679            final_slice.spec_bytes(),
680            immediate_output.spec_bytes(),
681            final_output.spec_bytes(),
682        )
683    }
684}
685
686#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
687pub assume_specification[ <Range<usize> as SliceIndex<str>>::get ](i: Range<usize>, s: &str) -> (r:
688    Option<&<Range<usize> as SliceIndex<str>>::Output>)
689;
690
691#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
692pub assume_specification[ <Range<usize> as SliceIndex<str>>::index ](
693    i: Range<usize>,
694    s: &str,
695) -> (r: &<Range<usize> as SliceIndex<str>>::Output)
696;
697
698#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
699pub assume_specification[ <Range<usize> as SliceIndex<str>>::get_mut ](
700    i: Range<usize>,
701    s: &mut str,
702) -> (r: Option<&mut <Range<usize> as SliceIndex<str>>::Output>)
703;
704
705#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
706pub assume_specification[ <Range<usize> as SliceIndex<str>>::index_mut ](
707    i: Range<usize>,
708    s: &mut str,
709) -> (r: &mut <Range<usize> as SliceIndex<str>>::Output)
710;
711
712#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
713impl super::slice::SliceIndexSpecImpl<str> for RangeFrom<usize> {
714    open spec fn in_bounds(&self, s: &str) -> bool {
715        str_slice_in_bounds(self, s)
716    }
717
718    open spec fn index_postcondition(&self, s: &str, r: &str) -> bool {
719        str_slice_index_postcondition(self, s.spec_bytes(), r.spec_bytes())
720    }
721
722    open spec fn index_mut_postcondition(
723        &self,
724        old_slice: &str,
725        final_slice: &str,
726        immediate_output: &str,
727        final_output: &str,
728    ) -> bool {
729        str_slice_index_mut_postcondition(
730            self,
731            old_slice.spec_bytes(),
732            final_slice.spec_bytes(),
733            immediate_output.spec_bytes(),
734            final_output.spec_bytes(),
735        )
736    }
737}
738
739#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
740pub assume_specification[ <RangeFrom<usize> as SliceIndex<str>>::get ](
741    i: RangeFrom<usize>,
742    s: &str,
743) -> (r: Option<&<RangeFrom<usize> as SliceIndex<str>>::Output>)
744;
745
746#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
747pub assume_specification[ <RangeFrom<usize> as SliceIndex<str>>::index ](
748    i: RangeFrom<usize>,
749    s: &str,
750) -> (r: &<RangeFrom<usize> as SliceIndex<str>>::Output)
751;
752
753#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
754pub assume_specification[ <RangeFrom<usize> as SliceIndex<str>>::get_mut ](
755    i: RangeFrom<usize>,
756    s: &mut str,
757) -> (r: Option<&mut <RangeFrom<usize> as SliceIndex<str>>::Output>)
758;
759
760#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
761pub assume_specification[ <RangeFrom<usize> as SliceIndex<str>>::index_mut ](
762    i: RangeFrom<usize>,
763    s: &mut str,
764) -> (r: &mut <RangeFrom<usize> as SliceIndex<str>>::Output)
765;
766
767#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
768impl super::slice::SliceIndexSpecImpl<str> for RangeFull {
769    open spec fn in_bounds(&self, s: &str) -> bool {
770        str_slice_in_bounds(self, s)
771    }
772
773    open spec fn index_postcondition(&self, s: &str, r: &str) -> bool {
774        str_slice_index_postcondition(self, s.spec_bytes(), r.spec_bytes())
775    }
776
777    open spec fn index_mut_postcondition(
778        &self,
779        old_slice: &str,
780        final_slice: &str,
781        immediate_output: &str,
782        final_output: &str,
783    ) -> bool {
784        str_slice_index_mut_postcondition(
785            self,
786            old_slice.spec_bytes(),
787            final_slice.spec_bytes(),
788            immediate_output.spec_bytes(),
789            final_output.spec_bytes(),
790        )
791    }
792}
793
794#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
795pub assume_specification[ <RangeFull as SliceIndex<str>>::get ](i: RangeFull, s: &str) -> (r:
796    Option<&<RangeFull as SliceIndex<str>>::Output>)
797;
798
799#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
800pub assume_specification[ <RangeFull as SliceIndex<str>>::index ](i: RangeFull, s: &str) -> (r:
801    &<RangeFull as SliceIndex<str>>::Output)
802;
803
804#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
805pub assume_specification[ <RangeFull as SliceIndex<str>>::get_mut ](
806    i: RangeFull,
807    s: &mut str,
808) -> (r: Option<&mut <RangeFull as SliceIndex<str>>::Output>)
809;
810
811#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
812pub assume_specification[ <RangeFull as SliceIndex<str>>::index_mut ](
813    i: RangeFull,
814    s: &mut str,
815) -> (r: &mut <RangeFull as SliceIndex<str>>::Output)
816;
817
818// Indexing with an empty range doesn't verify, since std doesn't say whether it
819// panics. `get` still verifies and returns `None` or an empty string.
820#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
821pub uninterp spec fn spec_range_inclusive_unspecified_str_in_bounds(
822    range: &RangeInclusive<usize>,
823    s: &str,
824) -> bool;
825
826#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
827impl super::slice::SliceIndexSpecImpl<str> for RangeInclusive<usize> {
828    open spec fn in_bounds(&self, s: &str) -> bool {
829        if spec_range_inclusive_is_empty(self) {
830            spec_range_inclusive_unspecified_str_in_bounds(self, s)
831        } else {
832            str_slice_in_bounds(self, s)
833        }
834    }
835
836    open spec fn index_postcondition(&self, s: &str, r: &str) -> bool {
837        if spec_range_inclusive_is_empty(self) {
838            r.spec_bytes().len() == 0
839        } else {
840            str_slice_index_postcondition(self, s.spec_bytes(), r.spec_bytes())
841        }
842    }
843
844    open spec fn index_mut_postcondition(
845        &self,
846        old_slice: &str,
847        final_slice: &str,
848        immediate_output: &str,
849        final_output: &str,
850    ) -> bool {
851        if spec_range_inclusive_is_empty(self) {
852            &&& immediate_output.spec_bytes().len() == 0
853            &&& final_slice.spec_bytes() == old_slice.spec_bytes()
854        } else {
855            str_slice_index_mut_postcondition(
856                self,
857                old_slice.spec_bytes(),
858                final_slice.spec_bytes(),
859                immediate_output.spec_bytes(),
860                final_output.spec_bytes(),
861            )
862        }
863    }
864}
865
866#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
867pub assume_specification[ <RangeInclusive<usize> as SliceIndex<str>>::get ](
868    i: RangeInclusive<usize>,
869    s: &str,
870) -> (r: Option<&<RangeInclusive<usize> as SliceIndex<str>>::Output>)
871;
872
873#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
874pub assume_specification[ <RangeInclusive<usize> as SliceIndex<str>>::index ](
875    i: RangeInclusive<usize>,
876    s: &str,
877) -> (r: &<RangeInclusive<usize> as SliceIndex<str>>::Output)
878;
879
880#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
881pub assume_specification[ <RangeInclusive<usize> as SliceIndex<str>>::get_mut ](
882    i: RangeInclusive<usize>,
883    s: &mut str,
884) -> (r: Option<&mut <RangeInclusive<usize> as SliceIndex<str>>::Output>)
885;
886
887#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
888pub assume_specification[ <RangeInclusive<usize> as SliceIndex<str>>::index_mut ](
889    i: RangeInclusive<usize>,
890    s: &mut str,
891) -> (r: &mut <RangeInclusive<usize> as SliceIndex<str>>::Output)
892;
893
894#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
895impl super::slice::SliceIndexSpecImpl<str> for RangeTo<usize> {
896    open spec fn in_bounds(&self, s: &str) -> bool {
897        str_slice_in_bounds(self, s)
898    }
899
900    open spec fn index_postcondition(&self, s: &str, r: &str) -> bool {
901        str_slice_index_postcondition(self, s.spec_bytes(), r.spec_bytes())
902    }
903
904    open spec fn index_mut_postcondition(
905        &self,
906        old_slice: &str,
907        final_slice: &str,
908        immediate_output: &str,
909        final_output: &str,
910    ) -> bool {
911        str_slice_index_mut_postcondition(
912            self,
913            old_slice.spec_bytes(),
914            final_slice.spec_bytes(),
915            immediate_output.spec_bytes(),
916            final_output.spec_bytes(),
917        )
918    }
919}
920
921#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
922pub assume_specification[ <RangeTo<usize> as SliceIndex<str>>::get ](
923    i: RangeTo<usize>,
924    s: &str,
925) -> (r: Option<&<RangeTo<usize> as SliceIndex<str>>::Output>)
926;
927
928#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
929pub assume_specification[ <RangeTo<usize> as SliceIndex<str>>::index ](
930    i: RangeTo<usize>,
931    s: &str,
932) -> (r: &<RangeTo<usize> as SliceIndex<str>>::Output)
933;
934
935#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
936pub assume_specification[ <RangeTo<usize> as SliceIndex<str>>::get_mut ](
937    i: RangeTo<usize>,
938    s: &mut str,
939) -> (r: Option<&mut <RangeTo<usize> as SliceIndex<str>>::Output>)
940;
941
942#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
943pub assume_specification[ <RangeTo<usize> as SliceIndex<str>>::index_mut ](
944    i: RangeTo<usize>,
945    s: &mut str,
946) -> (r: &mut <RangeTo<usize> as SliceIndex<str>>::Output)
947;
948
949#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
950impl super::slice::SliceIndexSpecImpl<str> for RangeToInclusive<usize> {
951    open spec fn in_bounds(&self, s: &str) -> bool {
952        str_slice_in_bounds(self, s)
953    }
954
955    open spec fn index_postcondition(&self, s: &str, r: &str) -> bool {
956        str_slice_index_postcondition(self, s.spec_bytes(), r.spec_bytes())
957    }
958
959    open spec fn index_mut_postcondition(
960        &self,
961        old_slice: &str,
962        final_slice: &str,
963        immediate_output: &str,
964        final_output: &str,
965    ) -> bool {
966        str_slice_index_mut_postcondition(
967            self,
968            old_slice.spec_bytes(),
969            final_slice.spec_bytes(),
970            immediate_output.spec_bytes(),
971            final_output.spec_bytes(),
972        )
973    }
974}
975
976#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
977pub assume_specification[ <RangeToInclusive<usize> as SliceIndex<str>>::get ](
978    i: RangeToInclusive<usize>,
979    s: &str,
980) -> (r: Option<&<RangeToInclusive<usize> as SliceIndex<str>>::Output>)
981;
982
983#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
984pub assume_specification[ <RangeToInclusive<usize> as SliceIndex<str>>::index ](
985    i: RangeToInclusive<usize>,
986    s: &str,
987) -> (r: &<RangeToInclusive<usize> as SliceIndex<str>>::Output)
988;
989
990#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
991pub assume_specification[ <RangeToInclusive<usize> as SliceIndex<str>>::get_mut ](
992    i: RangeToInclusive<usize>,
993    s: &mut str,
994) -> (r: Option<&mut <RangeToInclusive<usize> as SliceIndex<str>>::Output>)
995;
996
997#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
998pub assume_specification[ <RangeToInclusive<usize> as SliceIndex<str>>::index_mut ](
999    i: RangeToInclusive<usize>,
1000    s: &mut str,
1001) -> (r: &mut <RangeToInclusive<usize> as SliceIndex<str>>::Output)
1002;
1003
1004// `<str as ops::Index<I>>::index(&self, index: I)` just invokes
1005// `index.index(self)`. So we likewise delegate determining the meaning
1006// of the string-index operation to that of the index type.
1007#[cfg(all(verus_keep_ghost, not(verus_verify_core)))]
1008impl<I: SliceIndexSpec<str>> super::std_specs::core::IndexSpecImpl<I> for str {
1009    open spec fn index_req(&self, index: &I) -> bool {
1010        index.in_bounds(self)
1011    }
1012}
1013
1014pub use super::view::View;
1015
1016} // verus!