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