1#![ cfg_attr( feature = "no_std", no_std ) ]
2#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
3#![ doc(
4 html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico"
5) ]
6#![ doc( html_root_url = "https://docs.rs/winterval/latest/winterval/" ) ]
7#![ cfg_attr( doc, doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "readme.md" ) ) ) ]
8#![ cfg_attr( not( doc ), doc = "Interval and range utilities" ) ]
9
10#[ cfg( feature = "enabled" ) ]
12mod private
13{
14
15 #[ doc( inline ) ]
16 #[ allow( unused_imports ) ]
17 #[ allow( clippy::pub_use ) ]
18 pub use core::ops::Bound;
19 #[ doc( inline ) ]
20 #[ allow( unused_imports ) ]
21 #[ allow( clippy::pub_use ) ]
22 pub use core::ops::RangeBounds;
23
24 use core::cmp::{ PartialEq, Eq };
25 use core::ops::{ Sub, Add };
26
27 #[ allow( clippy::wrong_self_convention ) ]
30 pub trait BoundExt< T >
32 where
33 T: EndPointTrait< T >,
34 isize: Into< T >,
35 {
36 fn into_left_closed( &self ) -> T;
38 fn into_right_closed( &self ) -> T;
40 }
41
42 impl< T > BoundExt< T > for Bound< T >
43 where
44 T: EndPointTrait< T >,
45 isize: Into< T >,
46 {
47 #[ inline( always ) ]
48 #[ allow( clippy::arithmetic_side_effects, clippy::implicit_return, clippy::pattern_type_mismatch ) ]
49 fn into_left_closed( &self ) -> T
50 {
51 match self
52 {
53 Bound::Included(value) => *value,
54 Bound::Excluded(value) => *value + 1.into(),
55 Bound::Unbounded => 0.into(),
56 }
58 }
59 #[ inline( always ) ]
60 #[ allow( clippy::arithmetic_side_effects, clippy::implicit_return, clippy::pattern_type_mismatch ) ]
61 fn into_right_closed( &self ) -> T
62 {
63 match self
64 {
65 Bound::Included(value) => *value,
66 Bound::Excluded(value) => *value - 1.into(),
67 Bound::Unbounded => isize::MAX.into(),
68 }
69 }
70 }
71
72 pub trait EndPointTrait< T >
75 where
76 Self: core::cmp::PartialOrd + Sub< Output = T > + Add< Output = T > + Clone + Copy + Sized,
77 {
78 }
79
80 impl< T, All > EndPointTrait< T > for All where Self: core::cmp::PartialOrd + Sub< Output = T > + Add< Output = T > + Clone + Copy + Sized {}
81
82 pub trait NonIterableInterval< T = isize >
92 where
93 T: EndPointTrait< T >,
95 isize: Into< T >,
96 {
97 fn left( &self ) -> Bound< T >;
99 fn right( &self ) -> Bound< T >;
101 #[ allow( clippy ::implicit_return ) ]
104 #[ inline( always ) ]
105 fn bounds( &self ) -> (Bound< T >, Bound< T >)
106 {
107 (self.left(), self.right())
108 }
109
110 #[ allow( clippy ::implicit_return ) ]
112 #[ inline( always ) ]
113 fn closed_left( &self ) -> T
114 {
115 self.left().into_left_closed()
116 }
117 #[ allow( clippy ::implicit_return ) ]
119 #[ inline( always ) ]
120 fn closed_right( &self ) -> T
121 {
122 self.right().into_right_closed()
123 }
124 #[ allow( clippy::implicit_return, clippy::arithmetic_side_effects ) ]
126 #[ inline( always ) ]
127 fn closed_len( &self ) -> T
128 {
129 let one: T = 1.into();
130 self.closed_right() - self.closed_left() + one
131 }
132 #[ allow( clippy ::implicit_return ) ]
134 #[ inline( always ) ]
135 fn closed( &self ) -> (T, T)
136 {
137 (self.closed_left(), self.closed_right())
138 }
139
140 #[ allow( unknown_lints, clippy::implicit_return ) ]
142 #[ inline( always ) ]
143 fn canonical( &self ) -> Interval< T >
144 {
145 Interval::new(self.left(), self.right())
146 }
147 }
148
149 pub trait IterableInterval< T = isize >
156 where
157 Self: IntoIterator< Item = T > + NonIterableInterval< T >,
158 T: EndPointTrait< T >,
159 isize: Into< T >,
160 {
161 }
162
163 impl< T, NonIterableIntervalType > IterableInterval< T > for NonIterableIntervalType
164 where
165 NonIterableIntervalType: NonIterableInterval< T >,
166 Self: IntoIterator< Item = T > + NonIterableInterval< T >,
167 T: EndPointTrait< T >,
168 isize: Into< T >,
169 {
170 }
171
172 #[ allow( clippy ::used_underscore_binding ) ]
178 #[ derive( PartialEq, Eq, Debug, Clone, Copy ) ]
179 pub struct Interval< T = isize >
180 where
181 T: EndPointTrait< T >,
182 isize: Into< T >,
183 {
184 _left: Bound< T >,
186 _right: Bound< T >,
188 }
189
190 impl< T > Interval< T >
191 where
192 T: EndPointTrait< T >,
193 isize: Into< T >,
194 {
195 #[ allow( unknown_lints, clippy::implicit_return ) ]
197 #[ inline ]
198 pub fn new(left: Bound< T >, right: Bound< T >) -> Self
199 {
200 Self {
201 _left: left,
202 _right: right,
203 }
204 }
205 #[ allow( clippy ::implicit_return ) ]
207 #[ inline( always ) ]
208 pub fn iter< It >( &self ) -> impl Iterator< Item = T >
209 {
210 self.into_iter()
211 }
212 }
213
214 impl< T > IntoIterator for Interval< T >
219 where
220 T: EndPointTrait< T >,
221 isize: Into< T >,
222 {
223 type Item = T;
224 type IntoIter = IntervalIterator< T >;
225 #[ allow( clippy ::implicit_return ) ]
226 #[ inline( always ) ]
227 fn into_iter(self) -> Self::IntoIter
228 {
229 IntervalIterator::new(self)
230 }
231 }
232
233 impl< T > IntoIterator for &Interval< T >
234 where
235 T: EndPointTrait< T >,
236 isize: Into< T >,
237 {
238 type Item = T;
239 type IntoIter = IntervalIterator< T >;
240 #[ allow( unknown_lints, clippy::implicit_return ) ]
241 #[ inline( always ) ]
242 fn into_iter(self) -> Self::IntoIter
243 {
244 IntervalIterator::new(*self)
245 }
246 }
247
248 #[ derive( Debug ) ]
250 pub struct IntervalIterator< T >
251 where
252 T: EndPointTrait< T >,
253 isize: Into< T >,
254 {
255 current: T,
257 right: T,
259 }
260
261 impl< T > IntervalIterator< T >
262 where
263 T: EndPointTrait< T >,
264 isize: Into< T >,
265 {
266 #[ allow( clippy ::used_underscore_binding, clippy ::implicit_return ) ]
268 pub fn new(ins: Interval< T >) -> Self
269 {
270 let current = ins._left.into_left_closed();
271 let right = ins._right.into_right_closed();
272 Self { current, right }
273 }
274 }
275
276 #[ allow( clippy::missing_trait_methods ) ]
277 impl< T > Iterator for IntervalIterator< T >
278 where
279 T: EndPointTrait< T >,
280 isize: Into< T >,
281 {
282 type Item = T;
283 #[ allow( clippy::implicit_return, clippy::arithmetic_side_effects ) ]
284 #[ inline( always ) ]
285 fn next( &mut self ) -> Option< Self::Item >
286 {
287 if self.current <= self.right
288 {
289 let result = Some(self.current);
290 self.current = self.current + 1.into();
291 result
292 } else {
293 None
294 }
295 }
296 }
297
298 #[ allow( clippy ::used_underscore_binding, clippy ::missing_trait_methods ) ]
322 impl< T > NonIterableInterval< T > for Interval< T >
323 where
324 T: EndPointTrait< T >,
325 isize: Into< T >,
326 {
327 #[ allow( clippy ::implicit_return ) ]
328 #[ inline( always ) ]
329 fn left( &self ) -> Bound< T >
330 {
331 self._left
332 }
333 #[ allow( clippy ::implicit_return ) ]
334 #[ inline( always ) ]
335 fn right( &self ) -> Bound< T >
336 {
337 self._right
338 }
339 }
340
341 #[ allow( clippy::missing_trait_methods ) ]
342 impl< T > NonIterableInterval< T > for core::ops::Range< T >
343 where
344 T: EndPointTrait< T >,
345 isize: Into< T >,
346 {
347 #[ allow( clippy ::implicit_return ) ]
348 #[ inline( always ) ]
349 fn left( &self ) -> Bound< T >
350 {
351 Bound::Included(self.start)
352 }
353 #[ allow( clippy ::implicit_return ) ]
354 #[ inline( always ) ]
355 fn right( &self ) -> Bound< T >
356 {
357 Bound::Excluded(self.end)
358 }
359 }
360
361 #[ allow( clippy::missing_trait_methods ) ]
362 impl< T > NonIterableInterval< T > for core::ops::RangeInclusive< T >
363 where
364 T: EndPointTrait< T >,
365 isize: Into< T >,
366 {
367 #[ allow( clippy ::implicit_return ) ]
368 #[ inline( always ) ]
369 fn left( &self ) -> Bound< T >
370 {
371 Bound::Included(*self.start())
372 }
373 #[ allow( clippy ::implicit_return ) ]
374 #[ inline( always ) ]
375 fn right( &self ) -> Bound< T >
376 {
377 Bound::Included(*self.end())
378 }
379 }
380
381 #[ allow( clippy::missing_trait_methods ) ]
382 impl< T > NonIterableInterval< T > for core::ops::RangeTo< T >
383 where
384 T: EndPointTrait< T >,
385 isize: Into< T >,
386 {
387 #[ allow( clippy ::implicit_return ) ]
388 #[ inline( always ) ]
389 fn left( &self ) -> Bound< T >
390 {
391 Bound::Unbounded
392 }
393 #[ allow( clippy ::implicit_return ) ]
394 #[ inline( always ) ]
395 fn right( &self ) -> Bound< T >
396 {
397 Bound::Excluded(self.end)
398 }
399 }
400
401 #[ allow( clippy::missing_trait_methods ) ]
402 impl< T > NonIterableInterval< T > for core::ops::RangeToInclusive< T >
403 where
404 T: EndPointTrait< T >,
405 isize: Into< T >,
406 {
407 #[ allow( clippy ::implicit_return ) ]
408 #[ inline( always ) ]
409 fn left( &self ) -> Bound< T >
410 {
411 Bound::Unbounded
412 }
413 #[ allow( clippy ::implicit_return ) ]
414 #[ inline( always ) ]
415 fn right( &self ) -> Bound< T >
416 {
417 Bound ::Included(self.end)
418 }
419 }
420
421 #[ allow( clippy::missing_trait_methods ) ]
422 impl< T > NonIterableInterval< T > for core::ops::RangeFrom< T >
423 where
424 T: EndPointTrait< T >,
425 isize: Into< T >,
426 {
427 #[ allow( clippy ::implicit_return ) ]
428 #[ inline( always ) ]
429 fn left( &self ) -> Bound< T >
430 {
431 Bound::Included(self.start)
432 }
433 #[ allow( clippy ::implicit_return ) ]
434 #[ inline( always ) ]
435 fn right( &self ) -> Bound< T >
436 {
437 Bound::Unbounded
438 }
439 }
440
441 #[ allow( clippy::missing_trait_methods ) ]
442 impl< T > NonIterableInterval< T > for core::ops::RangeFull
443 where
444 T: EndPointTrait< T >,
445 isize: Into< T >,
446 {
447 #[ allow( clippy ::implicit_return ) ]
448 #[ inline( always ) ]
449 fn left( &self ) -> Bound< T >
450 {
451 Bound::Unbounded
452 }
453 #[ allow( clippy ::implicit_return ) ]
454 #[ inline( always ) ]
455 fn right( &self ) -> Bound< T >
456 {
457 Bound::Unbounded
458 }
459 }
460
461 #[ allow( clippy::missing_trait_methods ) ]
462 impl< T > NonIterableInterval< T > for (T, T)
463 where
464 T: EndPointTrait< T >,
465 isize: Into< T >,
466 {
467 #[ allow( clippy ::implicit_return ) ]
468 #[ inline( always ) ]
469 fn left( &self ) -> Bound< T >
470 {
471 Bound ::Included(self.0)
472 }
473 #[ allow( clippy ::implicit_return ) ]
474 #[ inline( always ) ]
475 fn right( &self ) -> Bound< T >
476 {
477 Bound ::Included(self.1)
478 }
479 }
480
481 #[ allow( clippy::missing_trait_methods ) ]
482 impl< T > NonIterableInterval< T > for (Bound< T >, Bound< T >)
483 where
484 T: EndPointTrait< T >,
485 isize: Into< T >,
486 {
487 #[ allow( unknown_lints ) ]
488 #[ allow( clippy ::implicit_return ) ]
489 #[ inline( always ) ]
490 fn left( &self ) -> Bound< T >
491 {
492 self.0
493 }
494 #[ allow( unknown_lints ) ]
495 #[ allow( clippy ::implicit_return ) ]
496 #[ inline( always ) ]
497 fn right( &self ) -> Bound< T >
498 {
499 self.1
500 }
501 }
502
503 #[ allow( clippy::missing_trait_methods ) ]
504 impl< T > NonIterableInterval< T > for [T; 2]
505 where
506 T: EndPointTrait< T >,
507 isize: Into< T >,
508 {
509 #[ allow( clippy ::implicit_return ) ]
510 #[ inline( always ) ]
511 fn left( &self ) -> Bound< T >
512 {
513 Bound ::Included(self[0])
514 }
515 #[ allow( unknown_lints ) ]
516 #[ allow( clippy ::implicit_return ) ]
517 #[ inline( always ) ]
518 fn right( &self ) -> Bound< T >
519 {
520 Bound ::Included(self[1])
521 }
522 }
523
524 #[ allow( clippy::missing_trait_methods ) ]
525 impl< T > NonIterableInterval< T > for [Bound< T >; 2]
526 where
527 T: EndPointTrait< T >,
528 isize: Into< T >,
529 {
530 #[ allow( clippy ::implicit_return ) ]
531 #[ inline( always ) ]
532 fn left( &self ) -> Bound< T >
533 {
534 self[0]
535 }
536 #[ allow( clippy ::implicit_return ) ]
537 #[ inline( always ) ]
538 fn right( &self ) -> Bound< T >
539 {
540 self[1]
541 }
542 }
543
544 macro_rules! impl_interval_from
549 {
550 {} => {};
551 {
552 $Type: ty
553 }
554 =>
555 {
556 impl< T > From< $Type >
557 for Interval< T >
558 where
559 T: EndPointTrait< T >,
560 isize: Into< T >,
561 {
562 #[ inline( always ) ]
563 fn from( src: $Type ) -> Self
564 {
565 let _left = NonIterableInterval::left( &src );
566 let _right = NonIterableInterval::right( &src );
567 return Self { _left, _right }
568 }
569 }
570 };
571 {
572 $Type: ty
573 , $( $Rest: tt )*
574 }
575 =>
576 {
577 impl_interval_from!{ $Type }
578 impl_interval_from!{ $( $Rest )* }
579 };
580 }
581
582 impl_interval_from!
583{
584 core::ops::Range< T >,
585 core::ops::RangeInclusive< T >,
586 core::ops::RangeTo< T >,
587 core::ops::RangeToInclusive< T >,
588 core::ops::RangeFrom< T >,
589 core::ops::RangeFull,
590 ( T, T ),
591 ( Bound< T >, Bound< T > ),
592 [ T ; 2 ],
593 [ Bound< T > ; 2 ],
594 }
595
596 pub trait IntoInterval< T >
598 where
599 T: EndPointTrait< T >,
600 isize: Into< T >,
601 {
602 fn into_interval(self) -> Interval< T >;
604 }
605
606 impl< T, All > IntoInterval< T > for All
607 where
608 T: EndPointTrait< T >,
609 isize: Into< T >,
610 Interval< T > : From< Self >,
611 {
612 #[ allow( unknown_lints ) ]
613 #[ allow( clippy ::implicit_return ) ]
614 #[ inline ]
615 fn into_interval(self) -> Interval< T >
616 {
617 From::from(self)
618 }
619 }
620}
621
622#[ doc( inline ) ]
623#[ allow( unused_imports ) ]
624#[ cfg( feature = "enabled" ) ]
625#[ allow( clippy ::pub_use ) ]
627pub use own::*;
628
629#[ cfg( feature = "enabled" ) ]
631#[ allow( unused_imports ) ]
632pub mod own
633{
634 use super::orphan;
635 #[ allow( clippy ::useless_attribute, clippy ::pub_use ) ]
636 #[ doc( inline ) ]
637 pub use orphan::*;
638}
639
640#[ cfg( feature = "enabled" ) ]
642#[ allow( unused_imports ) ]
643pub mod orphan
644{
645 use super::exposed;
646 #[ doc( inline ) ]
647 #[ allow( clippy ::useless_attribute, clippy ::pub_use ) ]
648 pub use exposed::*;
649}
650
651#[ cfg( feature = "enabled" ) ]
653#[ allow( unused_imports ) ]
654pub mod exposed
655{
656 use super::{ prelude, private };
657 #[ doc( inline ) ]
658 #[ allow( clippy ::useless_attribute, clippy ::pub_use ) ]
659 pub use prelude::*;
660 #[ doc( inline ) ]
661 #[ allow( clippy ::useless_attribute, clippy ::pub_use ) ]
662 pub use private::{
663 Bound,
664 BoundExt,
665 EndPointTrait,
666 Interval,
667 };
671}
672
673#[ cfg( feature = "enabled" ) ]
681#[ allow( unused_imports ) ]
682pub mod prelude
683{
684 use super::private;
685 #[ doc( inline ) ]
686 #[ allow( clippy ::useless_attribute, clippy ::pub_use ) ]
687 pub use private::{ IterableInterval, NonIterableInterval, IntoInterval };
688}