BoundOrd now DiscreteBoundOrd, created Stepable trait, and DiscreteBounds struct and enum
This commit is contained in:
parent
fc23e9b96b
commit
e5739cedf7
277
src/bound_ord.rs
277
src/bound_ord.rs
@ -22,19 +22,14 @@ use std::ops::Bound;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An newtype of [`Bound`] to implement [`Ord`].
|
||||
use crate::stepable::Stepable;
|
||||
|
||||
/// An newtype of [`Bound`] to implement [`Ord`] on types that
|
||||
/// implement [`Step`].
|
||||
///
|
||||
/// This type is used to circumvent [`BTreeMap`]s (and rust collections
|
||||
/// in general) lack of methods for searching with custom
|
||||
/// [`comparator`] functions and/or it's lack of a [`Cursor`]-like
|
||||
/// API.
|
||||
///
|
||||
/// [`start_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.start_bound
|
||||
/// [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
|
||||
/// [`comparator`]: https://stackoverflow.com/q/34028324
|
||||
/// [`Cursor`]: https://github.com/rust-lang/rfcs/issues/1778
|
||||
/// [`Step`]: std::iter::Step
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub(crate) enum BoundOrd<T> {
|
||||
pub(crate) enum DiscreteBoundOrd<T> {
|
||||
/// Mirror of [`Bound::Included`]
|
||||
/// There is no need for different Start and End variations as the
|
||||
/// Ord implementations are equivalent.
|
||||
@ -49,108 +44,91 @@ pub(crate) enum BoundOrd<T> {
|
||||
EndUnbounded,
|
||||
}
|
||||
|
||||
impl<T> BoundOrd<T> {
|
||||
impl<T> DiscreteBoundOrd<T> {
|
||||
pub(crate) fn start(bound: Bound<T>) -> Self {
|
||||
match bound {
|
||||
Bound::Included(point) => BoundOrd::Included(point),
|
||||
Bound::Excluded(point) => BoundOrd::StartExcluded(point),
|
||||
Bound::Unbounded => BoundOrd::StartUnbounded,
|
||||
Bound::Included(point) => DiscreteBoundOrd::Included(point),
|
||||
Bound::Excluded(point) => DiscreteBoundOrd::StartExcluded(point),
|
||||
Bound::Unbounded => DiscreteBoundOrd::StartUnbounded,
|
||||
}
|
||||
}
|
||||
pub(crate) fn end(bound: Bound<T>) -> Self {
|
||||
match bound {
|
||||
Bound::Included(point) => BoundOrd::Included(point),
|
||||
Bound::Excluded(point) => BoundOrd::EndExcluded(point),
|
||||
Bound::Unbounded => BoundOrd::EndUnbounded,
|
||||
Bound::Included(point) => DiscreteBoundOrd::Included(point),
|
||||
Bound::Excluded(point) => DiscreteBoundOrd::EndExcluded(point),
|
||||
Bound::Unbounded => DiscreteBoundOrd::EndUnbounded,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Ord for BoundOrd<T>
|
||||
impl<T> Ord for DiscreteBoundOrd<T>
|
||||
where
|
||||
T: Ord,
|
||||
T: Ord + Stepable,
|
||||
{
|
||||
#[rustfmt::skip]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
(BoundOrd::Included(start1), BoundOrd::Included(start2)) => start1.cmp(start2),
|
||||
(BoundOrd::Included(start1), BoundOrd::StartExcluded(start2)) => cmp_with_priority(start1, start2, true),
|
||||
(BoundOrd::Included(start1), BoundOrd::EndExcluded(start2)) => cmp_with_priority(start1, start2, false),
|
||||
(BoundOrd::Included(_), BoundOrd::EndUnbounded) => Ordering::Less,
|
||||
(BoundOrd::Included(_), BoundOrd::StartUnbounded) => Ordering::Greater,
|
||||
(DiscreteBoundOrd::Included(start1), DiscreteBoundOrd::Included(start2)) => start1.cmp(start2),
|
||||
(DiscreteBoundOrd::Included(start1), DiscreteBoundOrd::StartExcluded(start2)) => start1.cmp(&start2.up().unwrap()),
|
||||
(DiscreteBoundOrd::Included(start1), DiscreteBoundOrd::EndExcluded(start2)) => start1.cmp(&start2.down().unwrap()),
|
||||
(DiscreteBoundOrd::Included(_), DiscreteBoundOrd::EndUnbounded) => Ordering::Less,
|
||||
(DiscreteBoundOrd::Included(_), DiscreteBoundOrd::StartUnbounded) => Ordering::Greater,
|
||||
|
||||
(BoundOrd::StartExcluded(start1), BoundOrd::StartExcluded(start2)) => start1.cmp(start2),
|
||||
(BoundOrd::StartExcluded(start1), BoundOrd::Included(start2)) => cmp_with_priority(start1, start2, false),
|
||||
(BoundOrd::StartExcluded(start1), BoundOrd::EndExcluded(start2)) => cmp_with_priority(start1, start2, false),
|
||||
(BoundOrd::StartExcluded(_), BoundOrd::StartUnbounded) => Ordering::Greater,
|
||||
(BoundOrd::StartExcluded(_), BoundOrd::EndUnbounded) => Ordering::Less,
|
||||
(DiscreteBoundOrd::StartExcluded(start1), DiscreteBoundOrd::StartExcluded(start2)) => start1.cmp(start2),
|
||||
(DiscreteBoundOrd::StartExcluded(start1), DiscreteBoundOrd::Included(start2)) => start1.up().unwrap().cmp(start2),
|
||||
(DiscreteBoundOrd::StartExcluded(start1), DiscreteBoundOrd::EndExcluded(start2)) => start1.up().unwrap().cmp(&start2.down().unwrap()),
|
||||
(DiscreteBoundOrd::StartExcluded(_), DiscreteBoundOrd::StartUnbounded) => Ordering::Greater,
|
||||
(DiscreteBoundOrd::StartExcluded(_), DiscreteBoundOrd::EndUnbounded) => Ordering::Less,
|
||||
|
||||
(BoundOrd::StartUnbounded, BoundOrd::Included(_)) => Ordering::Less,
|
||||
(BoundOrd::StartUnbounded, BoundOrd::StartExcluded(_)) => Ordering::Less,
|
||||
(BoundOrd::StartUnbounded, BoundOrd::EndExcluded(_)) => Ordering::Less,
|
||||
(BoundOrd::StartUnbounded, BoundOrd::StartUnbounded) => Ordering::Equal,
|
||||
(BoundOrd::StartUnbounded, BoundOrd::EndUnbounded) => Ordering::Less,
|
||||
(DiscreteBoundOrd::StartUnbounded, DiscreteBoundOrd::Included(_)) => Ordering::Less,
|
||||
(DiscreteBoundOrd::StartUnbounded, DiscreteBoundOrd::StartExcluded(_)) => Ordering::Less,
|
||||
(DiscreteBoundOrd::StartUnbounded, DiscreteBoundOrd::EndExcluded(_)) => Ordering::Less,
|
||||
(DiscreteBoundOrd::StartUnbounded, DiscreteBoundOrd::StartUnbounded) => Ordering::Equal,
|
||||
(DiscreteBoundOrd::StartUnbounded, DiscreteBoundOrd::EndUnbounded) => Ordering::Less,
|
||||
|
||||
(BoundOrd::EndExcluded(start1), BoundOrd::EndExcluded(start2)) => start1.cmp(start2),
|
||||
(BoundOrd::EndExcluded(start1), BoundOrd::Included(start2)) => cmp_with_priority(start1, start2, true),
|
||||
(BoundOrd::EndExcluded(start1), BoundOrd::StartExcluded(start2)) => cmp_with_priority(start1, start2, true),
|
||||
(BoundOrd::EndExcluded(_), BoundOrd::StartUnbounded) => Ordering::Greater,
|
||||
(BoundOrd::EndExcluded(_), BoundOrd::EndUnbounded) => Ordering::Less,
|
||||
(DiscreteBoundOrd::EndExcluded(start1), DiscreteBoundOrd::EndExcluded(start2)) => start1.cmp(start2),
|
||||
(DiscreteBoundOrd::EndExcluded(start1), DiscreteBoundOrd::Included(start2)) => start1.down().unwrap().cmp(&start2),
|
||||
(DiscreteBoundOrd::EndExcluded(start1), DiscreteBoundOrd::StartExcluded(start2)) => start1.down().unwrap().cmp(&start2.up().unwrap()),
|
||||
(DiscreteBoundOrd::EndExcluded(_), DiscreteBoundOrd::StartUnbounded) => Ordering::Greater,
|
||||
(DiscreteBoundOrd::EndExcluded(_), DiscreteBoundOrd::EndUnbounded) => Ordering::Less,
|
||||
|
||||
(BoundOrd::EndUnbounded, BoundOrd::Included(_)) => Ordering::Greater,
|
||||
(BoundOrd::EndUnbounded, BoundOrd::StartExcluded(_)) => Ordering::Greater,
|
||||
(BoundOrd::EndUnbounded, BoundOrd::EndExcluded(_)) => Ordering::Greater,
|
||||
(BoundOrd::EndUnbounded, BoundOrd::EndUnbounded) => Ordering::Equal,
|
||||
(BoundOrd::EndUnbounded, BoundOrd::StartUnbounded) => Ordering::Greater,
|
||||
(DiscreteBoundOrd::EndUnbounded, DiscreteBoundOrd::Included(_)) => Ordering::Greater,
|
||||
(DiscreteBoundOrd::EndUnbounded, DiscreteBoundOrd::StartExcluded(_)) => Ordering::Greater,
|
||||
(DiscreteBoundOrd::EndUnbounded, DiscreteBoundOrd::EndExcluded(_)) => Ordering::Greater,
|
||||
(DiscreteBoundOrd::EndUnbounded, DiscreteBoundOrd::EndUnbounded) => Ordering::Equal,
|
||||
(DiscreteBoundOrd::EndUnbounded, DiscreteBoundOrd::StartUnbounded) => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialOrd for BoundOrd<T>
|
||||
impl<T> PartialOrd for DiscreteBoundOrd<T>
|
||||
where
|
||||
T: Ord,
|
||||
T: Ord + Stepable,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq for BoundOrd<T>
|
||||
impl<T> PartialEq for DiscreteBoundOrd<T>
|
||||
where
|
||||
T: Ord,
|
||||
T: Ord + Stepable,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.cmp(other).is_eq()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for BoundOrd<T> where T: Ord {}
|
||||
impl<T> Eq for DiscreteBoundOrd<T> where T: Ord + Stepable {}
|
||||
|
||||
/// If they are equal say the item with priority is larger
|
||||
/// where false means left has priority and true means right.
|
||||
fn cmp_with_priority<T>(left: &T, right: &T, priority: bool) -> Ordering
|
||||
where
|
||||
T: Ord,
|
||||
{
|
||||
let result = left.cmp(right);
|
||||
|
||||
match result {
|
||||
Ordering::Equal => match priority {
|
||||
false => Ordering::Greater,
|
||||
true => Ordering::Less,
|
||||
},
|
||||
x => x,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<BoundOrd<T>> for Bound<T> {
|
||||
fn from(start_bound: BoundOrd<T>) -> Bound<T> {
|
||||
impl<T> From<DiscreteBoundOrd<T>> for Bound<T> {
|
||||
fn from(start_bound: DiscreteBoundOrd<T>) -> Bound<T> {
|
||||
match start_bound {
|
||||
BoundOrd::Included(point) => Bound::Included(point),
|
||||
BoundOrd::StartExcluded(point) => Bound::Excluded(point),
|
||||
BoundOrd::StartUnbounded => Bound::Unbounded,
|
||||
BoundOrd::EndExcluded(point) => Bound::Excluded(point),
|
||||
BoundOrd::EndUnbounded => Bound::Unbounded,
|
||||
DiscreteBoundOrd::Included(point) => Bound::Included(point),
|
||||
DiscreteBoundOrd::StartExcluded(point) => Bound::Excluded(point),
|
||||
DiscreteBoundOrd::StartUnbounded => Bound::Unbounded,
|
||||
DiscreteBoundOrd::EndExcluded(point) => Bound::Excluded(point),
|
||||
DiscreteBoundOrd::EndUnbounded => Bound::Unbounded,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,58 +140,137 @@ mod tests {
|
||||
#[test]
|
||||
fn mass_start_bound_partial_ord_test() {
|
||||
//Included
|
||||
assert!(BoundOrd::Included(2) == BoundOrd::Included(2));
|
||||
assert!(BoundOrd::Included(2) <= BoundOrd::Included(2));
|
||||
assert!(BoundOrd::Included(2) >= BoundOrd::Included(2));
|
||||
assert!(BoundOrd::Included(0) < BoundOrd::Included(2));
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::Included(0));
|
||||
assert!(DiscreteBoundOrd::Included(2) == DiscreteBoundOrd::Included(2));
|
||||
assert!(DiscreteBoundOrd::Included(2) <= DiscreteBoundOrd::Included(2));
|
||||
assert!(DiscreteBoundOrd::Included(2) >= DiscreteBoundOrd::Included(2));
|
||||
assert!(DiscreteBoundOrd::Included(0) < DiscreteBoundOrd::Included(2));
|
||||
assert!(DiscreteBoundOrd::Included(2) > DiscreteBoundOrd::Included(0));
|
||||
|
||||
assert!(BoundOrd::Included(2) < BoundOrd::StartExcluded(2));
|
||||
assert!(BoundOrd::Included(0) < BoundOrd::StartExcluded(2));
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::StartExcluded(0));
|
||||
assert!(
|
||||
DiscreteBoundOrd::Included(2) < DiscreteBoundOrd::StartExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::Included(0) < DiscreteBoundOrd::StartExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::Included(2) > DiscreteBoundOrd::StartExcluded(0)
|
||||
);
|
||||
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::StartUnbounded);
|
||||
assert!(
|
||||
DiscreteBoundOrd::Included(2) > DiscreteBoundOrd::StartUnbounded
|
||||
);
|
||||
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::Included(0) < BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::EndExcluded(0));
|
||||
assert!(
|
||||
DiscreteBoundOrd::Included(2) > DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::Included(0) < DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::Included(2) > DiscreteBoundOrd::EndExcluded(0)
|
||||
);
|
||||
|
||||
assert!(BoundOrd::Included(2) < BoundOrd::EndUnbounded);
|
||||
assert!(DiscreteBoundOrd::Included(2) < DiscreteBoundOrd::EndUnbounded);
|
||||
|
||||
//StartExcluded
|
||||
assert!(BoundOrd::StartExcluded(2) == BoundOrd::StartExcluded(2));
|
||||
assert!(BoundOrd::StartExcluded(2) <= BoundOrd::StartExcluded(2));
|
||||
assert!(BoundOrd::StartExcluded(2) >= BoundOrd::StartExcluded(2));
|
||||
assert!(BoundOrd::StartExcluded(0) < BoundOrd::StartExcluded(2));
|
||||
assert!(BoundOrd::StartExcluded(2) > BoundOrd::StartExcluded(0));
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(2)
|
||||
== DiscreteBoundOrd::StartExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(2)
|
||||
<= DiscreteBoundOrd::StartExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(2)
|
||||
>= DiscreteBoundOrd::StartExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(0)
|
||||
< DiscreteBoundOrd::StartExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(2)
|
||||
> DiscreteBoundOrd::StartExcluded(0)
|
||||
);
|
||||
|
||||
assert!(BoundOrd::StartExcluded(2) > BoundOrd::StartUnbounded);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(2)
|
||||
> DiscreteBoundOrd::StartUnbounded
|
||||
);
|
||||
|
||||
assert!(BoundOrd::StartExcluded(2) > BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::StartExcluded(2) > BoundOrd::EndExcluded(0));
|
||||
assert!(BoundOrd::StartExcluded(0) < BoundOrd::EndExcluded(2));
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(2)
|
||||
> DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(2)
|
||||
> DiscreteBoundOrd::EndExcluded(0)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(0)
|
||||
< DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
|
||||
assert!(BoundOrd::StartExcluded(2) < BoundOrd::EndUnbounded);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartExcluded(2) < DiscreteBoundOrd::EndUnbounded
|
||||
);
|
||||
|
||||
//StartUnbounded
|
||||
assert!(BoundOrd::StartUnbounded::<i8> == BoundOrd::StartUnbounded);
|
||||
assert!(BoundOrd::StartUnbounded::<i8> <= BoundOrd::StartUnbounded);
|
||||
assert!(BoundOrd::StartUnbounded::<i8> >= BoundOrd::StartUnbounded);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartUnbounded::<i8>
|
||||
== DiscreteBoundOrd::StartUnbounded
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartUnbounded::<i8>
|
||||
<= DiscreteBoundOrd::StartUnbounded
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartUnbounded::<i8>
|
||||
>= DiscreteBoundOrd::StartUnbounded
|
||||
);
|
||||
|
||||
assert!(BoundOrd::StartUnbounded < BoundOrd::EndExcluded(2));
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartUnbounded < DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
|
||||
assert!(BoundOrd::StartUnbounded::<i8> < BoundOrd::EndUnbounded);
|
||||
assert!(
|
||||
DiscreteBoundOrd::StartUnbounded::<i8>
|
||||
< DiscreteBoundOrd::EndUnbounded
|
||||
);
|
||||
|
||||
//EndExcluded
|
||||
assert!(BoundOrd::EndExcluded(2) == BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::EndExcluded(2) <= BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::EndExcluded(2) >= BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::EndExcluded(0) < BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::EndExcluded(2) > BoundOrd::EndExcluded(0));
|
||||
assert!(
|
||||
DiscreteBoundOrd::EndExcluded(2)
|
||||
== DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::EndExcluded(2)
|
||||
<= DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::EndExcluded(2)
|
||||
>= DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::EndExcluded(0) < DiscreteBoundOrd::EndExcluded(2)
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::EndExcluded(2) > DiscreteBoundOrd::EndExcluded(0)
|
||||
);
|
||||
|
||||
//EndUnbounded
|
||||
assert!(BoundOrd::EndUnbounded::<i8> == BoundOrd::EndUnbounded);
|
||||
assert!(BoundOrd::EndUnbounded::<i8> <= BoundOrd::EndUnbounded);
|
||||
assert!(BoundOrd::EndUnbounded::<i8> >= BoundOrd::EndUnbounded);
|
||||
assert!(
|
||||
DiscreteBoundOrd::EndUnbounded::<i8>
|
||||
== DiscreteBoundOrd::EndUnbounded
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::EndUnbounded::<i8>
|
||||
<= DiscreteBoundOrd::EndUnbounded
|
||||
);
|
||||
assert!(
|
||||
DiscreteBoundOrd::EndUnbounded::<i8>
|
||||
>= DiscreteBoundOrd::EndUnbounded
|
||||
);
|
||||
}
|
||||
}
|
||||
|
28
src/discrete_bounds.rs
Normal file
28
src/discrete_bounds.rs
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2022 James Forster
|
||||
|
||||
This file is part of range_bounds_map.
|
||||
|
||||
range_bounds_map is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
range_bounds_map is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
pub struct DiscreteBounds<I> {
|
||||
start: DiscreteBound<I>,
|
||||
end: DiscreteBound<I>,
|
||||
}
|
||||
|
||||
pub enum DiscreteBound<I> {
|
||||
Included(I),
|
||||
Unbounded,
|
||||
}
|
@ -219,6 +219,7 @@ along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#![feature(let_chains)]
|
||||
#![feature(btree_cursors)]
|
||||
#![feature(step_trait)]
|
||||
#![allow(clippy::tabs_in_doc_comments)]
|
||||
#![allow(clippy::needless_return)]
|
||||
|
||||
@ -226,6 +227,9 @@ pub(crate) mod bound_ord;
|
||||
pub mod test_ranges;
|
||||
pub(crate) mod utils;
|
||||
|
||||
pub mod stepable;
|
||||
pub mod discrete_bounds;
|
||||
|
||||
pub mod range_bounds_map;
|
||||
pub mod range_bounds_set;
|
||||
pub mod try_from_bounds;
|
||||
|
@ -32,7 +32,7 @@ use serde::de::{MapAccess, Visitor};
|
||||
use serde::ser::SerializeMap;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::bound_ord::BoundOrd;
|
||||
use crate::bound_ord::DiscreteBoundOrd;
|
||||
use crate::utils::{
|
||||
cmp_range_with_bound_ord, cut_range, flip_bound, is_valid_range, overlaps,
|
||||
};
|
||||
@ -1669,8 +1669,8 @@ where
|
||||
I: Ord,
|
||||
{
|
||||
|inner_range: &K, new_range: &K| {
|
||||
BoundOrd::start(new_range.start())
|
||||
.cmp(&BoundOrd::start(inner_range.start()))
|
||||
DiscreteBoundOrd::start(new_range.start())
|
||||
.cmp(&DiscreteBoundOrd::start(inner_range.start()))
|
||||
}
|
||||
}
|
||||
fn overlapping_start_comp<I, K>(start: Bound<I>) -> impl FnMut(&K) -> Ordering
|
||||
@ -1679,7 +1679,7 @@ where
|
||||
K: NiceRange<I>,
|
||||
{
|
||||
move |inner_range: &K| {
|
||||
cmp_range_with_bound_ord(*inner_range, BoundOrd::start(start))
|
||||
cmp_range_with_bound_ord(*inner_range, DiscreteBoundOrd::start(start))
|
||||
}
|
||||
}
|
||||
fn overlapping_end_comp<I, K>(end: Bound<I>) -> impl FnMut(&K) -> Ordering
|
||||
@ -1688,7 +1688,7 @@ where
|
||||
K: NiceRange<I>,
|
||||
{
|
||||
move |inner_range: &K| {
|
||||
cmp_range_with_bound_ord(*inner_range, BoundOrd::end(end))
|
||||
cmp_range_with_bound_ord(*inner_range, DiscreteBoundOrd::end(end))
|
||||
}
|
||||
}
|
||||
fn touching_start_comp<I, K>(start: Bound<I>) -> impl FnMut(&K) -> Ordering
|
||||
@ -1707,7 +1707,7 @@ where
|
||||
}
|
||||
|
||||
(end, start) => {
|
||||
let normal_result = BoundOrd::start(start).cmp(&BoundOrd::end(end));
|
||||
let normal_result = DiscreteBoundOrd::start(start).cmp(&DiscreteBoundOrd::end(end));
|
||||
|
||||
//we overide any Equals to a random non-Equal since we
|
||||
//don't want non-touching matches
|
||||
@ -1735,7 +1735,7 @@ where
|
||||
|
||||
(end, _start) => {
|
||||
let normal_result =
|
||||
BoundOrd::end(end).cmp(&BoundOrd::start(inner_range.start()));
|
||||
DiscreteBoundOrd::end(end).cmp(&DiscreteBoundOrd::start(inner_range.start()));
|
||||
|
||||
//we overide any Equals to a random non-Equal since we
|
||||
//don't want non-touching matches
|
||||
@ -1881,7 +1881,7 @@ mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::bound_ord::BoundOrd;
|
||||
use crate::bound_ord::DiscreteBoundOrd;
|
||||
use crate::test_ranges::{ee, ei, ie, ii, iu, u, ue, ui, uu, AnyRange};
|
||||
use crate::utils::{config, Config, CutResult};
|
||||
|
||||
@ -2077,8 +2077,8 @@ mod tests {
|
||||
}
|
||||
//make our expected_overlapping the correct order
|
||||
if expected_overlapping.len() > 1 {
|
||||
if BoundOrd::start(expected_overlapping[0].start())
|
||||
> BoundOrd::start(expected_overlapping[1].start())
|
||||
if DiscreteBoundOrd::start(expected_overlapping[0].start())
|
||||
> DiscreteBoundOrd::start(expected_overlapping[1].start())
|
||||
{
|
||||
expected_overlapping.swap(0, 1);
|
||||
}
|
||||
|
41
src/stepable.rs
Normal file
41
src/stepable.rs
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2022 James Forster
|
||||
|
||||
This file is part of range_bounds_map.
|
||||
|
||||
range_bounds_map is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
range_bounds_map is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::iter::Step;
|
||||
|
||||
pub trait Stepable {
|
||||
fn up(self) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
fn down(self) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<T> Stepable for T
|
||||
where
|
||||
T: Sized + Step,
|
||||
{
|
||||
fn up(self) -> Option<Self> {
|
||||
<T as Step>::forward_checked(self, 1)
|
||||
}
|
||||
fn down(self) -> Option<Self> {
|
||||
<T as Step>::backward_checked(self, 1)
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 James Forster
|
||||
|
||||
This file is part of range_bounds_map.
|
||||
|
||||
range_bounds_map is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
range_bounds_map is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::ops::{
|
||||
Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo,
|
||||
RangeToInclusive,
|
||||
};
|
||||
|
||||
use crate::TryFromBoundsError;
|
||||
|
||||
/// A "newtype" trait to copy [`TryFrom`].
|
||||
///
|
||||
/// I am forced to use this "newtype" instead of [`TryFrom`] because
|
||||
/// [`Range`] and friends don't implement `TryFrom<(Bound, Bound)>`
|
||||
///
|
||||
/// I personally think they should since then I wouldn't have to make
|
||||
/// a trait just for this. I have made a post about it here should you
|
||||
/// wish to comment your view.
|
||||
/// <https://internals.rust-lang.org/t/range-should-impl-tryfrom-bound-bound>
|
||||
///
|
||||
/// [`TryFrom`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
||||
/// [`Range`]: https://doc.rust-lang.org/std/ops/struct.Range.html
|
||||
pub trait TryFromBounds<I> {
|
||||
fn try_from_bounds(
|
||||
start_bound: Bound<I>,
|
||||
end_bound: Bound<I>,
|
||||
) -> Result<Self, TryFromBoundsError>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<I> TryFromBounds<I> for (Bound<I>, Bound<I>) {
|
||||
fn try_from_bounds(
|
||||
start_bound: Bound<I>,
|
||||
end_bound: Bound<I>,
|
||||
) -> Result<Self, TryFromBoundsError> {
|
||||
Ok((start_bound, end_bound))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> TryFromBounds<I> for Range<I> {
|
||||
fn try_from_bounds(
|
||||
start_bound: Bound<I>,
|
||||
end_bound: Bound<I>,
|
||||
) -> Result<Self, TryFromBoundsError> {
|
||||
match (start_bound, end_bound) {
|
||||
(Bound::Included(start), Bound::Excluded(end)) => Ok(start..end),
|
||||
_ => Err(TryFromBoundsError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> TryFromBounds<I> for RangeInclusive<I> {
|
||||
fn try_from_bounds(
|
||||
start_bound: Bound<I>,
|
||||
end_bound: Bound<I>,
|
||||
) -> Result<Self, TryFromBoundsError> {
|
||||
match (start_bound, end_bound) {
|
||||
(Bound::Included(start), Bound::Included(end)) => Ok(start..=end),
|
||||
_ => Err(TryFromBoundsError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> TryFromBounds<I> for RangeFrom<I> {
|
||||
fn try_from_bounds(
|
||||
start_bound: Bound<I>,
|
||||
end_bound: Bound<I>,
|
||||
) -> Result<Self, TryFromBoundsError> {
|
||||
match (start_bound, end_bound) {
|
||||
(Bound::Included(start), Bound::Unbounded) => Ok(start..),
|
||||
_ => Err(TryFromBoundsError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> TryFromBounds<I> for RangeTo<I> {
|
||||
fn try_from_bounds(
|
||||
start_bound: Bound<I>,
|
||||
end_bound: Bound<I>,
|
||||
) -> Result<Self, TryFromBoundsError> {
|
||||
match (start_bound, end_bound) {
|
||||
(Bound::Unbounded, Bound::Excluded(end)) => Ok(..end),
|
||||
_ => Err(TryFromBoundsError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> TryFromBounds<I> for RangeToInclusive<I> {
|
||||
fn try_from_bounds(
|
||||
start_bound: Bound<I>,
|
||||
end_bound: Bound<I>,
|
||||
) -> Result<Self, TryFromBoundsError> {
|
||||
match (start_bound, end_bound) {
|
||||
(Bound::Unbounded, Bound::Included(end)) => Ok(..=end),
|
||||
_ => Err(TryFromBoundsError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> TryFromBounds<I> for RangeFull {
|
||||
fn try_from_bounds(
|
||||
start_bound: Bound<I>,
|
||||
end_bound: Bound<I>,
|
||||
) -> Result<Self, TryFromBoundsError> {
|
||||
match (start_bound, end_bound) {
|
||||
(Bound::Unbounded, Bound::Unbounded) => Ok(..),
|
||||
_ => Err(TryFromBoundsError),
|
||||
}
|
||||
}
|
||||
}
|
24
src/utils.rs
24
src/utils.rs
@ -20,20 +20,20 @@ along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::Bound;
|
||||
|
||||
use crate::bound_ord::BoundOrd;
|
||||
use crate::bound_ord::DiscreteBoundOrd;
|
||||
use crate::range_bounds_map::NiceRange;
|
||||
|
||||
pub(crate) fn cmp_range_with_bound_ord<A, B>(
|
||||
range: A,
|
||||
bound_ord: BoundOrd<B>,
|
||||
bound_ord: DiscreteBoundOrd<B>,
|
||||
) -> Ordering
|
||||
where
|
||||
A: NiceRange<B>,
|
||||
B: Ord,
|
||||
{
|
||||
if bound_ord < BoundOrd::start(range.start()) {
|
||||
if bound_ord < DiscreteBoundOrd::start(range.start()) {
|
||||
Ordering::Less
|
||||
} else if bound_ord > BoundOrd::end(range.end()) {
|
||||
} else if bound_ord > DiscreteBoundOrd::end(range.end()) {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Equal
|
||||
@ -56,11 +56,11 @@ where
|
||||
B: NiceRange<I>,
|
||||
I: Ord,
|
||||
{
|
||||
match BoundOrd::start(a.start()) < BoundOrd::start(b.start()) {
|
||||
match DiscreteBoundOrd::start(a.start()) < DiscreteBoundOrd::start(b.start()) {
|
||||
true => {
|
||||
match (
|
||||
contains_bound_ord(a, BoundOrd::start(b.start())),
|
||||
contains_bound_ord(a, BoundOrd::end(b.end())),
|
||||
contains_bound_ord(a, DiscreteBoundOrd::start(b.start())),
|
||||
contains_bound_ord(a, DiscreteBoundOrd::end(b.end())),
|
||||
) {
|
||||
(false, false) => Config::LeftFirstNonOverlapping,
|
||||
(true, false) => Config::LeftFirstPartialOverlap,
|
||||
@ -70,8 +70,8 @@ where
|
||||
}
|
||||
false => {
|
||||
match (
|
||||
contains_bound_ord(b, BoundOrd::start(a.start())),
|
||||
contains_bound_ord(b, BoundOrd::end(a.end())),
|
||||
contains_bound_ord(b, DiscreteBoundOrd::start(a.start())),
|
||||
contains_bound_ord(b, DiscreteBoundOrd::end(a.end())),
|
||||
) {
|
||||
(false, false) => Config::RightFirstNonOverlapping,
|
||||
(true, false) => Config::RightFirstPartialOverlap,
|
||||
@ -110,13 +110,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains_bound_ord<I, A>(range: A, bound_ord: BoundOrd<I>) -> bool
|
||||
pub(crate) fn contains_bound_ord<I, A>(range: A, bound_ord: DiscreteBoundOrd<I>) -> bool
|
||||
where
|
||||
A: NiceRange<I>,
|
||||
I: Ord,
|
||||
{
|
||||
let start_bound_ord = BoundOrd::start(range.start());
|
||||
let end_bound_ord = BoundOrd::end(range.end());
|
||||
let start_bound_ord = DiscreteBoundOrd::start(range.start());
|
||||
let end_bound_ord = DiscreteBoundOrd::end(range.end());
|
||||
|
||||
return bound_ord >= start_bound_ord && bound_ord <= end_bound_ord;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user