@@ -308,6 +308,154 @@ 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+ Some ( match ( left, right) {
326+ // left: ∞-----
327+ // right: ∞-----
328+ ( Unbounded , Unbounded ) => Ordering :: Equal ,
329+ // left: [---
330+ // right: ∞-----
331+ ( Included ( _left) , Unbounded ) => Ordering :: Greater ,
332+ // left: ]---
333+ // right: ∞-----
334+ ( Excluded ( _left) , Unbounded ) => Ordering :: Greater ,
335+ // left: ∞-----
336+ // right: [---
337+ ( Unbounded , Included ( _right) ) => Ordering :: Less ,
338+ // left: [----- OR [----- OR [-----
339+ // right: [--- OR [----- OR [---
340+ ( Included ( left) , Included ( right) ) => left. partial_cmp ( right) ?,
341+ ( Excluded ( left) , Included ( right) ) => match left. partial_cmp ( right) ? {
342+ // left: ]-----
343+ // right: [---
344+ Ordering :: Less => Ordering :: Less ,
345+ // left: ]-----
346+ // right: [---
347+ Ordering :: Equal => Ordering :: Greater ,
348+ // left: ]---
349+ // right: [-----
350+ Ordering :: Greater => Ordering :: Greater ,
351+ } ,
352+ // left: ∞-----
353+ // right: ]---
354+ ( Unbounded , Excluded ( _right) ) => Ordering :: Less ,
355+ ( Included ( left) , Excluded ( right) ) => match left. partial_cmp ( right) ? {
356+ // left: [-----
357+ // right: ]---
358+ Ordering :: Less => Ordering :: Less ,
359+ // left: [-----
360+ // right: ]---
361+ Ordering :: Equal => Ordering :: Less ,
362+ // left: [---
363+ // right: ]-----
364+ Ordering :: Greater => Ordering :: Greater ,
365+ } ,
366+ // left: ]----- OR ]----- OR ]---
367+ // right: ]--- OR ]----- OR ]-----
368+ ( Excluded ( left) , Excluded ( right) ) => left. partial_cmp ( right) ?,
369+ } )
370+ }
371+
372+ /// Implementing `PartialOrd` for end `Bound` of an interval.
373+ ///
374+ /// We flip the unbounded ranges from `-∞` to `∞`, while `V`-valued bounds checks remain the same.
375+ ///
376+ /// Legend: `∞` is unbounded, `[1,2]` is `>=1,<=2`, `]1,2[` is `>1,<2`.
377+ ///
378+ /// ```text
379+ /// left: [--------∞
380+ /// right: [-----]
381+ /// left is greater, since it starts earlier.
382+ ///
383+ /// left: [-----[
384+ /// right: [-----]
385+ /// left is smaller, since it ends earlier.
386+ /// ```
387+ fn cmp_bounds_end < V : PartialOrd > ( left : Bound < & V > , right : Bound < & V > ) -> Option < Ordering > {
388+ Some ( match ( left, right) {
389+ // left: -----∞
390+ // right: -----∞
391+ ( Unbounded , Unbounded ) => Ordering :: Equal ,
392+ // left: ---]
393+ // right: -----∞
394+ ( Included ( _left) , Unbounded ) => Ordering :: Less ,
395+ // left: ---[
396+ // right: -----∞
397+ ( Excluded ( _left) , Unbounded ) => Ordering :: Less ,
398+ // left: -----∞
399+ // right: ---]
400+ ( Unbounded , Included ( _right) ) => Ordering :: Greater ,
401+ // left: -----] OR -----] OR ---]
402+ // right: ---] OR -----] OR -----]
403+ ( Included ( left) , Included ( right) ) => left. partial_cmp ( right) ?,
404+ ( Excluded ( left) , Included ( right) ) => match left. partial_cmp ( right) ? {
405+ // left: ---[
406+ // right: -----]
407+ Ordering :: Less => Ordering :: Less ,
408+ // left: -----[
409+ // right: -----]
410+ Ordering :: Equal => Ordering :: Less ,
411+ // left: -----[
412+ // right: ---]
413+ Ordering :: Greater => Ordering :: Greater ,
414+ } ,
415+ ( Unbounded , Excluded ( _right) ) => Ordering :: Greater ,
416+ ( Included ( left) , Excluded ( right) ) => match left. partial_cmp ( right) ? {
417+ // left: ---]
418+ // right: -----[
419+ Ordering :: Less => Ordering :: Less ,
420+ // left: -----]
421+ // right: -----[
422+ Ordering :: Equal => Ordering :: Greater ,
423+ // left: -----]
424+ // right: ---[
425+ Ordering :: Greater => Ordering :: Greater ,
426+ } ,
427+ // left: -----[ OR -----[ OR ---[
428+ // right: ---[ OR -----[ OR -----[
429+ ( Excluded ( left) , Excluded ( right) ) => left. partial_cmp ( right) ?,
430+ } )
431+ }
432+
433+ impl < V : PartialOrd > PartialOrd for Range < V > {
434+ /// A simple ordering scheme where we zip the segments and compare all bounds in order. If all
435+ /// bounds are equal, the longer range is considered greater. (And if all zipped bounds are
436+ /// equal and we have the same number of segments, the ranges are equal).
437+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
438+ for ( left, right) in self . segments . iter ( ) . zip ( other. segments . iter ( ) ) {
439+ let start_cmp = cmp_bounds_start ( left. start_bound ( ) , right. start_bound ( ) ) ?;
440+ if start_cmp != Ordering :: Equal {
441+ return Some ( start_cmp) ;
442+ }
443+ let end_cmp = cmp_bounds_end ( left. end_bound ( ) , right. end_bound ( ) ) ?;
444+ if end_cmp != Ordering :: Equal {
445+ return Some ( end_cmp) ;
446+ }
447+ }
448+ Some ( self . segments . len ( ) . cmp ( & other. segments . len ( ) ) )
449+ }
450+ }
451+
452+ impl < V : Ord > Ord for Range < V > {
453+ fn cmp ( & self , other : & Self ) -> Ordering {
454+ self . partial_cmp ( other)
455+ . expect ( "PartialOrd must be `Some(Ordering)` for types that implement `Ord`" )
456+ }
457+ }
458+
311459/// The ordering of the version wrt to the interval.
312460/// ```text
313461/// |-------|
@@ -1069,4 +1217,33 @@ pub mod tests {
10691217 range. simplify( versions. into_iter( ) )
10701218 ) ;
10711219 }
1220+
1221+ #[ test]
1222+ fn version_ord ( ) {
1223+ let versions: & [ Range < u32 > ] = & [
1224+ Range :: strictly_lower_than ( 1u32 ) ,
1225+ Range :: lower_than ( 1u32 ) ,
1226+ Range :: singleton ( 1u32 ) ,
1227+ Range :: between ( 1u32 , 3u32 ) ,
1228+ Range :: higher_than ( 1u32 ) ,
1229+ Range :: strictly_higher_than ( 1u32 ) ,
1230+ Range :: singleton ( 2u32 ) ,
1231+ Range :: singleton ( 2u32 ) . union ( & Range :: singleton ( 3u32 ) ) ,
1232+ Range :: singleton ( 2u32 )
1233+ . union ( & Range :: singleton ( 3u32 ) )
1234+ . union ( & Range :: singleton ( 4u32 ) ) ,
1235+ Range :: singleton ( 2u32 ) . union ( & Range :: singleton ( 4u32 ) ) ,
1236+ Range :: singleton ( 3u32 ) ,
1237+ ] ;
1238+
1239+ let mut versions_sorted = versions. to_vec ( ) ;
1240+ versions_sorted. sort ( ) ;
1241+ assert_eq ! ( versions_sorted, versions) ;
1242+
1243+ // Check that the sorting isn't just stable because we're returning equal.
1244+ let mut version_reverse_sorted = versions. to_vec ( ) ;
1245+ version_reverse_sorted. reverse ( ) ;
1246+ version_reverse_sorted. sort ( ) ;
1247+ assert_eq ! ( version_reverse_sorted, versions) ;
1248+ }
10721249}
0 commit comments