@@ -7,7 +7,11 @@ use super::range::{slice_range_end, slice_range_start, slice_range_valid};
77use core:: ops:: {
88 Index , IndexMut , Range , RangeFrom , RangeFull , RangeInclusive , RangeTo , RangeToInclusive ,
99} ;
10- use core:: slice:: { Iter , SliceIndex } ;
10+ use core:: slice:: {
11+ ChunksExact , ChunksExactMut , EscapeAscii , Iter , IterMut , RChunksExact , RChunksExactMut ,
12+ SliceIndex , Windows ,
13+ } ;
14+ use core:: str:: Utf8Chunks ;
1115
1216use verus as verus_;
1317
@@ -408,6 +412,314 @@ pub assume_specification<T: Copy, R: core::ops::RangeBounds<usize>>[ <[T]>::copy
408412 ) ,
409413;
410414
415+ #[ verifier:: external_type_specification]
416+ #[ verifier:: external_body]
417+ #[ verifier:: reject_recursive_types( T ) ]
418+ pub struct ExIterMut <' a, T : ' a>( IterMut <' a, T >) ;
419+
420+ #[ verifier:: external_type_specification]
421+ #[ verifier:: external_body]
422+ #[ verifier:: reject_recursive_types( T ) ]
423+ pub struct ExChunksExact <' a, T : ' a>( ChunksExact <' a, T >) ;
424+
425+ #[ verifier:: external_type_specification]
426+ #[ verifier:: external_body]
427+ #[ verifier:: reject_recursive_types( T ) ]
428+ pub struct ExChunksExactMut <' a, T : ' a>( ChunksExactMut <' a, T >) ;
429+
430+ #[ verifier:: external_type_specification]
431+ #[ verifier:: external_body]
432+ #[ verifier:: reject_recursive_types( T ) ]
433+ pub struct ExRChunksExact <' a, T : ' a>( RChunksExact <' a, T >) ;
434+
435+ #[ verifier:: external_type_specification]
436+ #[ verifier:: external_body]
437+ #[ verifier:: reject_recursive_types( T ) ]
438+ pub struct ExRChunksExactMut <' a, T : ' a>( RChunksExactMut <' a, T >) ;
439+
440+ #[ verifier:: external_type_specification]
441+ #[ verifier:: external_body]
442+ #[ verifier:: reject_recursive_types( T ) ]
443+ pub struct ExWindows <' a, T : ' a>( Windows <' a, T >) ;
444+
445+ #[ verifier:: external_type_specification]
446+ #[ verifier:: external_body]
447+ pub struct ExUtf8Chunks <' a>( Utf8Chunks <' a>) ;
448+
449+ #[ verifier:: external_type_specification]
450+ #[ verifier:: external_body]
451+ pub struct ExEscapeAscii <' a>( EscapeAscii <' a>) ;
452+
453+ pub ghost struct SliceIteratorView <T > {
454+ pub source: Seq <T >,
455+ pub remaining: Seq <T >,
456+ pub yielded_prefix: Seq <T >,
457+ pub remainder: Seq <T >,
458+ pub chunk_size: int,
459+ pub reverse: bool ,
460+ }
461+
462+ pub uninterp spec fn slice_iterator_view<I , T >( iter: I ) -> SliceIteratorView <T >;
463+
464+ pub open spec fn slice_iterator_well_formed<T >( view: SliceIteratorView <T >) -> bool {
465+ 0 <= view. chunk_size && view. remainder. len( ) <= view. source. len( )
466+ }
467+
468+ pub broadcast axiom fn axiom_slice_iterator_view_well_formed<I , T >( iter: I )
469+ ensures
470+ slice_iterator_well_formed( #[ trigger] slice_iterator_view:: <I , T >( iter) ) ,
471+ ;
472+
473+ pub open spec fn utf8_chunk_partition<I >( iter: I , source: Seq <u8 >) -> bool {
474+ let view = slice_iterator_view:: <I , u8 >( iter) ;
475+ slice_iterator_well_formed( view)
476+ && view. source == source
477+ && view. remaining == source
478+ && view. yielded_prefix == Seq :: empty( )
479+ && view. remainder == Seq :: empty( )
480+ && view. chunk_size == 0
481+ && !view. reverse
482+ }
483+
484+ pub open spec fn ascii_is_uppercase( byte: u8 ) -> bool {
485+ 0x41 <= ( byte as int) && ( byte as int) <= 0x5a
486+ }
487+
488+ pub open spec fn ascii_is_lowercase( byte: u8 ) -> bool {
489+ 0x61 <= ( byte as int) && ( byte as int) <= 0x7a
490+ }
491+
492+ pub open spec fn ascii_lower_byte( byte: u8 ) -> u8 {
493+ if ascii_is_uppercase( byte) {
494+ ( ( byte as int) + 0x20 ) as u8
495+ } else {
496+ byte
497+ }
498+ }
499+
500+ pub open spec fn ascii_upper_byte( byte: u8 ) -> u8 {
501+ if ascii_is_lowercase( byte) {
502+ ( ( byte as int) - 0x20 ) as u8
503+ } else {
504+ byte
505+ }
506+ }
507+
508+ pub open spec fn ascii_is_whitespace( byte: u8 ) -> bool {
509+ byte == 0x09u8
510+ || byte == 0x0au8
511+ || byte == 0x0cu8
512+ || byte == 0x0du8
513+ || byte == 0x20u8
514+ }
515+
516+ pub open spec fn ascii_lower_seq( seq: Seq <u8 >) -> Seq <u8 > {
517+ Seq :: new( seq. len( ) , |i: int| ascii_lower_byte( seq[ i] ) )
518+ }
519+
520+ pub open spec fn ascii_upper_seq( seq: Seq <u8 >) -> Seq <u8 > {
521+ Seq :: new( seq. len( ) , |i: int| ascii_upper_byte( seq[ i] ) )
522+ }
523+
524+ pub open spec fn ascii_eq_ignore_case( left: Seq <u8 >, right: Seq <u8 >) -> bool {
525+ left. len( ) == right. len( )
526+ && forall|i: int| 0 <= i < left. len( )
527+ ==> ascii_lower_byte( left[ i] ) == ascii_lower_byte( right[ i] )
528+ }
529+
530+ pub open spec fn ascii_trim_start_boundary( seq: Seq <u8 >, i: int) -> bool {
531+ 0 <= i <= seq. len( )
532+ && ( forall|j: int| 0 <= j < i ==> #[ trigger] ascii_is_whitespace( seq[ j] ) )
533+ && ( i < seq. len( ) ==> !ascii_is_whitespace( seq[ i] ) )
534+ }
535+
536+ pub open spec fn ascii_trim_end_boundary( seq: Seq <u8 >, i: int) -> bool {
537+ 0 <= i <= seq. len( )
538+ && ( forall|j: int| i <= j < seq. len( ) ==> #[ trigger] ascii_is_whitespace( seq[ j] ) )
539+ && ( 0 < i ==> !ascii_is_whitespace( seq[ i - 1 ] ) )
540+ }
541+
542+ pub open spec fn ascii_trim_start_index( seq: Seq <u8 >) -> int {
543+ choose|i: int| #[ trigger] ascii_trim_start_boundary( seq, i)
544+ }
545+
546+ pub open spec fn ascii_trim_end_index( seq: Seq <u8 >) -> int {
547+ choose|i: int| #[ trigger] ascii_trim_end_boundary( seq, i)
548+ }
549+
550+ pub open spec fn ascii_trim_start_result( seq: Seq <u8 >, ret: & [ u8 ] ) -> bool {
551+ 0 <= ascii_trim_start_index( seq) <= seq. len( )
552+ && ret@ == seq. subrange( ascii_trim_start_index( seq) , seq. len( ) as int)
553+ && ( forall|i: int| 0 <= i < ascii_trim_start_index( seq)
554+ ==> ascii_is_whitespace( seq[ i] ) )
555+ && ( ascii_trim_start_index( seq) < seq. len( )
556+ ==> !ascii_is_whitespace( seq[ ascii_trim_start_index( seq) ] ) )
557+ }
558+
559+ pub open spec fn ascii_trim_end_result( seq: Seq <u8 >, ret: & [ u8 ] ) -> bool {
560+ 0 <= ascii_trim_end_index( seq) <= seq. len( )
561+ && ret@ == seq. subrange( 0 , ascii_trim_end_index( seq) )
562+ && ( forall|i: int| ascii_trim_end_index( seq) <= i < seq. len( )
563+ ==> ascii_is_whitespace( seq[ i] ) )
564+ && ( 0 < ascii_trim_end_index( seq)
565+ ==> !ascii_is_whitespace( seq[ ascii_trim_end_index( seq) - 1 ] ) )
566+ }
567+
568+ pub open spec fn ascii_trim_source_body_result( seq: Seq <u8 >, ret: & [ u8 ] ) -> bool {
569+ let start = ascii_trim_start_index( seq) ;
570+ let after_start = seq. subrange( start, seq. len( ) as int) ;
571+ let end = ascii_trim_end_index( after_start) ;
572+ 0 <= start <= seq. len( )
573+ && 0 <= end <= after_start. len( )
574+ && ret@ == seq. subrange( start, start + end)
575+ && ( forall|i: int| 0 <= i < start ==> ascii_is_whitespace( seq[ i] ) )
576+ && ( forall|i: int| start + end <= i < seq. len( ) ==> ascii_is_whitespace( seq[ i] ) )
577+ }
578+
579+ pub open spec fn ascii_lower_hex_digit( nibble: int) -> u8
580+ recommends
581+ 0 <= nibble < 16 ,
582+ {
583+ if nibble < 10 {
584+ ( 0x30 + nibble) as u8
585+ } else {
586+ ( 0x61 + ( nibble - 10 ) ) as u8
587+ }
588+ }
589+
590+ pub open spec fn ascii_escape_byte( byte: u8 ) -> Seq <u8 > {
591+ if byte == 0x09u8 {
592+ seq![ 0x5cu8 , 0x74u8 ]
593+ } else if byte == 0x0du8 {
594+ seq![ 0x5cu8 , 0x72u8 ]
595+ } else if byte == 0x0au8 {
596+ seq![ 0x5cu8 , 0x6eu8 ]
597+ } else if byte == 0x27u8 {
598+ seq![ 0x5cu8 , 0x27u8 ]
599+ } else if byte == 0x22u8 {
600+ seq![ 0x5cu8 , 0x22u8 ]
601+ } else if byte == 0x5cu8 {
602+ seq![ 0x5cu8 , 0x5cu8 ]
603+ } else if 0x20 <= ( byte as int) && ( byte as int) <= 0x7e {
604+ seq![ byte]
605+ } else {
606+ seq![
607+ 0x5cu8 ,
608+ 0x78u8 ,
609+ ascii_lower_hex_digit( ( byte as int) / 16 ) ,
610+ ascii_lower_hex_digit( ( byte as int) % 16 ) ,
611+ ]
612+ }
613+ }
614+
615+ pub open spec fn ascii_escape_seq( seq: Seq <u8 >) -> Seq <u8 > {
616+ seq. flat_map( |byte: u8 | ascii_escape_byte( byte) )
617+ }
618+
619+ pub assume_specification<' a, T >[ <[ T ] >:: iter_mut ] (
620+ slice: & ' a mut [ T ] ,
621+ ) -> ( iter: IterMut <' a, T >)
622+ ensures
623+ slice_iterator_view:: <IterMut <' a, T >, T >( iter) . source == old( slice) @,
624+ slice_iterator_view:: <IterMut <' a, T >, T >( iter) . remaining == old( slice) @,
625+ final( slice) @ == old( slice) @,
626+ ;
627+
628+ pub assume_specification<' a, T >[ <[ T ] >:: windows ] (
629+ slice: & ' a [ T ] ,
630+ size: usize ,
631+ ) -> ( iter: Windows <' a, T >)
632+ requires
633+ size != 0 ,
634+ ensures
635+ slice_iterator_view:: <Windows <' a, T >, T >( iter) . source == slice@,
636+ slice_iterator_view:: <Windows <' a, T >, T >( iter) . remaining == slice@,
637+ slice_iterator_view:: <Windows <' a, T >, T >( iter) . yielded_prefix == Seq :: empty( ) ,
638+ slice_iterator_view:: <Windows <' a, T >, T >( iter) . remainder == Seq :: empty( ) ,
639+ slice_iterator_view:: <Windows <' a, T >, T >( iter) . chunk_size == size as int,
640+ !slice_iterator_view:: <Windows <' a, T >, T >( iter) . reverse,
641+ ;
642+
643+ pub assume_specification<' a, T >[ ChunksExact :: <' a, T >:: remainder ] (
644+ iter: & ChunksExact <' a, T >,
645+ ) -> ( ret: & ' a [ T ] )
646+ ensures
647+ ret@ == slice_iterator_view:: <& ChunksExact <' a, T >, T >( iter) . remainder,
648+ ret@. len( ) < slice_iterator_view:: <& ChunksExact <' a, T >, T >( iter) . chunk_size,
649+ ;
650+
651+ pub assume_specification<' a, T >[ ChunksExactMut :: <' a, T >:: into_remainder ] (
652+ iter: ChunksExactMut <' a, T >,
653+ ) -> ( ret: & ' a mut [ T ] )
654+ ensures
655+ ret@ == slice_iterator_view:: <ChunksExactMut <' a, T >, T >( iter) . remainder,
656+ ret@. len( ) < slice_iterator_view:: <ChunksExactMut <' a, T >, T >( iter) . chunk_size,
657+ ;
658+
659+ pub assume_specification<' a, T >[ RChunksExact :: <' a, T >:: remainder ] (
660+ iter: & RChunksExact <' a, T >,
661+ ) -> ( ret: & ' a [ T ] )
662+ ensures
663+ ret@ == slice_iterator_view:: <& RChunksExact <' a, T >, T >( iter) . remainder,
664+ ret@. len( ) < slice_iterator_view:: <& RChunksExact <' a, T >, T >( iter) . chunk_size,
665+ ;
666+
667+ pub assume_specification<' a, T >[ RChunksExactMut :: <' a, T >:: into_remainder ] (
668+ iter: RChunksExactMut <' a, T >,
669+ ) -> ( ret: & ' a mut [ T ] )
670+ ensures
671+ ret@ == slice_iterator_view:: <RChunksExactMut <' a, T >, T >( iter) . remainder,
672+ ret@. len( ) < slice_iterator_view:: <RChunksExactMut <' a, T >, T >( iter) . chunk_size,
673+ ;
674+
675+ pub assume_specification<' a>[ <[ u8 ] >:: utf8_chunks ] (
676+ slice: & ' a [ u8 ] ,
677+ ) -> ( iter: Utf8Chunks <' a>)
678+ ensures
679+ utf8_chunk_partition:: <Utf8Chunks <' a>>( iter, slice@) ,
680+ ;
681+
682+ pub assume_specification[ <[ u8 ] >:: eq_ignore_ascii_case ] (
683+ slice: & [ u8 ] ,
684+ other: & [ u8 ] ,
685+ ) -> ( ret: bool )
686+ ensures
687+ ret <==> ascii_eq_ignore_case( slice@, other@) ,
688+ ;
689+
690+ pub assume_specification<' a>[ <[ u8 ] >:: escape_ascii ] (
691+ slice: & ' a [ u8 ] ,
692+ ) -> ( iter: EscapeAscii <' a>)
693+ ensures
694+ slice_iterator_view:: <EscapeAscii <' a>, u8 >( iter) . source == slice@,
695+ slice_iterator_view:: <EscapeAscii <' a>, u8 >( iter) . remaining == ascii_escape_seq( slice@) ,
696+ ;
697+
698+ pub assume_specification[ <[ u8 ] >:: make_ascii_lowercase ] ( slice: & mut [ u8 ] )
699+ ensures
700+ final( slice) @ == ascii_lower_seq( old( slice) @) ,
701+ ;
702+
703+ pub assume_specification[ <[ u8 ] >:: make_ascii_uppercase ] ( slice: & mut [ u8 ] )
704+ ensures
705+ final( slice) @ == ascii_upper_seq( old( slice) @) ,
706+ ;
707+
708+ pub assume_specification[ <[ u8 ] >:: trim_ascii ] ( slice: & [ u8 ] ) -> ( ret: & [ u8 ] )
709+ ensures
710+ ascii_trim_source_body_result( slice@, ret) ,
711+ ;
712+
713+ pub assume_specification[ <[ u8 ] >:: trim_ascii_end ] ( slice: & [ u8 ] ) -> ( ret: & [ u8 ] )
714+ ensures
715+ ascii_trim_end_result( slice@, ret) ,
716+ ;
717+
718+ pub assume_specification[ <[ u8 ] >:: trim_ascii_start ] ( slice: & [ u8 ] ) -> ( ret: & [ u8 ] )
719+ ensures
720+ ascii_trim_start_result( slice@, ret) ,
721+ ;
722+
411723pub broadcast group group_slice_axioms {
412724 axiom_slice_get_range,
413725 axiom_slice_get_range_to,
0 commit comments