1use super::prelude::*;
29use super::seq::*;
30
31verus! {
32
33broadcast use super::seq::group_seq_lemmas;
34pub open spec fn is_leading_byte_width_1(byte: u8) -> bool {
39 0x00 <= byte <= 0x7f
40}
41
42pub open spec fn is_leading_byte_width_2(byte: u8) -> bool {
45 0xc0 <= byte <= 0xdf
46}
47
48pub open spec fn is_leading_byte_width_3(byte: u8) -> bool {
51 0xe0 <= byte <= 0xef
52}
53
54pub open spec fn is_leading_byte_width_4(byte: u8) -> bool {
57 0xf0 <= byte <= 0xf7
58}
59
60pub open spec fn is_continuation_byte(byte: u8) -> bool {
63 0x80 <= byte <= 0xbf
64}
65
66pub open spec fn continuation_bits(byte: u8) -> u32
68 recommends
69 is_continuation_byte(byte),
70{
71 (byte & 0x3f) as u32
73}
74
75pub open spec fn leading_bits_width_1(byte: u8) -> u32
77 recommends
78 is_leading_byte_width_1(byte),
79{
80 (byte & 0x7F) as u32
82}
83
84pub open spec fn leading_bits_width_2(byte: u8) -> u32
86 recommends
87 is_leading_byte_width_2(byte),
88{
89 (byte & 0x1F) as u32
91}
92
93pub open spec fn leading_bits_width_3(byte: u8) -> u32
95 recommends
96 is_leading_byte_width_3(byte),
97{
98 (byte & 0x0F) as u32
100}
101
102pub open spec fn leading_bits_width_4(byte: u8) -> u32
104 recommends
105 is_leading_byte_width_4(byte),
106{
107 (byte & 0x07) as u32
109}
110
111pub open spec fn codepoint_width_1(byte1: u8) -> u32
113 recommends
114 is_leading_byte_width_1(byte1),
115{
116 leading_bits_width_1(byte1)
117}
118
119pub open spec fn codepoint_width_2(byte1: u8, byte2: u8) -> u32
126 recommends
127 is_leading_byte_width_2(byte1),
128 is_continuation_byte(byte2),
129{
130 (leading_bits_width_2(byte1) << 6) | continuation_bits(byte2)
131}
132
133pub open spec fn codepoint_width_3(byte1: u8, byte2: u8, byte3: u8) -> u32
135 recommends
136 is_leading_byte_width_3(byte1),
137 is_continuation_byte(byte2),
138 is_continuation_byte(byte3),
139{
140 (leading_bits_width_3(byte1) << 12) | (continuation_bits(byte2) << 6) | continuation_bits(byte3)
141}
142
143pub open spec fn codepoint_width_4(byte1: u8, byte2: u8, byte3: u8, byte4: u8) -> u32
151 recommends
152 is_leading_byte_width_4(byte1),
153 is_continuation_byte(byte2),
154 is_continuation_byte(byte3),
155 is_continuation_byte(byte4),
156{
157 (leading_bits_width_4(byte1) << 18) | (continuation_bits(byte2) << 12) | (continuation_bits(
158 byte3,
159 ) << 6) | continuation_bits(byte4)
160}
161
162pub open spec fn valid_leading_and_continuation_bytes_first_codepoint(bytes: Seq<u8>) -> bool {
164 ||| (bytes.len() >= 1 && is_leading_byte_width_1(bytes[0]))
165 ||| (bytes.len() >= 2 && is_leading_byte_width_2(bytes[0]) && is_continuation_byte(bytes[1]))
166 ||| (bytes.len() >= 3 && is_leading_byte_width_3(bytes[0]) && is_continuation_byte(bytes[1])
167 && is_continuation_byte(bytes[2]))
168 ||| (bytes.len() >= 4 && is_leading_byte_width_4(bytes[0]) && is_continuation_byte(bytes[1])
169 && is_continuation_byte(bytes[2]) && is_continuation_byte(bytes[3]))
170}
171
172pub open spec fn decode_first_codepoint(bytes: Seq<u8>) -> u32
174 recommends
175 valid_leading_and_continuation_bytes_first_codepoint(bytes),
176{
177 if is_leading_byte_width_1(bytes[0]) {
178 codepoint_width_1(bytes[0])
179 } else if is_leading_byte_width_2(bytes[0]) {
180 codepoint_width_2(bytes[0], bytes[1])
181 } else if is_leading_byte_width_3(bytes[0]) {
182 codepoint_width_3(bytes[0], bytes[1], bytes[2])
183 } else {
184 codepoint_width_4(bytes[0], bytes[1], bytes[2], bytes[3])
185 }
186}
187
188pub open spec fn length_of_first_codepoint(bytes: Seq<u8>) -> int
190 recommends
191 valid_leading_and_continuation_bytes_first_codepoint(bytes),
192{
193 if is_leading_byte_width_1(bytes[0]) {
194 1
195 } else if is_leading_byte_width_2(bytes[0]) {
196 2
197 } else if is_leading_byte_width_3(bytes[0]) {
198 3
199 } else {
200 4
201 }
202}
203
204pub open spec fn not_overlong_encoding(codepoint: u32, len: int) -> bool {
207 &&& (len == 2 ==> 0x80 <= codepoint)
208 &&& (len == 3 ==> 0x800 <= codepoint)
209 &&& (len == 4 ==> 0x10000 <= codepoint <= 0x10ffff)
210}
211
212pub open spec fn not_surrogate(codepoint: u32) -> bool {
215 !(0xD800 <= codepoint <= 0xDFFF)
216}
217
218pub open spec fn valid_first_scalar(bytes: Seq<u8>) -> bool {
222 &&& valid_leading_and_continuation_bytes_first_codepoint(bytes)
223 &&& not_overlong_encoding(decode_first_codepoint(bytes), length_of_first_codepoint(bytes))
224 &&& not_surrogate(decode_first_codepoint(bytes))
225}
226
227pub open spec fn decode_first_scalar(bytes: Seq<u8>) -> u32
229 recommends
230 valid_first_scalar(bytes),
231{
232 decode_first_codepoint(bytes)
233}
234
235pub open spec fn length_of_first_scalar(bytes: Seq<u8>) -> int
237 recommends
238 valid_first_scalar(bytes),
239{
240 length_of_first_codepoint(bytes)
241}
242
243pub open spec fn pop_first_scalar(bytes: Seq<u8>) -> Seq<u8>
245 recommends
246 valid_first_scalar(bytes),
247{
248 bytes.subrange(length_of_first_scalar(bytes), bytes.len() as int)
249}
250
251proof fn lemma_pop_first_scalar_decreases(bytes: Seq<u8>)
252 requires
253 valid_first_scalar(bytes),
254 ensures
255 pop_first_scalar(bytes).len() < bytes.len(),
256{
257 assert(length_of_first_scalar(bytes) <= bytes.len() as int);
258 assert(pop_first_scalar(bytes).len() == bytes.len() as int - length_of_first_scalar(bytes)) by {
259 lemma_seq_subrange_len(bytes, length_of_first_scalar(bytes), bytes.len() as int)
260 };
261}
262
263pub open spec fn take_first_scalar(bytes: Seq<u8>) -> Seq<u8>
265 recommends
266 valid_first_scalar(bytes),
267{
268 bytes.subrange(0, length_of_first_scalar(bytes))
269}
270
271pub open spec fn valid_utf8(bytes: Seq<u8>) -> bool
273 decreases bytes.len(),
274{
275 bytes.len() != 0 ==> valid_first_scalar(bytes) && valid_utf8(pop_first_scalar(bytes))
276}
277
278pub open spec fn decode_utf8(bytes: Seq<u8>) -> Seq<char>
280 recommends
281 valid_utf8(bytes),
282 decreases bytes.len(),
283 when valid_utf8(bytes)
284{
285 if bytes.len() == 0 {
286 seq![]
287 } else {
288 seq![decode_first_scalar(bytes) as char] + decode_utf8(pop_first_scalar(bytes))
289 }
290}
291
292pub open spec fn length_of_last_scalar(bytes: Seq<u8>) -> int
294 recommends
295 valid_utf8(bytes),
296 bytes.len() > 0,
297{
298 let n = bytes.len() as int;
299 if !is_continuation_byte(bytes[n - 1]) {
300 1
301 } else if !is_continuation_byte(bytes[n - 2]) {
302 2
303 } else if !is_continuation_byte(bytes[n - 3]) {
304 3
305 } else {
306 4
307 }
308}
309
310pub open spec fn take_last_scalar(bytes: Seq<u8>) -> Seq<u8>
312 recommends
313 valid_utf8(bytes),
314 bytes.len() > 0,
315{
316 let len = length_of_last_scalar(bytes);
317 bytes.subrange(bytes.len() - len, bytes.len() as int)
318}
319
320pub open spec fn decode_last_scalar(bytes: Seq<u8>) -> u32
322 recommends
323 valid_utf8(bytes),
324 bytes.len() > 0,
325{
326 let n = bytes.len() as int;
327 if !is_continuation_byte(bytes[n - 1]) {
328 codepoint_width_1(bytes[n - 1])
329 } else if !is_continuation_byte(bytes[n - 2]) {
330 codepoint_width_2(bytes[n - 2], bytes[n - 1])
331 } else if !is_continuation_byte(bytes[n - 3]) {
332 codepoint_width_3(bytes[n - 3], bytes[n - 2], bytes[n - 1])
333 } else {
334 codepoint_width_4(bytes[n - 4], bytes[n - 3], bytes[n - 2], bytes[n - 1])
335 }
336}
337
338pub open spec fn has_width_1_encoding(v: u32) -> bool {
342 0 <= v <= 0x7F
343}
344
345pub open spec fn has_width_2_encoding(v: u32) -> bool {
347 0x80 <= v <= 0x7FF
348}
349
350pub open spec fn has_width_3_encoding(v: u32) -> bool {
352 0x800 <= v <= 0xFFFF && !(0xD800 <= v <= 0xDFFF)
353}
354
355pub open spec fn has_width_4_encoding(v: u32) -> bool {
357 0x10000 <= v <= 0x10FFFF
358}
359
360pub open spec fn is_scalar(v: u32) -> bool {
363 ||| has_width_1_encoding(v)
364 ||| has_width_2_encoding(v)
365 ||| has_width_3_encoding(v)
366 ||| has_width_4_encoding(v)
367}
368
369pub open spec fn leading_byte_width_1(scalar: u32) -> u8
371 recommends
372 has_width_1_encoding(scalar),
373{
374 (scalar & 0x7F) as u8
375}
376
377pub open spec fn leading_byte_width_2(scalar: u32) -> u8
379 recommends
380 has_width_2_encoding(scalar),
381{
382 0xC0 | ((scalar >> 6) & 0x1F) as u8
383}
384
385pub open spec fn leading_byte_width_3(scalar: u32) -> u8
387 recommends
388 has_width_3_encoding(scalar),
389{
390 0xE0 | ((scalar >> 12) & 0x0F) as u8
391}
392
393pub open spec fn leading_byte_width_4(scalar: u32) -> u8
395 recommends
396 has_width_4_encoding(scalar),
397{
398 0xF0 | ((scalar >> 18) & 0x7) as u8
399}
400
401pub open spec fn last_continuation_byte(scalar: u32) -> u8
403 recommends
404 has_width_2_encoding(scalar) || has_width_3_encoding(scalar) || has_width_4_encoding(
405 scalar,
406 ),
407{
408 0x80 | (scalar & 0x3F) as u8
409}
410
411pub open spec fn second_last_continuation_byte(scalar: u32) -> u8
413 recommends
414 has_width_3_encoding(scalar) || has_width_4_encoding(scalar),
415{
416 0x80 | ((scalar >> 6) & 0x3F) as u8
417}
418
419pub open spec fn third_last_continuation_byte(scalar: u32) -> u8
421 recommends
422 has_width_4_encoding(scalar),
423{
424 0x80 | ((scalar >> 12) & 0x3F) as u8
425}
426
427pub open spec fn encode_scalar(scalar: u32) -> Seq<u8>
429 recommends
430 is_scalar(scalar),
431{
432 if has_width_1_encoding(scalar) {
433 seq![leading_byte_width_1(scalar)]
434 } else if has_width_2_encoding(scalar) {
435 seq![leading_byte_width_2(scalar), last_continuation_byte(scalar)]
436 } else if has_width_3_encoding(scalar) {
437 seq![
438 leading_byte_width_3(scalar),
439 second_last_continuation_byte(scalar),
440 last_continuation_byte(scalar),
441 ]
442 } else {
443 seq![
444 leading_byte_width_4(scalar),
445 third_last_continuation_byte(scalar),
446 second_last_continuation_byte(scalar),
447 last_continuation_byte(scalar),
448 ]
449 }
450}
451
452pub open spec fn encode_utf8(chars: Seq<char>) -> Seq<u8>
454 decreases chars.len(),
455{
456 if chars.len() == 0 {
457 seq![]
458 } else {
459 encode_scalar(chars[0] as u32) + encode_utf8(chars.drop_first())
460 }
461}
462
463pub broadcast proof fn encode_utf8_concat(a: Seq<char>, b: Seq<char>)
468 ensures
469 #[trigger] encode_utf8(a + b) == encode_utf8(a) + encode_utf8(b),
470 decreases a.len(),
471{
472 if a.len() == 0 {
473 assert(a + b =~= b);
474 } else {
475 assert((a + b).drop_first() =~= a.drop_first() + b);
476 encode_utf8_concat(a.drop_first(), b);
477 assert(encode_scalar(a[0] as u32) + (encode_utf8(a.drop_first()) + encode_utf8(b)) =~= (
478 encode_scalar(a[0] as u32) + encode_utf8(a.drop_first())) + encode_utf8(b));
479 }
480}
481
482pub broadcast proof fn encode_utf8_push(chars: Seq<char>, c: char)
484 ensures
485 #[trigger] encode_utf8(chars.push(c)) == encode_utf8(chars) + encode_scalar(c as u32),
486{
487 assert(chars.push(c) =~= chars + seq![c]);
488 encode_utf8_concat(chars, seq![c]);
489 assert(seq![c].drop_first() =~= Seq::<char>::empty());
490 assert(encode_utf8(seq![c]) =~= encode_scalar(c as u32) + encode_utf8(Seq::<char>::empty()));
491}
492
493pub proof fn lemma_encode_utf8_len_strictly_monotonic(s: Seq<char>, i: int, j: int)
496 requires
497 0 <= i < j <= s.len(),
498 ensures
499 encode_utf8(s.subrange(0, i)).len() < encode_utf8(s.subrange(0, j)).len(),
500{
501 assert(s.subrange(0, i) + s.subrange(i, j) =~= s.subrange(0, j));
502 encode_utf8_concat(s.subrange(0, i), s.subrange(i, j));
503 assert(s.subrange(i, j).len() == j - i);
504}
505
506proof fn encode_decode_width_1(c: u32)
510 by (bit_vector)
511 requires
512 has_width_1_encoding(c),
513 ensures
514 ({
515 let b1 = leading_byte_width_1(c);
516 &&& is_leading_byte_width_1(b1)
517 &&& codepoint_width_1(b1) == c
518 }),
519{
520}
521
522proof fn decode_encode_width_1(b1: u8)
524 by (bit_vector)
525 requires
526 is_leading_byte_width_1(b1),
527 ensures
528 ({
529 let c = codepoint_width_1(b1);
530 &&& has_width_1_encoding(c)
531 &&& leading_byte_width_1(c) == b1
532 }),
533{
534}
535
536proof fn encode_decode_width_2(c: u32)
538 by (bit_vector)
539 requires
540 has_width_2_encoding(c),
541 ensures
542 ({
543 let b1 = leading_byte_width_2(c);
544 let b2 = last_continuation_byte(c);
545 &&& is_leading_byte_width_2(b1)
546 &&& is_continuation_byte(b2)
547 &&& codepoint_width_2(b1, b2) == c
548 }),
549{
550}
551
552proof fn decode_encode_width_2(b1: u8, b2: u8)
554 by (bit_vector)
555 requires
556 is_leading_byte_width_2(b1),
557 is_continuation_byte(b2),
558 not_overlong_encoding(codepoint_width_2(b1, b2), 2),
559 ensures
560 ({
561 let c = codepoint_width_2(b1, b2);
562 &&& has_width_2_encoding(c)
563 &&& leading_byte_width_2(c) == b1
564 &&& last_continuation_byte(c) == b2
565 }),
566{
567}
568
569proof fn encode_decode_width_3(c: u32)
571 by (bit_vector)
572 requires
573 has_width_3_encoding(c),
574 ensures
575 ({
576 let b1 = leading_byte_width_3(c);
577 let b2 = second_last_continuation_byte(c);
578 let b3 = last_continuation_byte(c);
579 &&& is_leading_byte_width_3(b1)
580 &&& is_continuation_byte(b2)
581 &&& is_continuation_byte(b3)
582 &&& codepoint_width_3(b1, b2, b3) == c
583 }),
584{
585}
586
587proof fn decode_encode_width_3(b1: u8, b2: u8, b3: u8)
589 by (bit_vector)
590 requires
591 is_leading_byte_width_3(b1),
592 is_continuation_byte(b2),
593 is_continuation_byte(b3),
594 not_overlong_encoding(codepoint_width_3(b1, b2, b3), 3),
595 not_surrogate(codepoint_width_3(b1, b2, b3)),
596 ensures
597 ({
598 let c = codepoint_width_3(b1, b2, b3);
599 &&& has_width_3_encoding(c)
600 &&& leading_byte_width_3(c) == b1
601 &&& second_last_continuation_byte(c) == b2
602 &&& last_continuation_byte(c) == b3
603 }),
604{
605}
606
607proof fn encode_decode_width_4(c: u32)
609 by (bit_vector)
610 requires
611 has_width_4_encoding(c),
612 ensures
613 ({
614 let b1 = leading_byte_width_4(c);
615 let b2 = third_last_continuation_byte(c);
616 let b3 = second_last_continuation_byte(c);
617 let b4 = last_continuation_byte(c);
618 &&& is_leading_byte_width_4(b1)
619 &&& is_continuation_byte(b2)
620 &&& is_continuation_byte(b3)
621 &&& is_continuation_byte(b4)
622 &&& codepoint_width_4(b1, b2, b3, b4) == c
623 }),
624{
625}
626
627proof fn decode_encode_width_4(b1: u8, b2: u8, b3: u8, b4: u8)
629 by (bit_vector)
630 requires
631 is_leading_byte_width_4(b1),
632 is_continuation_byte(b2),
633 is_continuation_byte(b3),
634 is_continuation_byte(b4),
635 not_overlong_encoding(codepoint_width_4(b1, b2, b3, b4), 4),
636 ensures
637 ({
638 let c = codepoint_width_4(b1, b2, b3, b4);
639 &&& has_width_4_encoding(c)
640 &&& leading_byte_width_4(c) == b1
641 &&& third_last_continuation_byte(c) == b2
642 &&& second_last_continuation_byte(c) == b3
643 &&& last_continuation_byte(c) == b4
644 }),
645{
646}
647
648pub broadcast proof fn char_is_scalar(c: char)
650 ensures
651 is_scalar(#[trigger] (c as u32)),
652{
653}
654
655pub broadcast proof fn char_u32_cast(c: char, u: u32)
657 requires
658 u == #[trigger] (c as u32),
659 ensures
660 #[trigger] (u as char) == c,
661{
662}
663
664pub proof fn encode_utf8_first_scalar(chars: Seq<char>)
666 requires
667 chars.len() > 0,
668 ensures
669 decode_first_scalar(encode_utf8(chars)) == chars[0] as u32,
670 length_of_first_scalar(encode_utf8(chars)) == encode_scalar(chars[0] as u32).len(),
671 valid_first_scalar(encode_utf8(chars)),
672{
673 char_is_scalar(chars[0]);
674 let s = chars[0] as u32;
675 if has_width_1_encoding(s) {
676 encode_decode_width_1(s);
677 } else if has_width_2_encoding(s) {
678 encode_decode_width_2(s);
679 } else if has_width_3_encoding(s) {
680 encode_decode_width_3(s);
681 } else {
682 encode_decode_width_4(s);
683 }
684}
685
686pub broadcast proof fn encode_utf8_valid_utf8(chars: Seq<char>)
688 ensures
689 valid_utf8(#[trigger] encode_utf8(chars)),
690 decreases chars.len(),
691{
692 if chars.len() == 0 {
693 } else {
694 let bytes = encode_utf8(chars);
695 encode_utf8_first_scalar(chars);
696 assert(pop_first_scalar(bytes) =~= encode_utf8(chars.drop_first()));
697 encode_utf8_valid_utf8(chars.drop_first());
698 }
699}
700
701pub broadcast proof fn encode_utf8_decode_utf8(chars: Seq<char>)
703 ensures
704 #[trigger] decode_utf8(encode_utf8(chars)) == chars,
705 decreases chars.len(),
706{
707 broadcast use encode_utf8_valid_utf8;
708
709 if chars.len() == 0 {
710 } else {
711 let bytes = encode_utf8(chars);
712 encode_utf8_first_scalar(chars);
713 char_u32_cast(chars[0], decode_first_scalar(bytes));
714
715 assert(pop_first_scalar(bytes) =~= encode_utf8(chars.drop_first()));
716 let rest = chars.drop_first();
717 encode_utf8_decode_utf8(rest);
718 }
719}
720
721pub proof fn decode_utf8_first_scalar(bytes: Seq<u8>)
723 requires
724 valid_utf8(bytes),
725 bytes.len() > 0,
726 ensures
727 encode_scalar((decode_first_scalar(bytes) as char) as u32) == take_first_scalar(bytes),
728{
729 if is_leading_byte_width_1(bytes[0]) {
730 decode_encode_width_1(bytes[0]);
731 } else if is_leading_byte_width_2(bytes[0]) {
732 decode_encode_width_2(bytes[0], bytes[1]);
733 } else if is_leading_byte_width_3(bytes[0]) {
734 decode_encode_width_3(bytes[0], bytes[1], bytes[2]);
735 } else {
736 decode_encode_width_4(bytes[0], bytes[1], bytes[2], bytes[3]);
737 }
738}
739
740pub broadcast proof fn decode_utf8_encode_utf8(bytes: Seq<u8>)
742 requires
743 valid_utf8(bytes),
744 ensures
745 #[trigger] encode_utf8(decode_utf8(bytes)) == bytes,
746 decreases bytes.len(),
747{
748 broadcast use encode_utf8_valid_utf8;
749
750 if bytes.len() == 0 {
751 } else {
752 let chars = decode_utf8(bytes);
753 let first = decode_first_scalar(bytes) as char;
754 let rest = pop_first_scalar(bytes);
755
756 char_is_scalar(first);
757 assert(encode_scalar(first as u32) == take_first_scalar(bytes)) by {
758 decode_utf8_first_scalar(bytes);
759 }
760
761 assert(chars.drop_first() =~= decode_utf8(rest));
762 decode_utf8_encode_utf8(rest);
763 }
764}
765
766pub open spec fn partial_valid_utf8(bytes: Seq<u8>, i: int) -> bool {
770 0 <= i <= bytes.len() && valid_utf8(bytes.subrange(0, i))
771}
772
773pub proof fn partial_valid_partial_invalid_utf8(bytes: Seq<u8>, i: int)
775 requires
776 0 <= i <= bytes.len(),
777 valid_utf8(bytes.subrange(0, i)),
778 !valid_utf8(bytes.subrange(i, bytes.len() as int)),
779 ensures
780 !valid_utf8(bytes),
781{
782 partial_valid_utf8_invalid_subrange_helper(bytes, i, 0);
783 assert(bytes.subrange(0, bytes.len() as int) =~= bytes);
784}
785
786proof fn partial_valid_utf8_invalid_subrange_helper(bytes: Seq<u8>, i: int, j: int)
787 requires
788 0 <= j <= i <= bytes.len(),
789 valid_utf8(bytes.subrange(0, i)),
790 !valid_utf8(bytes.subrange(i, bytes.len() as int)),
791 valid_utf8(bytes.subrange(0, j)),
792 valid_utf8(bytes.subrange(j, i)),
793 ensures
794 !valid_utf8(bytes.subrange(j, bytes.len() as int)),
795 decreases (bytes.len() - j),
796{
797 if j == i {
798 } else {
799 let bytes_j = bytes.subrange(j, bytes.len() as int);
800 if valid_first_scalar(bytes_j) {
801 partial_valid_utf8_extend(bytes, j);
802 let k = length_of_first_scalar(bytes_j);
803
804 assert(pop_first_scalar(bytes.subrange(j, i)) == bytes.subrange(j + k, i));
805
806 partial_valid_utf8_invalid_subrange_helper(bytes, i, j + k);
807
808 assert(bytes_j.subrange(k, bytes_j.len() as int) == bytes.subrange(
809 j + k,
810 bytes.len() as int,
811 ));
812 }
813 }
814}
815
816pub broadcast proof fn valid_utf8_concat(b1: Seq<u8>, b2: Seq<u8>)
818 requires
819 #[trigger] valid_utf8(b1),
820 #[trigger] valid_utf8(b2),
821 ensures
822 #[trigger] valid_utf8(b1 + b2),
823 decreases b1.len(),
824{
825 if b1.len() == 0 {
826 assert(b1 + b2 == b2) by { Seq::add_empty_left(b1, b2) };
827 assert(valid_utf8(b1 + b2));
828 } else {
829 let rest = pop_first_scalar(b1);
830 assert(pop_first_scalar(b1).len() < b1.len()) by { lemma_pop_first_scalar_decreases(b1) };
831 valid_utf8_concat(rest, b2);
832 assert(pop_first_scalar(b1 + b2) =~= rest + b2);
833 assert(valid_utf8(b1 + b2));
834 }
835}
836
837pub broadcast proof fn partial_valid_utf8_extend(bytes: Seq<u8>, i: int)
840 requires
841 #[trigger] partial_valid_utf8(bytes, i),
842 #[trigger] valid_first_scalar(bytes.subrange(i, bytes.len() as int)),
843 ensures
844 #[trigger] partial_valid_utf8(
845 bytes,
846 i + length_of_first_scalar(bytes.subrange(i, bytes.len() as int)),
847 ),
848{
849 reveal_with_fuel(valid_utf8, 2);
850 let scalar = bytes.subrange(
851 i,
852 i + length_of_first_scalar(bytes.subrange(i, bytes.len() as int)),
853 );
854 valid_utf8_concat(bytes.subrange(0, i), scalar);
855 assert(bytes.subrange(0, i) + scalar =~= bytes.subrange(
856 0,
857 i + length_of_first_scalar(bytes.subrange(i, bytes.len() as int)),
858 ));
859}
860
861pub broadcast proof fn partial_valid_utf8_extend_ascii_block(bytes: Seq<u8>, start: int, end: int)
864 requires
865 forall|i: int|
866 0 <= start <= i < end <= bytes.len() ==> #[trigger] is_leading_byte_width_1(bytes[i]),
867 partial_valid_utf8(bytes, start),
868 0 <= start <= end <= bytes.len(),
869 ensures
870 #![trigger partial_valid_utf8(bytes, start), partial_valid_utf8(bytes, end)]
871 partial_valid_utf8(bytes, end),
872 decreases end - start,
873{
874 if end == start {
875 } else {
876 partial_valid_utf8_extend_ascii_block(bytes, start, end - 1);
877
878 let b = bytes[end - 1];
879 assert(is_leading_byte_width_1(b));
880 partial_valid_utf8_extend(bytes, end - 1);
881 }
882}
883
884pub open spec fn is_char_boundary(bytes: Seq<u8>, index: int) -> bool
888 recommends
889 valid_utf8(bytes),
890 decreases bytes.len(),
891 when valid_utf8(bytes)
892{
893 if index == 0 {
894 true
895 } else if index < 0 || bytes.len() < index {
896 false
897 } else {
898 is_char_boundary(pop_first_scalar(bytes), index - length_of_first_scalar(bytes))
899 }
900}
901
902proof fn take_first_scalar_valid_utf8(bytes: Seq<u8>)
903 requires
904 valid_utf8(bytes),
905 ensures
906 bytes.len() > 0 ==> valid_utf8(take_first_scalar(bytes)),
907{
908 reveal_with_fuel(valid_utf8, 2);
909}
910
911pub broadcast proof fn valid_utf8_split(bytes: Seq<u8>, index: int)
913 requires
914 valid_utf8(bytes),
915 is_char_boundary(bytes, index),
916 ensures
917 #![trigger valid_utf8(bytes.subrange(0, index)), is_char_boundary(bytes, index)]
918 #![trigger valid_utf8(bytes.subrange(index, bytes.len() as int)), is_char_boundary(bytes, index)]
919 valid_utf8(bytes.subrange(0, index)),
920 valid_utf8(bytes.subrange(index, bytes.len() as int)),
921 decreases bytes.len(),
922{
923 if index == 0 {
924 assert(bytes =~= bytes.subrange(index, bytes.len() as int));
925 } else {
926 broadcast use lemma_seq_subrange_len;
927
928 let s1 = bytes.subrange(0, index);
929 let s2 = bytes.subrange(index, bytes.len() as int);
930 let head = take_first_scalar(bytes);
931 let tail = pop_first_scalar(bytes);
932 let new_offset = index - length_of_first_scalar(bytes);
933 valid_utf8_split(tail, new_offset);
935 let n1 = tail.subrange(0, new_offset);
936 let n2 = tail.subrange(new_offset, tail.len() as int);
937 assert(s1 =~= head + n1) by {
939 assert(s1.len() == head.len() + n1.len()) by {
940 is_char_boundary_len_first_scalar(bytes, index);
942 }
943 }
944 assert(valid_utf8(head + n1)) by {
945 take_first_scalar_valid_utf8(bytes);
946 valid_utf8_concat(head, n1);
947 }
948 assert(s2 =~= n2);
949 }
950}
951
952pub broadcast proof fn decode_utf8_split(bytes: Seq<u8>, index: int)
954 requires
955 valid_utf8(bytes),
956 is_char_boundary(bytes, index),
957 ensures
958 #![trigger decode_utf8(bytes.subrange(0, index)), is_char_boundary(bytes, index)]
959 #![trigger decode_utf8(bytes.subrange(index, bytes.len() as int)), is_char_boundary(bytes, index)]
960 decode_utf8(bytes) =~= decode_utf8(bytes.subrange(0, index)) + decode_utf8(
961 bytes.subrange(index, bytes.len() as int),
962 ),
963 decreases index,
964{
965 if index == 0 {
966 assert(bytes.subrange(index, bytes.len() as int) =~= bytes);
967 } else {
968 let first = bytes.subrange(0, index);
969 let second = bytes.subrange(index, bytes.len() as int);
970 is_char_boundary_len_first_scalar(bytes, index);
971 valid_utf8_split(bytes, index);
972 let bytes_tail = pop_first_scalar(bytes);
973 let first_tail = pop_first_scalar(first);
974 let bytes_head = decode_first_scalar(bytes) as char;
975 let first_head = decode_first_scalar(first) as char;
976 let new_index = (index - length_of_first_scalar(bytes)) as int;
977 decode_utf8_split(bytes_tail, new_index);
978 assert(second =~= bytes_tail.subrange(new_index, bytes_tail.len() as int));
979 assert(first_tail =~= bytes_tail.subrange(0, new_index));
980 }
981}
982
983proof fn is_char_boundary_len_first_scalar(bytes: Seq<u8>, index: int)
984 requires
985 valid_utf8(bytes),
986 is_char_boundary(bytes, index),
987 ensures
988 index > 0 ==> index >= length_of_first_scalar(bytes),
989{
990 reveal_with_fuel(is_char_boundary, 2);
991}
992
993pub broadcast proof fn is_char_boundary_start_end_of_seq(bytes: Seq<u8>)
995 requires
996 valid_utf8(bytes),
997 ensures
998 #![trigger is_char_boundary(bytes, 0)]
999 #![trigger is_char_boundary(bytes, bytes.len() as int)]
1000 is_char_boundary(bytes, 0),
1001 is_char_boundary(bytes, bytes.len() as int),
1002 decreases bytes.len(),
1003{
1004 if bytes.len() == 0 {
1005 } else {
1006 is_char_boundary_start_end_of_seq(pop_first_scalar(bytes));
1007 }
1008}
1009
1010pub broadcast proof fn is_char_boundary_iff_not_is_continuation_byte(bytes: Seq<u8>, index: int)
1012 requires
1013 valid_utf8(bytes),
1014 0 <= index < bytes.len(),
1015 ensures
1016 #[trigger] is_char_boundary(bytes, index) <==> !(#[trigger] is_continuation_byte(
1017 bytes[index],
1018 )),
1019 decreases bytes.len(),
1020{
1021 if 0 <= index < length_of_first_scalar(bytes) {
1022 reveal_with_fuel(is_char_boundary, 2);
1023 } else {
1024 is_char_boundary_iff_not_is_continuation_byte(
1025 pop_first_scalar(bytes),
1026 index - length_of_first_scalar(bytes),
1027 );
1028 }
1029}
1030
1031pub broadcast proof fn is_char_boundary_iff_is_leading_byte(bytes: Seq<u8>, index: int)
1033 requires
1034 valid_utf8(bytes),
1035 0 <= index < bytes.len(),
1036 ensures
1037 #![trigger is_char_boundary(bytes, index), is_leading_byte_width_1(bytes[index])]
1038 #![trigger is_char_boundary(bytes, index), is_leading_byte_width_2(bytes[index])]
1039 #![trigger is_char_boundary(bytes, index), is_leading_byte_width_3(bytes[index])]
1040 #![trigger is_char_boundary(bytes, index), is_leading_byte_width_4(bytes[index])]
1041 is_char_boundary(bytes, index) <==> (is_leading_byte_width_1(bytes[index])
1042 || is_leading_byte_width_2(bytes[index]) || is_leading_byte_width_3(bytes[index])
1043 || is_leading_byte_width_4(bytes[index])),
1044 decreases bytes.len(),
1045{
1046 if 0 <= index < length_of_first_scalar(bytes) {
1047 reveal_with_fuel(is_char_boundary, 2);
1048 } else {
1049 is_char_boundary_iff_is_leading_byte(
1050 pop_first_scalar(bytes),
1051 index - length_of_first_scalar(bytes),
1052 );
1053 }
1054}
1055
1056pub broadcast proof fn valid_utf8_last(s: Seq<u8>)
1057 requires
1058 valid_utf8(s),
1059 s.len() > 0,
1060 ensures
1061 #![trigger is_continuation_byte(s.last())]
1062 #![trigger is_leading_byte_width_1(s.last())]
1063 !is_continuation_byte(s.last()) ==> is_leading_byte_width_1(s.last()),
1064 decreases s.len(),
1065{
1066 let first = decode_first_scalar(s);
1069 let rest = pop_first_scalar(s);
1070
1071 if rest.len() == 0 {
1072 if s.len() > 1 {
1073 assert(is_continuation_byte(s[s.len() - 1]));
1074 }
1075 } else {
1076 valid_utf8_last(rest);
1077 }
1078}
1079
1080pub broadcast proof fn utf8_byte_ranges_bitwise(b: u8)
1084 by (bit_vector)
1085 ensures
1086 #![trigger b & 0x80]
1087 #![trigger b & 0xf0]
1088 #![trigger b & 0xf8]
1089 #![trigger b & 0xe0]
1090 #![trigger b & 0xc0]
1091 0x00 <= b <= 0x7f <==> b & 0x80 == 0,
1092 0xc0 <= b <= 0xdf <==> b & 0xe0 == 0xc0,
1093 0xe0 <= b <= 0xef <==> b & 0xf0 == 0xe0,
1094 0xf0 <= b <= 0xf7 <==> b & 0xf8 == 0xf0,
1095 0x80 <= b <= 0xbf <==> b & 0xc0 == 0x80,
1096{
1097}
1098
1099pub open spec fn is_ascii_chars(chars: Seq<char>) -> bool {
1103 forall|i| 0 <= i < chars.len() ==> '\0' <= #[trigger] chars[i] <= '\u{7f}'
1104}
1105
1106pub broadcast proof fn is_ascii_chars_encode_utf8(chars: Seq<char>)
1108 requires
1109 #[trigger] is_ascii_chars(chars),
1110 ensures
1111 chars.len() == encode_utf8(chars).len(),
1112 forall|i|
1113 #![trigger chars[i]]
1114 #![trigger encode_utf8(chars)[i]]
1115 0 <= i < chars.len() ==> chars[i] as u8 == encode_utf8(chars)[i],
1116 decreases chars.len(),
1117{
1118 if chars.len() == 0 {
1119 } else {
1120 let c0 = chars[0] as u32;
1121 assert(c0 as u8 == leading_byte_width_1(c0)) by (bit_vector)
1122 requires
1123 has_width_1_encoding(c0),
1124 ;
1125 is_ascii_chars_encode_utf8(chars.drop_first());
1126 }
1127}
1128
1129pub broadcast proof fn is_ascii_chars_nat_bound(chars: Seq<char>)
1131 ensures
1132 #[trigger] is_ascii_chars(chars) ==> forall|i: int|
1133 0 <= i < chars.len() ==> (chars.index(i) as nat) < 128,
1134{
1135}
1136
1137pub broadcast proof fn is_ascii_chars_concat(c1: Seq<char>, c2: Seq<char>, c3: Seq<char>)
1139 requires
1140 c1 =~= c2 + c3,
1141 ensures
1142 #![trigger c2 + c3, is_ascii_chars(c1), is_ascii_chars(c2), is_ascii_chars(c3)]
1143 is_ascii_chars(c1) <==> is_ascii_chars(c2) && is_ascii_chars(c3),
1144{
1145 if (is_ascii_chars(c1)) {
1146 assert(c2 =~= c1.subrange(0, c2.len() as int));
1147 assert(c3 =~= c1.subrange(c2.len() as int, c1.len() as int));
1148 }
1149}
1150
1151pub broadcast group group_utf8_lib {
1152 encode_utf8_valid_utf8,
1153 encode_utf8_decode_utf8,
1154 decode_utf8_encode_utf8,
1155 char_is_scalar,
1156 char_u32_cast,
1157 valid_utf8_concat,
1158 partial_valid_utf8_extend,
1159 partial_valid_utf8_extend_ascii_block,
1160 valid_utf8_split,
1161 decode_utf8_split,
1162 is_char_boundary_start_end_of_seq,
1163 is_char_boundary_iff_not_is_continuation_byte,
1164 is_char_boundary_iff_is_leading_byte,
1165 valid_utf8_last,
1166 utf8_byte_ranges_bitwise,
1167 is_ascii_chars_encode_utf8,
1168 is_ascii_chars_nat_bound,
1169 is_ascii_chars_concat,
1170 encode_utf8_concat,
1171 encode_utf8_push,
1172}
1173
1174}