@@ -826,6 +826,87 @@ impl<V: Ord + Clone> Ranges<V> {
826826 }
827827}
828828
829+ impl < V : Ord + Debug > FromIterator < ( Bound < V > , Bound < V > ) > for Ranges < V > {
830+ /// Constructor from arbitrary, unsorted and potentially overlapping ranges.
831+ ///
832+ /// This is equivalent to computing the [`Ranges::union`] of the [`Range::from_range_bounds`] of
833+ /// each segment.
834+ fn from_iter < T : IntoIterator < Item = ( Bound < V > , Bound < V > ) > > ( iter : T ) -> Self {
835+ // We have three constraints we need to fulfil:
836+ // 1. The segments are sorted, from lowest to highest (through `Ord`): By sorting.
837+ // 2. Each segment contains at least one version (start < end): By `union`.
838+ // 3. There is at least one version between two segments: By `union`.
839+ let mut segments: SmallVec < [ Interval < V > ; 1 ] > = SmallVec :: new ( ) ;
840+
841+ for segment in iter {
842+ if !valid_segment ( & segment. start_bound ( ) , & segment. end_bound ( ) ) {
843+ continue ;
844+ }
845+ // Find where to insert the new segment
846+ let insertion_point = segments. partition_point ( |elem : & Interval < V > | {
847+ cmp_bounds_start ( elem. start_bound ( ) , segment. start_bound ( ) )
848+ . unwrap ( )
849+ . is_lt ( )
850+ } ) ;
851+ // Is it overlapping with the previous segment?
852+ let previous_overlapping = insertion_point > 0
853+ && !end_before_start_with_gap (
854+ & segments[ insertion_point - 1 ] . end_bound ( ) ,
855+ & segment. start_bound ( ) ,
856+ ) ;
857+
858+ // Is it overlapping with the following segment?
859+ let next_overlapping = insertion_point < segments. len ( )
860+ && !end_before_start_with_gap (
861+ & segment. end_bound ( ) ,
862+ & segments[ insertion_point] . start_bound ( ) ,
863+ ) ;
864+
865+ match ( previous_overlapping, next_overlapping) {
866+ ( true , true ) => {
867+ // previous: |-------|
868+ // segment: |-------|
869+ // following: |-----|
870+ //
871+ // final: |--------------------|
872+ // We merge all three segments into one, which is effectively removing one of
873+ // two previously inserted and changing the bounds on the other.
874+ let following = segments. remove ( insertion_point) ;
875+ segments[ insertion_point - 1 ] . 1 = following. 1 ;
876+ }
877+ ( true , false ) => {
878+ // previous: |-----|
879+ // segment: |-----|
880+ // following: |-----|
881+ //
882+ // final: |---------| |-----|
883+ // We can reuse the existing element by extending it.
884+ segments[ insertion_point - 1 ] . 1 = segment. 1 ;
885+ }
886+ ( false , true ) => {
887+ // previous: |-----|
888+ // segment: |-----|
889+ // following: |-----|
890+ //
891+ // final: |-----| |---------|
892+ // We can reuse the existing element by extending it.
893+ segments[ insertion_point] . 0 = segment. 0 ;
894+ }
895+ ( false , false ) => {
896+ // previous: |-----|
897+ // segment: |-----|
898+ // following: |-----|
899+ //
900+ // final: |-----| |-----| |-----|
901+ segments. insert ( insertion_point, segment) ;
902+ }
903+ }
904+ }
905+
906+ Self { segments }
907+ }
908+ }
909+
829910// REPORT ######################################################################
830911
831912impl < V : Display + Eq > Display for Ranges < V > {
@@ -1130,6 +1211,12 @@ pub mod tests {
11301211 }
11311212 assert!( simp. segments. len( ) <= range. segments. len( ) )
11321213 }
1214+
1215+ #[ test]
1216+ fn from_iter_valid( segments in proptest:: collection:: vec( any:: <( Bound <u32 >, Bound <u32 >) >( ) , ..30 ) ) {
1217+ // We check invariants in the method.
1218+ Ranges :: from_iter( segments. clone( ) ) ;
1219+ }
11331220 }
11341221
11351222 #[ test]
@@ -1166,6 +1253,15 @@ pub mod tests {
11661253 ) ;
11671254 }
11681255
1256+ #[ test]
1257+ fn from_iter_regression ( ) {
1258+ Ranges :: from_iter ( [
1259+ ( Included ( 0 ) , Included ( 0 ) ) ,
1260+ ( Excluded ( 1u32 ) , Unbounded ) ,
1261+ ( Included ( 0 ) , Included ( 0 ) ) ,
1262+ ] ) ;
1263+ }
1264+
11691265 #[ test]
11701266 fn version_ord ( ) {
11711267 let versions: & [ Ranges < u32 > ] = & [
0 commit comments