@@ -308,6 +308,104 @@ impl<V: Ord> Range<V> {
308308 }
309309}
310310
311+ /// Implementing `PartialOrd` for start `Bound` of an interval.
312+ ///
313+ /// Legend: `∞` is unbounded, `[1,2]` is `>1,<2`, `]1,2[` is `>=1,<=2`.
314+ ///
315+ /// ```text
316+ /// left: ∞-------]
317+ /// right: [-----]
318+ /// left is smaller, since it starts earlier.
319+ ///
320+ /// left: [-----]
321+ /// right: ]-----]
322+ /// left is smaller, since it starts earlier.
323+ /// ```
324+ fn cmp_bounds_start < V : PartialOrd > ( left : Bound < & V > , right : Bound < & V > ) -> Option < Ordering > {
325+ match ( left, right) {
326+ ( Unbounded , Unbounded ) => Some ( Ordering :: Equal ) ,
327+ ( Included ( _left) , Unbounded ) => Some ( Ordering :: Greater ) ,
328+ ( Excluded ( _left) , Unbounded ) => Some ( Ordering :: Greater ) ,
329+ ( Unbounded , Included ( _right) ) => Some ( Ordering :: Less ) ,
330+ ( Included ( left) , Included ( right) ) => left. partial_cmp ( right) ,
331+ ( Excluded ( left) , Included ( right) ) => match left. partial_cmp ( right) ? {
332+ Ordering :: Less => Some ( Ordering :: Less ) ,
333+ Ordering :: Equal => Some ( Ordering :: Greater ) ,
334+ Ordering :: Greater => Some ( Ordering :: Greater ) ,
335+ } ,
336+ ( Unbounded , Excluded ( _right) ) => Some ( Ordering :: Less ) ,
337+ ( Included ( left) , Excluded ( right) ) => match left. partial_cmp ( right) ? {
338+ Ordering :: Less => Some ( Ordering :: Less ) ,
339+ Ordering :: Equal => Some ( Ordering :: Less ) ,
340+ Ordering :: Greater => Some ( Ordering :: Greater ) ,
341+ } ,
342+ ( Excluded ( left) , Excluded ( right) ) => left. partial_cmp ( right) ,
343+ }
344+ }
345+
346+ /// Implementing `PartialOrd` for end `Bound` of an interval.
347+ ///
348+ /// We flip the unbounded ranges from `-∞` to `∞`, while `V`-valued bounds checks remain the same.
349+ ///
350+ /// Legend: `∞` is unbounded, `[1,2]` is `>1,<2`, `]1,2[` is `>=1,<=2`.
351+ ///
352+ /// ```text
353+ /// left: [--------∞
354+ /// right: [-----]
355+ /// left is greater, since it starts earlier.
356+ ///
357+ /// left: [-----[
358+ /// right: [-----]
359+ /// left is smaller, since it ends earlier.
360+ /// ```
361+ fn cmp_bounds_end < V : PartialOrd > ( left : Bound < & V > , right : Bound < & V > ) -> Option < Ordering > {
362+ match ( left, right) {
363+ ( Unbounded , Unbounded ) => Some ( Ordering :: Equal ) ,
364+ ( Included ( _left) , Unbounded ) => Some ( Ordering :: Less ) ,
365+ ( Excluded ( _left) , Unbounded ) => Some ( Ordering :: Less ) ,
366+ ( Unbounded , Included ( _right) ) => Some ( Ordering :: Greater ) ,
367+ ( Included ( left) , Included ( right) ) => left. partial_cmp ( right) ,
368+ ( Excluded ( left) , Included ( right) ) => match left. partial_cmp ( right) ? {
369+ Ordering :: Less => Some ( Ordering :: Less ) ,
370+ Ordering :: Equal => Some ( Ordering :: Less ) ,
371+ Ordering :: Greater => Some ( Ordering :: Greater ) ,
372+ } ,
373+ ( Unbounded , Excluded ( _right) ) => Some ( Ordering :: Greater ) ,
374+ ( Included ( left) , Excluded ( right) ) => match left. partial_cmp ( right) ? {
375+ Ordering :: Less => Some ( Ordering :: Less ) ,
376+ Ordering :: Equal => Some ( Ordering :: Greater ) ,
377+ Ordering :: Greater => Some ( Ordering :: Greater ) ,
378+ } ,
379+ ( Excluded ( left) , Excluded ( right) ) => left. partial_cmp ( right) ,
380+ }
381+ }
382+
383+ impl < V : PartialOrd > PartialOrd for Range < V > {
384+ /// A simple ordering scheme where we zip the segments and compare all bounds in order. If all
385+ /// bounds are equal, the longer range is considered greater. (And if all zipped bounds are
386+ /// equal and we have the same number of segments, the ranges are equal).
387+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
388+ for ( left, right) in self . segments . iter ( ) . zip ( other. segments . iter ( ) ) {
389+ let start_cmp = cmp_bounds_start ( left. start_bound ( ) , right. start_bound ( ) ) ?;
390+ if start_cmp != Ordering :: Equal {
391+ return Some ( start_cmp) ;
392+ }
393+ let end_cmp = cmp_bounds_end ( left. end_bound ( ) , right. end_bound ( ) ) ?;
394+ if end_cmp != Ordering :: Equal {
395+ return Some ( end_cmp) ;
396+ }
397+ }
398+ Some ( self . segments . len ( ) . cmp ( & other. segments . len ( ) ) )
399+ }
400+ }
401+
402+ impl < V : Ord > Ord for Range < V > {
403+ fn cmp ( & self , other : & Self ) -> Ordering {
404+ self . partial_cmp ( other)
405+ . expect ( "PartialOrd must be `Some(Ordering)` for types that implement `Ord`" )
406+ }
407+ }
408+
311409/// The ordering of the version wrt to the interval.
312410/// ```text
313411/// |-------|
@@ -1069,4 +1167,26 @@ pub mod tests {
10691167 range. simplify( versions. into_iter( ) )
10701168 ) ;
10711169 }
1170+
1171+ #[ test]
1172+ fn version_ord ( ) {
1173+ let versions: & [ Range < u32 > ] = & [
1174+ Range :: strictly_lower_than ( 1u32 ) ,
1175+ Range :: lower_than ( 1u32 ) ,
1176+ Range :: singleton ( 1u32 ) ,
1177+ Range :: between ( 1u32 , 3u32 ) ,
1178+ Range :: higher_than ( 1u32 ) ,
1179+ Range :: strictly_higher_than ( 1u32 ) ,
1180+ Range :: singleton ( 2u32 ) ,
1181+ Range :: singleton ( 2u32 ) . union ( & Range :: singleton ( 3u32 ) ) ,
1182+ Range :: singleton ( 2u32 )
1183+ . union ( & Range :: singleton ( 3u32 ) )
1184+ . union ( & Range :: singleton ( 4u32 ) ) ,
1185+ Range :: singleton ( 2u32 ) . union ( & Range :: singleton ( 4u32 ) ) ,
1186+ Range :: singleton ( 3u32 ) ,
1187+ ] ;
1188+ let mut versions_sorted = versions. to_vec ( ) ;
1189+ versions_sorted. sort ( ) ;
1190+ assert_eq ! ( versions_sorted, versions) ;
1191+ }
10721192}
0 commit comments