@@ -155,6 +155,7 @@ let is_circular_buffer
155155 Spec. ranges_match_contents repr st . contents ( SZ. v cbi . bo ) /\
156156 RMSpec. range_map_wf repr /\
157157 Spec. repr_well_positioned repr ( SZ. v cbi . bo ) /\
158+ ( Seq. length repr = 0 \/ ( Seq. index repr 0 ). low >= SZ. v cbi . bo ) /\
158159 Seq. length repr < RM. max_range_vec_entries
159160 )
160161
@@ -559,6 +560,17 @@ fn write_buffer_core
559560 // cf == cpl after write
560561 Spec. write_preserves_cf_eq_cpl repr st . contents ( SZ. v cb_val . bo ) ( SZ. v offset ) ( reveal src_data );
561562
563+ // Bounded: add_range preserves boundedness
564+ RMSpec. add_range_bounded repr ( SZ. v abs_offset ) ( SZ. v write_len ) ( SZ. v cb_val . bo + SZ. v cb_val . al );
565+
566+ // Count bound: first.low >= bo preserved by add_range
567+ RMSpec. add_range_first_low repr ( SZ. v abs_offset ) ( SZ. v write_len ) ( SZ. v cb_val . bo );
568+ // now: |add_range repr ...| > 0 /\ first'.low >= bo
569+ // so repr_count_bound_gap applies
570+ Spec. repr_count_bound_gap ( RMSpec. add_range repr ( SZ. v abs_offset ) ( SZ. v write_len ))
571+ ( SZ. v cb_val . bo ) ( SZ. v cb_val . al );
572+ // gives: 2 * |repr'| <= al + 1 <= pow2_63 + 1, so |repr'| <= pow2_62 < max
573+
562574 fold ( is_circular_buffer cb rm
563575 { st with contents =
564576 GT. write_range_contents_t st . contents ( SZ. v offset ) ( reveal src_data ) });
@@ -780,6 +792,14 @@ fn write_buffer
780792 Spec. write_preserves_rwp repr2 ( SZ. v cb_val2 . bo ) ( SZ. v rel_offset ) ( SZ. v trimmed_len );
781793 Spec. write_preserves_cf_eq_cpl repr2 ( reveal rs_st ). contents ( SZ. v cb_val2 . bo ) ( SZ. v rel_offset ) ( reveal trimmed_data );
782794
795+ // Bounded: add_range preserves boundedness
796+ RMSpec. add_range_bounded repr2 ( SZ. v rm_abs ) ( SZ. v trimmed_len ) ( SZ. v cb_val2 . bo + SZ. v cb_val2 . al );
797+
798+ // Count bound: first.low >= bo preserved, then derive count < max
799+ RMSpec. add_range_first_low repr2 ( SZ. v rm_abs ) ( SZ. v trimmed_len ) ( SZ. v cb_val2 . bo );
800+ Spec. repr_count_bound_gap ( RMSpec. add_range repr2 ( SZ. v rm_abs ) ( SZ. v trimmed_len ))
801+ ( SZ. v cb_val2 . bo ) ( SZ. v cb_val2 . al );
802+
783803 fold ( is_circular_buffer cb rm
784804 { Spec. resize_result st ( SZ. v new_al ) with contents = reveal new_st_contents });
785805 { wrote = true ; new_data_ready = ndr ; resize_failed = false }
@@ -863,6 +883,14 @@ fn write_buffer
863883 Spec. write_preserves_rwp repr ( SZ. v cb_val . bo ) ( SZ. v rel_offset ) ( SZ. v trimmed_len );
864884 Spec. write_preserves_cf_eq_cpl repr st . contents ( SZ. v cb_val . bo ) ( SZ. v rel_offset ) ( reveal trimmed_data );
865885
886+ // Bounded: add_range preserves boundedness
887+ RMSpec. add_range_bounded repr ( SZ. v rm_abs ) ( SZ. v trimmed_len ) ( SZ. v cb_val . bo + SZ. v cb_val . al );
888+
889+ // Count bound: first.low >= bo preserved, then derive count < max
890+ RMSpec. add_range_first_low repr ( SZ. v rm_abs ) ( SZ. v trimmed_len ) ( SZ. v cb_val . bo );
891+ Spec. repr_count_bound_gap ( RMSpec. add_range repr ( SZ. v rm_abs ) ( SZ. v trimmed_len ))
892+ ( SZ. v cb_val . bo ) ( SZ. v cb_val . al );
893+
866894 fold ( is_circular_buffer cb rm
867895 { st with contents =
868896 GT. write_range_contents_t st . contents ( SZ. v rel_offset ) ( reveal trimmed_data ) });
@@ -897,32 +925,45 @@ fn drain
897925 let new_rs = SZ. rem temp cb_val . al ;
898926 let new_bo = SZ. add cb_val . bo n ;
899927
900- // Compute new prefix length from range map with new base_offset
901- let new_pl = RM. range_vec_contiguous_from rm new_bo ;
902-
903- let new_cbi = Mkcb_internal cb_val . buf new_rs cb_val . al new_pl cb_val . vl new_bo ;
904- ( := ) cb new_cbi ;
905- rewrite ( Vec. pts_to cb_val . buf buf_data ) as ( Vec. pts_to new_cbi . buf buf_data );
906-
907- // Physical coherence preserved under drain
908- Spec. drain_preserves_coherence st . alloc_length buf_data st . contents st . read_start ( SZ. v n );
909-
910- // Bridge preserved by index substitution with padding (trivial!)
911- Spec. ranges_match_drain_padded repr st . contents ( SZ. v cb_val . bo ) ( SZ. v n );
912-
913- // repr_well_positioned preserved
914- Spec. drain_preserves_rwp repr ( SZ. v cb_val . bo ) ( SZ. v n );
915-
916- // cf == cpl after drain
917- Spec. rwp_cf_eq_cpl repr
918- ( Spec. drained_contents st . alloc_length st . contents ( SZ. v n ))
919- ( SZ. v new_bo );
920-
921- // Drain prefix: new_cpl = old_cpl - n, so new_cpl == 0 iff old_cpl == n
922- Spec. drain_prefix_length st . alloc_length st . contents ( SZ. v n );
923-
924- fold ( is_circular_buffer cb rm ( Spec. drain_result st ( SZ. v n )));
925- SZ. eq new_pl 0sz
928+ if ( SZ. gt n 0sz) {
929+ // n > 0: drain range vec + fold with drain_repr
930+ RM. range_vec_drain rm new_bo ;
931+
932+ let new_pl = RM. range_vec_contiguous_from rm new_bo ;
933+ let new_cbi = Mkcb_internal cb_val . buf new_rs cb_val . al new_pl cb_val . vl new_bo ;
934+ ( := ) cb new_cbi ;
935+ rewrite ( Vec. pts_to cb_val . buf buf_data ) as ( Vec. pts_to new_cbi . buf buf_data );
936+
937+ Spec. drain_preserves_coherence st . alloc_length buf_data st . contents st . read_start ( SZ. v n );
938+ Spec. ranges_match_drain_repr repr st . contents ( SZ. v cb_val . bo ) ( SZ. v n );
939+ RMSpec. drain_repr_wf repr ( SZ. v new_bo );
940+ Spec. drain_repr_preserves_rwp repr ( SZ. v cb_val . bo ) ( SZ. v n );
941+ Spec. rwp_cf_eq_cpl ( RMSpec. drain_repr repr ( SZ. v new_bo ))
942+ ( Spec. drained_contents st . alloc_length st . contents ( SZ. v n ))
943+ ( SZ. v new_bo );
944+ Spec. drain_prefix_length st . alloc_length st . contents ( SZ. v n );
945+ RMSpec. drain_repr_length repr ( SZ. v new_bo );
946+
947+ fold ( is_circular_buffer cb rm ( Spec. drain_result st ( SZ. v n )));
948+ SZ. eq new_pl 0sz
949+ } else {
950+ // n = 0: no drain, fold with original repr
951+ let new_pl = RM. range_vec_contiguous_from rm new_bo ;
952+ let new_cbi = Mkcb_internal cb_val . buf new_rs cb_val . al new_pl cb_val . vl new_bo ;
953+ ( := ) cb new_cbi ;
954+ rewrite ( Vec. pts_to cb_val . buf buf_data ) as ( Vec. pts_to new_cbi . buf buf_data );
955+
956+ Spec. drain_preserves_coherence st . alloc_length buf_data st . contents st . read_start ( SZ. v n );
957+ Spec. ranges_match_drain_padded repr st . contents ( SZ. v cb_val . bo ) ( SZ. v n );
958+ Spec. drain_preserves_rwp repr ( SZ. v cb_val . bo ) ( SZ. v n );
959+ Spec. rwp_cf_eq_cpl repr
960+ ( Spec. drained_contents st . alloc_length st . contents ( SZ. v n ))
961+ ( SZ. v new_bo );
962+ Spec. drain_prefix_length st . alloc_length st . contents ( SZ. v n );
963+
964+ fold ( is_circular_buffer cb rm ( Spec. drain_result st ( SZ. v n )));
965+ SZ. eq new_pl 0sz
966+ }
926967}
927968# pop - options
928969
0 commit comments