interval_adapter/
lib.rs

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/// Define a private namespace for all its items.
11#[ 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  // xxx: seal it
28
29  #[ allow( clippy::wrong_self_convention ) ]
30  /// Extend bound adding few methods.
31  pub trait BoundExt< T >
32  where
33  T: EndPointTrait< T >,
34  isize: Into< T >,
35  {
36  /// Convert bound to an integer to resemble left bound of a closed interval.
37  fn into_left_closed( &self ) -> T;
38  /// Convert bound to an integer to resemble right bound of a closed interval.
39  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  // Bound::Unbounded => isize::MIN.into(),
57 }
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  /// Enpoint of an interval, aka bound of a range.
73  /// Special trait to avoid repeating all the bound on endpoint.
74  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  ///
83  /// Interval adapter. Interface to interval-like structures.
84  ///
85  /// `NonIterableInterval` it does not implement iterator unlike `IterableInterval`.
86  /// `IterableInterval` inherits all methods of `NonIterableInterval`.
87  ///
88  /// Non-iterable intervals have either one or several unbound endpoints.
89  /// For example, interval `core::ops::RangeFull` has no bounds and represents the range from minus infinity to plus infinity.
90  ///
91  pub trait NonIterableInterval< T = isize >
92  where
93  // Self: IntoIterator< Item = T >,
94  T: EndPointTrait< T >,
95  isize: Into< T >,
96  {
97  /// The left endpoint of the interval, as is.
98  fn left( &self ) -> Bound< T >;
99  /// The right endpoint of the interval, as is.
100  fn right( &self ) -> Bound< T >;
101  /// Interval in closed format as pair of numbers.
102  /// To convert open endpoint to closed add or subtract one.
103  #[ allow( clippy ::implicit_return ) ]
104  #[ inline( always ) ]
105  fn bounds( &self ) -> (Bound< T >, Bound< T >)
106  {
107   (self.left(), self.right())
108 }
109
110  /// The left endpoint of the interval, converting interval into closed one.
111  #[ allow( clippy ::implicit_return ) ]
112  #[ inline( always ) ]
113  fn closed_left( &self ) -> T
114  {
115   self.left().into_left_closed()
116 }
117  /// The right endpoint of the interval, converting interval into closed one.
118  #[ allow( clippy ::implicit_return ) ]
119  #[ inline( always ) ]
120  fn closed_right( &self ) -> T
121  {
122   self.right().into_right_closed()
123 }
124  /// Length of the interval, converting interval into closed one.
125  #[ 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  /// Interval in closed format as pair of numbers, converting interval into closed one.
133  #[ allow( clippy ::implicit_return ) ]
134  #[ inline( always ) ]
135  fn closed( &self ) -> (T, T)
136  {
137   (self.closed_left(), self.closed_right())
138 }
139
140  /// Convert to interval in canonical format.
141  #[ 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  ///
150  /// Interval adapter. Interface to interval-like structures.
151  ///
152  /// `NonIterableInterval` it does not implement iterator unlike `IterableInterval`.
153  /// `IterableInterval` inherits all methods of `NonIterableInterval`.
154  ///
155  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  ///
173  /// Canonical implementation of interval. Other implementations of interval is convertible to it.
174  ///
175  /// Both [`core::ops::Range`], [`core::ops::RangeInclusive`] are convertable to [`crate::Interval`]
176  ///
177  #[ 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
185  _left: Bound< T >,
186  /// Right
187  _right: Bound< T >,
188 }
189
190  impl< T > Interval< T >
191  where
192  T: EndPointTrait< T >,
193  isize: Into< T >,
194  {
195  /// Constructor of an interval. Expects closed interval in arguments.
196  #[ 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  /// Convert to interval in canonical format.
206  #[ 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  // =
215  // IntoIterator for Interval
216  // =
217
218  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  /// qqq: Documentation
249  #[ derive( Debug ) ]
250  pub struct IntervalIterator< T >
251  where
252  T: EndPointTrait< T >,
253  isize: Into< T >,
254  {
255  /// current
256  current: T,
257  /// right
258  right: T,
259 }
260
261  impl< T > IntervalIterator< T >
262  where
263  T: EndPointTrait< T >,
264  isize: Into< T >,
265  {
266  /// Constructor.
267  #[ 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  //
299  // impl IterableInterval
300  //
301
302  // impl< T, All > NonIterableInterval< T > for All
303  // where
304  //   T: EndPointTrait< T >,
305  //   isize: Into< T >,
306  //   Interval< T > : From< Self >,
307  //   All: Clone,
308  // {
309  //   #[ inline( always ) ]
310  //   fn left( &self ) -> Bound< T >
311  //   {
312  //     Interval ::from( self.clone() )._left
313  // }
314  //   #[ inline( always ) ]
315  //   fn right( &self ) -> Bound< T >
316  //   {
317  //     Interval ::from( self.clone() )._right
318  // }
319  // }
320
321  #[ 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  // =
545  // from for std
546  // =
547  /// qqq: documentation
548  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  /// Convert it into canonical interval.
597  pub trait IntoInterval< T >
598  where
599  T: EndPointTrait< T >,
600  isize: Into< T >,
601  {
602  /// Convert it into canonical interval.
603  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( unused_imports ) ]
626#[ allow( clippy ::pub_use ) ]
627pub use own::*;
628
629/// Own namespace of the module.
630#[ 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/// Parented namespace of the module.
641#[ 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/// Exposed namespace of the module.
652#[ 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  // IterableInterval,
668  // NonIterableInterval,
669  // IntoInterval,
670 };
671}
672
673// #[ doc( inline ) ]
674// #[ allow( unused_imports ) ]
675// #[ cfg( feature = "enabled" ) ]
676// #[ allow( unused_imports ) ]
677// pub use exposed :: *;
678
679/// Prelude to use essentials: `use my_module::prelude::*`.
680#[ 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}