@@ -308,6 +308,154 @@ impl<V: Ord> Range<V> {
308
308
}
309
309
}
310
310
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
+
311
459
/// The ordering of the version wrt to the interval.
312
460
/// ```text
313
461
/// |-------|
@@ -1069,4 +1217,33 @@ pub mod tests {
1069
1217
range. simplify( versions. into_iter( ) )
1070
1218
) ;
1071
1219
}
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
+ }
1072
1249
}
0 commit comments