1pub use range_traits::{Measure, PartialEnum};
2use std::{
3 cmp::PartialOrd,
4 ops::{Bound, RangeBounds},
5};
6
7mod bound;
8mod ordering;
9
10mod any;
11mod from_excluded;
12mod from_excluded_to;
13mod from_excluded_to_included;
14
15pub use any::*;
16pub use bound::*;
17pub use from_excluded::*;
18pub use from_excluded_to::*;
19pub use from_excluded_to_included::*;
20pub use ordering::*;
21
22pub trait AsRange: Sized {
24 type Item: Measure + PartialEnum;
26
27 fn start(&self) -> Bound<&Self::Item>;
29
30 fn end(&self) -> Bound<&Self::Item>;
32
33 fn is_empty(&self) -> bool {
34 is_range_empty(self.start(), self.end())
35 }
36
37 fn intersects<R: AsRange>(&self, other: &R) -> bool
38 where
39 Self::Item: PartialOrd<R::Item> + Measure<R::Item>,
40 {
41 matches!(
42 self.range_partial_cmp(other),
43 Some(RangeOrdering::Intersecting(_, _))
44 )
45 }
46
47 fn connected_to<R: AsRange>(&self, other: &R) -> bool
48 where
49 Self::Item: PartialOrd<R::Item> + Measure<R::Item>,
50 {
51 match self.range_partial_cmp(other) {
52 Some(RangeOrdering::Intersecting(_, _)) => true,
53 Some(RangeOrdering::Before(connected)) => connected,
54 Some(RangeOrdering::After(connected)) => connected,
55 _ => false,
56 }
57 }
58
59 fn intersected_with<'a, R: AsRange<Item = Self::Item>>(
60 &'a self,
61 other: &'a R,
62 ) -> AnyRange<&'a Self::Item>
63 where
64 Self::Item: PartialOrd + Measure,
65 {
66 AnyRange {
67 start: max_bound(self.start(), other.start(), true),
68 end: min_bound(self.end(), other.end(), false),
69 }
70 }
71
72 fn without<'a, R: AsRange<Item = Self::Item>>(
73 &'a self,
74 other: &'a R,
75 ) -> Difference<&'a Self::Item>
76 where
77 Self::Item: PartialOrd + Measure,
78 {
79 let left = match invert_bound(other.start()) {
80 Some(inverted_other_start) => {
81 if !is_range_empty(self.start(), inverted_other_start) {
82 Some(AnyRange {
83 start: self.start(),
84 end: inverted_other_start,
85 })
86 } else {
87 None
88 }
89 }
90 None => None,
91 };
92
93 let right = match invert_bound(other.end()) {
94 Some(inverted_other_end) => {
95 if !is_range_empty(inverted_other_end, self.end()) {
96 Some(AnyRange {
97 start: inverted_other_end,
98 end: self.end(),
99 })
100 } else {
101 None
102 }
103 }
104 None => None,
105 };
106
107 match (left, right) {
108 (Some(left), None) => Difference::Before(
109 left,
110 Directed::End(left.end) >= Directed::Start(other.start()),
111 ),
112 (None, Some(right)) => Difference::After(
113 right,
114 Directed::Start(right.start) <= Directed::End(other.end()),
115 ),
116 (Some(left), Some(right)) => Difference::Split(left, right),
117 (None, None) => Difference::Empty,
118 }
119 }
120
121 fn product<'a, R: AsRange<Item = Self::Item>>(&'a self, other: &'a R) -> Product<&'a Self::Item>
122 where
123 Self::Item: PartialOrd + Measure,
124 {
125 let before = match crop_right(self, other.start()) {
126 Some(self_before) => Some(ProductArg::Subject(self_before)),
127 None => crop_right(other, self.start()).map(ProductArg::Object),
128 };
129
130 let intersection = self.intersected_with(other);
131 let intersection = if is_range_empty(intersection.start, intersection.end) {
132 None
133 } else {
134 Some(intersection)
135 };
136
137 let after = match crop_left(self, other.end()) {
138 Some(self_after) => Some(ProductArg::Subject(self_after)),
139 None => crop_left(other, self.end()).map(ProductArg::Object),
140 };
141
142 Product {
143 before,
144 intersection,
145 after,
146 }
147 }
148}
149
150pub trait IntoRange: AsRange {
151 fn into_range(self) -> AnyRange<Self::Item>;
152}
153
154fn crop_left<'a, R: AsRange>(
155 range: &'a R,
156 other_end: Bound<&'a R::Item>,
157) -> Option<AnyRange<&'a R::Item>> {
158 match invert_bound(other_end) {
159 Some(inverted_other_end) => {
160 let max_start = max_bound(range.start(), inverted_other_end, true);
161 if !is_range_empty(max_start, range.end()) {
162 Some(AnyRange {
163 start: inverted_other_end,
164 end: range.end(),
165 })
166 } else {
167 None
168 }
169 }
170 None => None,
171 }
172}
173
174fn crop_right<'a, R: AsRange>(
175 range: &'a R,
176 other_start: Bound<&'a R::Item>,
177) -> Option<AnyRange<&'a R::Item>> {
178 match invert_bound(other_start) {
179 Some(inverted_other_start) => {
180 let min_end = min_bound(range.end(), inverted_other_start, false);
181 if !is_range_empty(range.start(), min_end) {
182 Some(AnyRange {
183 start: range.start(),
184 end: min_end,
185 })
186 } else {
187 None
188 }
189 }
190 None => None,
191 }
192}
193
194#[derive(Debug)]
196pub enum ProductArg<T> {
197 Subject(AnyRange<T>),
199
200 Object(AnyRange<T>),
202}
203
204impl<T: Clone> ProductArg<&T> {
205 pub fn cloned(&self) -> ProductArg<T> {
206 match self {
207 ProductArg::Subject(range) => ProductArg::Subject(range.cloned()),
208 ProductArg::Object(range) => ProductArg::Object(range.cloned()),
209 }
210 }
211}
212
213#[derive(Debug)]
215pub struct Product<T> {
216 pub before: Option<ProductArg<T>>,
218
219 pub intersection: Option<AnyRange<T>>,
221
222 pub after: Option<ProductArg<T>>,
224}
225
226impl<T: Clone> Product<&T> {
227 pub fn cloned(&self) -> Product<T> {
228 Product {
229 before: self.before.as_ref().map(|r| r.cloned()),
230 intersection: self.intersection.as_ref().map(|r| r.cloned()),
231 after: self.after.as_ref().map(|r| r.cloned()),
232 }
233 }
234}
235
236pub enum RelativePosition {
237 Before,
238 After,
239}
240
241pub enum Difference<T> {
243 Before(AnyRange<T>, bool),
245
246 After(AnyRange<T>, bool),
248
249 Split(AnyRange<T>, AnyRange<T>),
251
252 Empty,
254}
255
256macro_rules! singleton_range {
257 ($ty:ident) => {
258 impl AsRange for $ty {
259 type Item = Self;
260
261 fn start(&self) -> Bound<&Self::Item> {
262 Bound::Included(self)
263 }
264
265 fn end(&self) -> Bound<&Self::Item> {
266 Bound::Included(self)
267 }
268 }
269
270 impl IntoRange for $ty {
271 fn into_range(self) -> AnyRange<Self::Item> {
272 AnyRange::new(Bound::Included(self), Bound::Included(self))
273 }
274 }
275 };
276}
277
278singleton_range!(u8);
279singleton_range!(i8);
280singleton_range!(u16);
281singleton_range!(i16);
282singleton_range!(u32);
283singleton_range!(i32);
284singleton_range!(u64);
285singleton_range!(i64);
286singleton_range!(usize);
289singleton_range!(f32);
291singleton_range!(f64);
292singleton_range!(char);
293
294macro_rules! standard_range {
295 ($ty:path, |$this:ident| $into_range:expr) => {
296 impl<T: Measure + PartialEnum> AsRange for $ty {
297 type Item = T;
298
299 fn start(&self) -> Bound<&Self::Item> {
300 self.start_bound()
301 }
302
303 fn end(&self) -> Bound<&Self::Item> {
304 self.end_bound()
305 }
306 }
307
308 impl<T: Measure + PartialEnum> IntoRange for $ty {
309 fn into_range($this) -> AnyRange<Self::Item> {
310 $into_range
311 }
312 }
313 };
314}
315
316standard_range!(std::ops::Range<T>, |self| AnyRange::new(
317 Bound::Included(self.start),
318 Bound::Excluded(self.end)
319));
320standard_range!(std::ops::RangeInclusive<T>, |self| {
321 let (a, b) = self.into_inner();
322 AnyRange::new(Bound::Included(a), Bound::Included(b))
323});
324standard_range!(std::ops::RangeFrom<T>, |self| AnyRange::new(
325 Bound::Included(self.start),
326 Bound::Unbounded
327));
328standard_range!(std::ops::RangeTo<T>, |self| AnyRange::new(
329 Bound::Unbounded,
330 Bound::Excluded(self.end)
331));
332standard_range!(std::ops::RangeToInclusive<T>, |self| AnyRange::new(
333 Bound::Unbounded,
334 Bound::Included(self.end)
335));
336standard_range!(AnyRange<T>, |self| self);
337standard_range!(RangeFromExcluded<T>, |self| AnyRange::new(
338 Bound::Excluded(self.start),
339 Bound::Unbounded
340));
341standard_range!(RangeFromExcludedTo<T>, |self| AnyRange::new(
342 Bound::Excluded(self.start),
343 Bound::Excluded(self.end)
344));
345standard_range!(RangeFromExcludedToIncluded<T>, |self| AnyRange::new(
346 Bound::Excluded(self.start),
347 Bound::Included(self.end)
348));
349
350#[inline(always)]
351fn is_range_empty<T, U>(start: Bound<&T>, end: Bound<&U>) -> bool
352where
353 T: PartialOrd<U> + Measure<U> + PartialEnum,
354 U: PartialEnum,
355{
356 Directed::Start(start) > Directed::End(end)
357}
358
359#[cfg(test)]
360mod tests {
361 use crate::RangeSet;
362
363 use super::*;
364 use std::cmp::Ordering;
365
366 macro_rules! make_bound {
367 ([= $v:literal ..]) => {
368 Directed::Start(Bound::Included(&$v))
369 };
370 ([$v:literal ..]) => {
371 Directed::Start(Bound::Excluded(&$v))
372 };
373 ([~ ..]) => {
374 Directed::Start(Bound::Unbounded)
375 };
376 ([..= $v:literal]) => {
377 Directed::End(Bound::Included(&$v))
378 };
379 ([.. $v:literal]) => {
380 Directed::End(Bound::Excluded(&$v))
381 };
382 ([.. ~]) => {
383 Directed::End(Bound::Unbounded)
384 };
385 }
386
387 macro_rules! test_bound_cmp {
388 (@assert $ty:ty, $a:tt, $b:tt, $expected:ident) => {
389 assert_eq!(<Directed<Bound<&$ty>> as PartialOrd>::partial_cmp(&make_bound!($a), &make_bound!($b)), Some(Ordering::$expected));
390 };
391 ($ty:ty, $a:tt < $b:tt) => {
392 test_bound_cmp!(@assert $ty, $a, $b, Less)
393 };
394 ($ty:ty, $a:tt == $b:tt) => {
395 test_bound_cmp!(@assert $ty, $a, $b, Equal)
396 };
397 ($ty:ty, $a:tt > $b:tt) => {
398 test_bound_cmp!(@assert $ty, $a, $b, Greater)
399 }
400 }
401
402 #[test]
403 fn issue_2() {
404 let k = AnyRange {
405 start: Bound::Excluded(0u32),
406 end: Bound::Unbounded,
407 };
408 assert!(!k.is_empty());
409
410 let mut ids: RangeSet<u32> = RangeSet::new();
411 ids.insert(0u32);
412
413 let mut gaps = ids.gaps();
414 assert_eq!(
415 gaps.next().unwrap().cloned(),
416 AnyRange::new(Bound::Excluded(0), Bound::Unbounded)
417 );
418 assert_eq!(gaps.next().map(AnyRange::cloned), None);
419 }
420
421 #[test]
422 fn unsigned_integer_bound_partial_less() {
423 test_bound_cmp!(u32, [=0..] < [=1..]);
424 test_bound_cmp!(u32, [=0..] < [0..]);
425 test_bound_cmp!(u32, [=0..] < [..=1]);
426 test_bound_cmp!(u32, [=0..] < [..2]);
427 test_bound_cmp!(u32, [=0..] < [..~]);
428
429 test_bound_cmp!(u32, [0..] < [=2..]);
430 test_bound_cmp!(u32, [0..] < [1..]);
431 test_bound_cmp!(u32, [0..] < [..=2]);
432 test_bound_cmp!(u32, [0..] < [..3]);
433 test_bound_cmp!(u32, [0..] < [..~]);
434
435 test_bound_cmp!(u32, [~..] < [..=0]);
436 test_bound_cmp!(u32, [~..] < [..~]);
437
438 test_bound_cmp!(u32, [..=0] < [=1..]);
439 test_bound_cmp!(u32, [..=0] < [0..]);
440 test_bound_cmp!(u32, [..=0] < [..=1]);
441 test_bound_cmp!(u32, [..=0] < [..2]);
442 test_bound_cmp!(u32, [..=0] < [..~]);
443
444 test_bound_cmp!(u32, [..1] < [=1..]);
445 test_bound_cmp!(u32, [..1] < [0..]);
446 test_bound_cmp!(u32, [..1] < [..=1]);
447 test_bound_cmp!(u32, [..1] < [..2]);
448 test_bound_cmp!(u32, [..0] < [..~]);
449 }
450
451 #[test]
452 fn unsigned_integer_bound_partial_eq() {
453 test_bound_cmp!(u32, [~..] == [=0..]);
454 }
455
456 #[test]
457 fn unsigned_integer_bound_partial_greater() {
458 test_bound_cmp!(u32, [~..] > [..0]);
459 }
460
461 #[test]
462 fn integer_bound_partial_less() {
463 test_bound_cmp!(i32, [=0..] < [=1..]);
464 test_bound_cmp!(i32, [=0..] < [0..]);
465 test_bound_cmp!(i32, [=0..] < [..=1]);
466 test_bound_cmp!(i32, [=0..] < [..2]);
467 test_bound_cmp!(i32, [=0..] < [..~]);
468
469 test_bound_cmp!(i32, [0..] < [=2..]);
470 test_bound_cmp!(i32, [0..] < [1..]);
471 test_bound_cmp!(i32, [0..] < [..=2]);
472 test_bound_cmp!(i32, [0..] < [..3]);
473 test_bound_cmp!(i32, [0..] < [..~]);
474 test_bound_cmp!(i32, [-2_147_483_648i32..] < [..~]);
475
476 test_bound_cmp!(i32, [~..] < [=0..]);
477 test_bound_cmp!(i32, [~..] < [..=0]);
478 test_bound_cmp!(i32, [~..] < [..0]);
479 test_bound_cmp!(i32, [~..] < [..~]);
480
481 test_bound_cmp!(i32, [..=0] < [=1..]);
482 test_bound_cmp!(i32, [..=0] < [0..]);
483 test_bound_cmp!(i32, [..=0] < [..=1]);
484 test_bound_cmp!(i32, [..=0] < [..2]);
485 test_bound_cmp!(i32, [..=0] < [..~]);
486
487 test_bound_cmp!(i32, [..1] < [=1..]);
488 test_bound_cmp!(i32, [..1] < [0..]);
489 test_bound_cmp!(i32, [..1] < [..=1]);
490 test_bound_cmp!(i32, [..1] < [..2]);
491 test_bound_cmp!(i32, [..0] < [..~]);
492 }
493
494 #[test]
495 fn integer_bound_partial_eq() {
496 test_bound_cmp!(i32, [=0..] == [=0..]);
497 test_bound_cmp!(i32, [=1..] == [0..]);
498 test_bound_cmp!(i32, [=0..] == [..=0]);
499 test_bound_cmp!(i32, [=0..] == [..1]);
500
501 test_bound_cmp!(i32, [0..] == [=1..]);
502 test_bound_cmp!(i32, [0..] == [0..]);
503 test_bound_cmp!(i32, [0..] == [..=1]);
504 test_bound_cmp!(i32, [0..] == [..2]);
505
506 test_bound_cmp!(i32, [~..] == [~..]);
507
508 test_bound_cmp!(i32, [..=0] == [=0..]);
509 test_bound_cmp!(i32, [..=1] == [0..]);
510 test_bound_cmp!(i32, [..=0] == [..=0]);
511 test_bound_cmp!(i32, [..=0] == [..1]);
512
513 test_bound_cmp!(i32, [..1] == [=0..]);
514 test_bound_cmp!(i32, [..2] == [0..]);
515 test_bound_cmp!(i32, [..1] == [..=0]);
516 test_bound_cmp!(i32, [..0] == [..0]);
517
518 test_bound_cmp!(i32, [..~] == [..~]);
519 }
520
521 #[test]
522 fn integer_bound_partial_greater() {
523 test_bound_cmp!(i32, [=1..] > [=0..]);
524 test_bound_cmp!(i32, [0..] > [=0..]);
525 test_bound_cmp!(i32, [..=1] > [=0..]);
526 test_bound_cmp!(i32, [..2] > [=0..]);
527 test_bound_cmp!(i32, [..~] > [=0..]);
528
529 test_bound_cmp!(i32, [=2..] > [0..]);
530 test_bound_cmp!(i32, [1..] > [0..]);
531 test_bound_cmp!(i32, [..=2] > [0..]);
532 test_bound_cmp!(i32, [..3] > [0..]);
533 test_bound_cmp!(i32, [..~] > [0..]);
534
535 test_bound_cmp!(i32, [=0..] > [~..]);
536 test_bound_cmp!(i32, [..=0] > [~..]);
537 test_bound_cmp!(i32, [..0] > [~..]);
538 test_bound_cmp!(i32, [..~] > [~..]);
539
540 test_bound_cmp!(i32, [=1..] > [..=0]);
541 test_bound_cmp!(i32, [0..] > [..=0]);
542 test_bound_cmp!(i32, [..=1] > [..=0]);
543 test_bound_cmp!(i32, [..2] > [..=0]);
544 test_bound_cmp!(i32, [..~] > [..=0]);
545
546 test_bound_cmp!(i32, [=1..] > [..1]);
547 test_bound_cmp!(i32, [0..] > [..1]);
548 test_bound_cmp!(i32, [..=1] > [..1]);
549 test_bound_cmp!(i32, [..2] > [..1]);
550 test_bound_cmp!(i32, [..~] > [..0]);
551 }
552
553 #[test]
554 fn float_bound_partial_less() {
555 test_bound_cmp!(f32, [=0.0..] < [=1.0..]);
556 test_bound_cmp!(f32, [=0.0..] < [0.0..]);
557 test_bound_cmp!(f32, [=0.0..] < [..=1.0]);
558 test_bound_cmp!(f32, [=0.0..] < [..2.0]);
559 test_bound_cmp!(f32, [=0.0..] < [..~]);
560
561 test_bound_cmp!(f32, [0.0..] < [=2.0..]);
562 test_bound_cmp!(f32, [0.0..] < [1.0..]);
563 test_bound_cmp!(f32, [0.0..] < [..1.0]); test_bound_cmp!(f32, [0.0..] < [..=2.0]);
565 test_bound_cmp!(f32, [0.0..] < [..3.0]);
566 test_bound_cmp!(f32, [0.0..] < [..~]);
567
568 test_bound_cmp!(f32, [~..] < [=0.0..]);
569 test_bound_cmp!(f32, [~..] < [..=0.0]);
570 test_bound_cmp!(f32, [~..] < [..0.0]);
571 test_bound_cmp!(f32, [~..] < [..~]);
572
573 test_bound_cmp!(f32, [..=0.0] < [=1.0..]);
574 test_bound_cmp!(f32, [..=0.0] < [0.0..]);
575 test_bound_cmp!(f32, [..=0.0] < [..=1.0]);
576 test_bound_cmp!(f32, [..=0.0] < [..2.0]);
577 test_bound_cmp!(f32, [..=0.0] < [..~]);
578
579 test_bound_cmp!(f32, [..1.0] < [=1.0..]);
580 test_bound_cmp!(f32, [..1.0] < [1.0..]);
581 test_bound_cmp!(f32, [..1.0] < [..=1.0]);
582 test_bound_cmp!(f32, [..1.0] < [..2.0]);
583 test_bound_cmp!(f32, [..0.0] < [..~]);
584 }
585
586 #[test]
587 fn float_bound_partial_eq() {
588 test_bound_cmp!(f32, [=0.0..] == [=0.0..]);
589 test_bound_cmp!(f32, [=1.0..] > [0.0..]); test_bound_cmp!(f32, [=0.0..] == [..=0.0]);
591 test_bound_cmp!(f32, [=0.0..] < [..1.0]); test_bound_cmp!(f32, [0.0..] < [=1.0..]); test_bound_cmp!(f32, [0.0..] == [0.0..]);
595 test_bound_cmp!(f32, [0.0..] < [..=1.0]); test_bound_cmp!(f32, [0.0..] < [..2.0]); test_bound_cmp!(f32, [~..] == [~..]);
599
600 test_bound_cmp!(f32, [..=0.0] == [=0.0..]);
601 test_bound_cmp!(f32, [..=1.0] > [0.0..]); test_bound_cmp!(f32, [..=0.0] == [..=0.0]);
603 test_bound_cmp!(f32, [..=0.0] < [..1.0]); test_bound_cmp!(f32, [..1.0] > [=0.0..]); test_bound_cmp!(f32, [..2.0] > [0.0..]); test_bound_cmp!(f32, [..1.0] > [..=0.0]); test_bound_cmp!(f32, [..0.0] == [..0.0]);
609
610 test_bound_cmp!(f32, [..~] == [..~]);
611 }
612
613 #[test]
614 fn float_bound_partial_greater() {
615 test_bound_cmp!(f32, [=1.0..] > [=0.0..]);
616 test_bound_cmp!(f32, [0.0..] > [=0.0..]);
617 test_bound_cmp!(f32, [..=1.0] > [=0.0..]);
618 test_bound_cmp!(f32, [..2.0] > [=0.0..]);
619 test_bound_cmp!(f32, [..~] > [=0.0..]);
620
621 test_bound_cmp!(f32, [=2.0..] > [0.0..]);
622 test_bound_cmp!(f32, [1.0..] > [0.0..]);
623 test_bound_cmp!(f32, [..1.0] > [0.0..]); test_bound_cmp!(f32, [..=2.0] > [0.0..]);
625 test_bound_cmp!(f32, [..3.0] > [0.0..]);
626 test_bound_cmp!(f32, [..~] > [0.0..]);
627
628 test_bound_cmp!(f32, [=0.0..] > [~..]);
629 test_bound_cmp!(f32, [..=0.0] > [~..]);
630 test_bound_cmp!(f32, [..0.0] > [~..]);
631 test_bound_cmp!(f32, [..~] > [~..]);
632
633 test_bound_cmp!(f32, [=1.0..] > [..=0.0]);
634 test_bound_cmp!(f32, [0.0..] > [..=0.0]);
635 test_bound_cmp!(f32, [..=1.0] > [..=0.0]);
636 test_bound_cmp!(f32, [..2.0] > [..=0.0]);
637 test_bound_cmp!(f32, [..~] > [..=0.0]);
638
639 test_bound_cmp!(f32, [=1.0..] > [..1.0]);
640 test_bound_cmp!(f32, [1.0..] > [..1.0]);
641 test_bound_cmp!(f32, [..=1.0] > [..1.0]);
642 test_bound_cmp!(f32, [..2.0] > [..1.0]);
643 test_bound_cmp!(f32, [..~] > [..0.0]);
644 }
645
646 #[test]
647 fn int_intersection() {
648 assert!((0..10).intersects(&(5..100)));
649 }
650
651 #[test]
653 fn int_connected_intersection() {
654 assert!((0..10).connected_to(&(5..100)));
655 }
656
657 #[test]
658 fn int_connected() {
659 assert!((0..10).connected_to(&(10..20)));
660 assert!((10..20).connected_to(&(0..10)));
661 assert!((0..=10).connected_to(&(RangeFromExcludedTo::new(10, 20))));
662 }
663
664 #[test]
665 fn int_disconnected() {
666 assert!(!(0..10).connected_to(&(11..20)));
667 assert!(!(11..20).connected_to(&(0..10)));
668 assert!(!(0..10).connected_to(&(RangeFromExcludedTo::new(10, 20))));
669 }
670
671 #[test]
672 fn float_connected() {
673 assert!((0.0..10.0).connected_to(&(10.0..20.0)));
674 assert!((0.0..=10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0))));
675 }
676
677 #[test]
678 fn float_disconnected() {
679 assert!(!(0.0..10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0))));
680 assert!(!(..10.0).connected_to(&(RangeFromExcludedTo::new(10.0, 20.0))));
681 assert!(!(0.0..10.0).connected_to(&(RangeFromExcluded::new(10.0))));
682 assert!(!(..10.0).connected_to(&(RangeFromExcluded::new(10.0))));
683 }
684}