changed name of StartBound to more generic BoundOrd
This commit is contained in:
parent
b921fce269
commit
ec97b5d199
203
src/bound_ord.rs
Normal file
203
src/bound_ord.rs
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
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 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
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::Bound;
|
||||
|
||||
use labels::{parent_tested, tested, trivial};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An newtype of [`Bound`] to implement [`Ord`].
|
||||
///
|
||||
/// 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
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
pub(crate) enum BoundOrd<T> {
|
||||
/// Mirror of [`Bound::Included`]
|
||||
/// There is no need for different Start and End variations as the
|
||||
/// Ord implementations are equivalent.
|
||||
Included(T),
|
||||
/// [`Bound::Excluded`] specific to Start bounds.
|
||||
StartExcluded(T),
|
||||
/// [`Bound::Unbounded`] specific to Start bounds.
|
||||
StartUnbounded,
|
||||
/// [`Bound::Excluded`] specific to End bounds.
|
||||
EndExcluded(T),
|
||||
/// [`Bound::Unbounded`] specific to End bounds.
|
||||
EndUnbounded,
|
||||
}
|
||||
|
||||
impl<T> Eq for BoundOrd<T> where T: PartialEq {}
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl<T> PartialOrd for BoundOrd<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
#[tested]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match (self, other) {
|
||||
(BoundOrd::Included(start1), BoundOrd::Included(start2)) => start1.partial_cmp(start2),
|
||||
(BoundOrd::Included(start1), BoundOrd::StartExcluded(start2)) => partial_cmp_with_priority(start1, start2, true),
|
||||
(BoundOrd::Included(start1), BoundOrd::EndExcluded(start2)) => partial_cmp_with_priority(start1, start2, false),
|
||||
(BoundOrd::Included(_), BoundOrd::EndUnbounded) => Some(Ordering::Less),
|
||||
(BoundOrd::Included(_), BoundOrd::StartUnbounded) => Some(Ordering::Greater),
|
||||
|
||||
(BoundOrd::StartExcluded(start1), BoundOrd::StartExcluded(start2)) => start1.partial_cmp(start2),
|
||||
(BoundOrd::StartExcluded(start1), BoundOrd::Included(start2)) => partial_cmp_with_priority(start1, start2, false),
|
||||
(BoundOrd::StartExcluded(start1), BoundOrd::EndExcluded(start2)) => partial_cmp_with_priority(start1, start2, false),
|
||||
(BoundOrd::StartExcluded(_), BoundOrd::StartUnbounded) => Some(Ordering::Greater),
|
||||
(BoundOrd::StartExcluded(_), BoundOrd::EndUnbounded) => Some(Ordering::Less),
|
||||
|
||||
(BoundOrd::StartUnbounded, BoundOrd::Included(_)) => Some(Ordering::Less),
|
||||
(BoundOrd::StartUnbounded, BoundOrd::StartExcluded(_)) => Some(Ordering::Less),
|
||||
(BoundOrd::StartUnbounded, BoundOrd::EndExcluded(_)) => Some(Ordering::Less),
|
||||
(BoundOrd::StartUnbounded, BoundOrd::StartUnbounded) => Some(Ordering::Equal),
|
||||
(BoundOrd::StartUnbounded, BoundOrd::EndUnbounded) => Some(Ordering::Less),
|
||||
|
||||
(BoundOrd::EndExcluded(start1), BoundOrd::EndExcluded(start2)) => start1.partial_cmp(start2),
|
||||
(BoundOrd::EndExcluded(start1), BoundOrd::Included(start2)) => partial_cmp_with_priority(start1, start2, true),
|
||||
(BoundOrd::EndExcluded(start1), BoundOrd::StartExcluded(start2)) => partial_cmp_with_priority(start1, start2, true),
|
||||
(BoundOrd::EndExcluded(_), BoundOrd::StartUnbounded) => Some(Ordering::Greater),
|
||||
(BoundOrd::EndExcluded(_), BoundOrd::EndUnbounded) => Some(Ordering::Less),
|
||||
|
||||
(BoundOrd::EndUnbounded, BoundOrd::Included(_)) => Some(Ordering::Greater),
|
||||
(BoundOrd::EndUnbounded, BoundOrd::StartExcluded(_)) => Some(Ordering::Greater),
|
||||
(BoundOrd::EndUnbounded, BoundOrd::EndExcluded(_)) => Some(Ordering::Greater),
|
||||
(BoundOrd::EndUnbounded, BoundOrd::EndUnbounded) => Some(Ordering::Equal),
|
||||
(BoundOrd::EndUnbounded, BoundOrd::StartUnbounded) => Some(Ordering::Greater),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If they are equal say the item with priority is larger
|
||||
/// where false means left has priority and true means right.
|
||||
#[parent_tested]
|
||||
fn partial_cmp_with_priority<T>(
|
||||
left: &T,
|
||||
right: &T,
|
||||
priority: bool,
|
||||
) -> Option<Ordering>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
let result = left.partial_cmp(right)?;
|
||||
|
||||
Some(match result {
|
||||
Ordering::Equal => match priority {
|
||||
false => Ordering::Greater,
|
||||
true => Ordering::Less,
|
||||
},
|
||||
x => x,
|
||||
})
|
||||
}
|
||||
|
||||
impl<T> Ord for BoundOrd<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
#[trivial]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<BoundOrd<T>> for Bound<T> {
|
||||
#[trivial]
|
||||
fn from(start_bound: BoundOrd<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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[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!(BoundOrd::Included(2) < BoundOrd::StartExcluded(2));
|
||||
assert!(BoundOrd::Included(0) < BoundOrd::StartExcluded(2));
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::StartExcluded(0));
|
||||
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::StartUnbounded);
|
||||
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::Included(0) < BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::Included(2) > BoundOrd::EndExcluded(0));
|
||||
|
||||
assert!(BoundOrd::Included(2) < BoundOrd::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!(BoundOrd::StartExcluded(2) > BoundOrd::StartUnbounded);
|
||||
|
||||
assert!(BoundOrd::StartExcluded(2) > BoundOrd::EndExcluded(2));
|
||||
assert!(BoundOrd::StartExcluded(2) > BoundOrd::EndExcluded(0));
|
||||
assert!(BoundOrd::StartExcluded(0) < BoundOrd::EndExcluded(2));
|
||||
|
||||
assert!(BoundOrd::StartExcluded(2) < BoundOrd::EndUnbounded);
|
||||
|
||||
//StartUnbounded
|
||||
assert!(BoundOrd::StartUnbounded::<u8> == BoundOrd::StartUnbounded);
|
||||
assert!(BoundOrd::StartUnbounded::<u8> <= BoundOrd::StartUnbounded);
|
||||
assert!(BoundOrd::StartUnbounded::<u8> >= BoundOrd::StartUnbounded);
|
||||
|
||||
assert!(BoundOrd::StartUnbounded < BoundOrd::EndExcluded(2));
|
||||
|
||||
assert!(BoundOrd::StartUnbounded::<u8> < BoundOrd::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));
|
||||
|
||||
//EndUnbounded
|
||||
assert!(BoundOrd::EndUnbounded::<u8> == BoundOrd::EndUnbounded);
|
||||
assert!(BoundOrd::EndUnbounded::<u8> <= BoundOrd::EndUnbounded);
|
||||
assert!(BoundOrd::EndUnbounded::<u8> >= BoundOrd::EndUnbounded);
|
||||
}
|
||||
}
|
250
src/bounds.rs
250
src/bounds.rs
@ -1,250 +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 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
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::Bound;
|
||||
|
||||
use labels::{parent_tested, tested, trivial};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An Ord newtype of [`Bound`] specific to [`start_bound()`].
|
||||
///
|
||||
/// 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
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
pub(crate) enum StartBound<T> {
|
||||
/// Mirror of [`Bound::Included`]
|
||||
Included(T),
|
||||
/// Mirror of [`Bound::Excluded`]
|
||||
Excluded(T),
|
||||
/// Mirror of [`Bound::Unbounded`]
|
||||
Unbounded,
|
||||
/// Workaround type used to represent [`Bound::Excluded`] in [`end_bound()`] in meta-bound
|
||||
/// [`BTreeMap::range`] searches in [`crate::RangeBoundsMap::overlapping()`]
|
||||
///
|
||||
/// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound
|
||||
/// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
|
||||
ReverseExcluded(T),
|
||||
/// Workaround type used to represent [`Bound::Unbounded`] in [`end_bound()`] in meta-bound
|
||||
/// [`BTreeMap::range`] searches in [`crate::RangeBoundsMap::overlapping()`]
|
||||
///
|
||||
/// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound
|
||||
/// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
|
||||
ReverseUnbounded,
|
||||
}
|
||||
|
||||
impl<T> StartBound<T> {
|
||||
/// Converts the [`StartBound`] to the appropriate type for use as
|
||||
/// an [`end_bound()`] in a range search
|
||||
///
|
||||
/// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound
|
||||
#[trivial]
|
||||
pub(crate) fn into_end_bound(self) -> StartBound<T> {
|
||||
match self {
|
||||
//flipping is unnecessary
|
||||
StartBound::Included(point) => StartBound::Included(point),
|
||||
//flip to Reverses
|
||||
StartBound::Excluded(point) => StartBound::ReverseExcluded(point),
|
||||
StartBound::Unbounded => StartBound::ReverseUnbounded,
|
||||
_ => panic!("unsuitable operation"),
|
||||
}
|
||||
}
|
||||
/// Does the inverse of [`StartBound::into_end_bound()`].
|
||||
#[trivial]
|
||||
pub(crate) fn into_start_bound(self) -> StartBound<T> {
|
||||
match self {
|
||||
StartBound::Included(point) => StartBound::Included(point),
|
||||
StartBound::ReverseExcluded(point) => StartBound::Excluded(point),
|
||||
StartBound::ReverseUnbounded => StartBound::Unbounded,
|
||||
_ => panic!("unsuitable operation"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for StartBound<T> where T: PartialEq {}
|
||||
|
||||
/// The [`PartialOrd`] implementaion with the goal of allowing the use
|
||||
/// of [`BTreeMap::range`] on [`StartBound`]s
|
||||
///
|
||||
/// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
|
||||
#[rustfmt::skip]
|
||||
impl<T> PartialOrd for StartBound<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
#[tested]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match (self, other) {
|
||||
(StartBound::Included(start1), StartBound::Included(start2)) => start1.partial_cmp(start2),
|
||||
(StartBound::Included(start1), StartBound::Excluded(start2)) => partial_cmp_with_priority(start1, start2, true),
|
||||
(StartBound::Included(start1), StartBound::ReverseExcluded(start2)) => partial_cmp_with_priority(start1, start2, false),
|
||||
(StartBound::Included(_), StartBound::ReverseUnbounded) => Some(Ordering::Less),
|
||||
(StartBound::Included(_), StartBound::Unbounded) => Some(Ordering::Greater),
|
||||
|
||||
(StartBound::Excluded(start1), StartBound::Excluded(start2)) => start1.partial_cmp(start2),
|
||||
(StartBound::Excluded(start1), StartBound::Included(start2)) => partial_cmp_with_priority(start1, start2, false),
|
||||
(StartBound::Excluded(start1), StartBound::ReverseExcluded(start2)) => partial_cmp_with_priority(start1, start2, false),
|
||||
(StartBound::Excluded(_), StartBound::Unbounded) => Some(Ordering::Greater),
|
||||
(StartBound::Excluded(_), StartBound::ReverseUnbounded) => Some(Ordering::Less),
|
||||
|
||||
(StartBound::Unbounded, StartBound::Included(_)) => Some(Ordering::Less),
|
||||
(StartBound::Unbounded, StartBound::Excluded(_)) => Some(Ordering::Less),
|
||||
(StartBound::Unbounded, StartBound::ReverseExcluded(_)) => Some(Ordering::Less),
|
||||
(StartBound::Unbounded, StartBound::Unbounded) => Some(Ordering::Equal),
|
||||
(StartBound::Unbounded, StartBound::ReverseUnbounded) => Some(Ordering::Less),
|
||||
|
||||
(StartBound::ReverseExcluded(start1), StartBound::ReverseExcluded(start2)) => start1.partial_cmp(start2),
|
||||
(StartBound::ReverseExcluded(start1), StartBound::Included(start2)) => partial_cmp_with_priority(start1, start2, true),
|
||||
(StartBound::ReverseExcluded(start1), StartBound::Excluded(start2)) => partial_cmp_with_priority(start1, start2, true),
|
||||
(StartBound::ReverseExcluded(_), StartBound::Unbounded) => Some(Ordering::Greater),
|
||||
(StartBound::ReverseExcluded(_), StartBound::ReverseUnbounded) => Some(Ordering::Less),
|
||||
|
||||
(StartBound::ReverseUnbounded, StartBound::Included(_)) => Some(Ordering::Greater),
|
||||
(StartBound::ReverseUnbounded, StartBound::Excluded(_)) => Some(Ordering::Greater),
|
||||
(StartBound::ReverseUnbounded, StartBound::ReverseExcluded(_)) => Some(Ordering::Greater),
|
||||
(StartBound::ReverseUnbounded, StartBound::ReverseUnbounded) => Some(Ordering::Equal),
|
||||
(StartBound::ReverseUnbounded, StartBound::Unbounded) => Some(Ordering::Greater),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if they are equal say the item with priority is larger
|
||||
//where false means left has priority and true means right
|
||||
#[parent_tested]
|
||||
fn partial_cmp_with_priority<T>(
|
||||
left: &T,
|
||||
right: &T,
|
||||
priority: bool,
|
||||
) -> Option<Ordering>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
let result = left.partial_cmp(right)?;
|
||||
|
||||
Some(match result {
|
||||
Ordering::Equal => match priority {
|
||||
false => Ordering::Greater,
|
||||
true => Ordering::Less,
|
||||
},
|
||||
x => x,
|
||||
})
|
||||
}
|
||||
|
||||
impl<T> Ord for StartBound<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
#[trivial]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Bound<T>> for StartBound<T> {
|
||||
#[trivial]
|
||||
fn from(bound: Bound<T>) -> Self {
|
||||
match bound {
|
||||
Bound::Included(point) => StartBound::Included(point),
|
||||
Bound::Excluded(point) => StartBound::Excluded(point),
|
||||
Bound::Unbounded => StartBound::Unbounded,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> From<StartBound<T>> for Bound<T> {
|
||||
#[trivial]
|
||||
fn from(start_bound: StartBound<T>) -> Bound<T> {
|
||||
match start_bound {
|
||||
StartBound::Included(point) => Bound::Included(point),
|
||||
StartBound::Excluded(point) => Bound::Excluded(point),
|
||||
StartBound::Unbounded => Bound::Unbounded,
|
||||
_ => panic!("unsuitable operation"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn mass_start_bound_partial_ord_test() {
|
||||
//Included
|
||||
assert!(StartBound::Included(2) == StartBound::Included(2));
|
||||
assert!(StartBound::Included(2) <= StartBound::Included(2));
|
||||
assert!(StartBound::Included(2) >= StartBound::Included(2));
|
||||
assert!(StartBound::Included(0) < StartBound::Included(2));
|
||||
assert!(StartBound::Included(2) > StartBound::Included(0));
|
||||
|
||||
assert!(StartBound::Included(2) < StartBound::Excluded(2));
|
||||
assert!(StartBound::Included(0) < StartBound::Excluded(2));
|
||||
assert!(StartBound::Included(2) > StartBound::Excluded(0));
|
||||
|
||||
assert!(StartBound::Included(2) > StartBound::Unbounded);
|
||||
|
||||
assert!(StartBound::Included(2) > StartBound::ReverseExcluded(2));
|
||||
assert!(StartBound::Included(0) < StartBound::ReverseExcluded(2));
|
||||
assert!(StartBound::Included(2) > StartBound::ReverseExcluded(0));
|
||||
|
||||
assert!(StartBound::Included(2) < StartBound::ReverseUnbounded);
|
||||
|
||||
//Exluded
|
||||
assert!(StartBound::Excluded(2) == StartBound::Excluded(2));
|
||||
assert!(StartBound::Excluded(2) <= StartBound::Excluded(2));
|
||||
assert!(StartBound::Excluded(2) >= StartBound::Excluded(2));
|
||||
assert!(StartBound::Excluded(0) < StartBound::Excluded(2));
|
||||
assert!(StartBound::Excluded(2) > StartBound::Excluded(0));
|
||||
|
||||
assert!(StartBound::Excluded(2) > StartBound::Unbounded);
|
||||
|
||||
assert!(StartBound::Excluded(2) > StartBound::ReverseExcluded(2));
|
||||
assert!(StartBound::Excluded(2) > StartBound::ReverseExcluded(0));
|
||||
assert!(StartBound::Excluded(0) < StartBound::ReverseExcluded(2));
|
||||
|
||||
assert!(StartBound::Excluded(2) < StartBound::ReverseUnbounded);
|
||||
|
||||
//Unbounded
|
||||
assert!(StartBound::Unbounded::<u8> == StartBound::Unbounded);
|
||||
assert!(StartBound::Unbounded::<u8> <= StartBound::Unbounded);
|
||||
assert!(StartBound::Unbounded::<u8> >= StartBound::Unbounded);
|
||||
|
||||
assert!(StartBound::Unbounded < StartBound::ReverseExcluded(2));
|
||||
|
||||
assert!(StartBound::Unbounded::<u8> < StartBound::ReverseUnbounded);
|
||||
|
||||
//ReverseExcluded
|
||||
assert!(StartBound::ReverseExcluded(2) == StartBound::ReverseExcluded(2));
|
||||
assert!(StartBound::ReverseExcluded(2) <= StartBound::ReverseExcluded(2));
|
||||
assert!(StartBound::ReverseExcluded(2) >= StartBound::ReverseExcluded(2));
|
||||
assert!(StartBound::ReverseExcluded(0) < StartBound::ReverseExcluded(2));
|
||||
assert!(StartBound::ReverseExcluded(2) > StartBound::ReverseExcluded(0));
|
||||
|
||||
//ReverseUnbounded
|
||||
assert!(StartBound::ReverseUnbounded::<u8> == StartBound::ReverseUnbounded);
|
||||
assert!(StartBound::ReverseUnbounded::<u8> <= StartBound::ReverseUnbounded);
|
||||
assert!(StartBound::ReverseUnbounded::<u8> >= StartBound::ReverseUnbounded);
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
#![feature(let_chains)]
|
||||
#![allow(clippy::tabs_in_doc_comments)]
|
||||
#![allow(clippy::needless_return)]
|
||||
pub(crate) mod bounds;
|
||||
pub(crate) mod bound_ord;
|
||||
pub mod range_bounds_map;
|
||||
//pub mod range_bounds_set;
|
||||
pub mod try_from_bounds;
|
||||
|
@ -28,7 +28,7 @@ use itertools::Itertools;
|
||||
use labels::{tested, trivial};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::bounds::StartBound;
|
||||
use crate::bound_ord::BoundOrd;
|
||||
use crate::TryFromBounds;
|
||||
|
||||
/// An ordered map of [`RangeBounds`] based on [`BTreeMap`]
|
||||
@ -120,7 +120,7 @@ pub struct RangeBoundsMap<I, K, V>
|
||||
where
|
||||
I: PartialOrd,
|
||||
{
|
||||
starts: BTreeMap<StartBound<I>, (K, V)>,
|
||||
starts: BTreeMap<BoundOrd<I>, (K, V)>,
|
||||
}
|
||||
|
||||
/// An error type to represent a `RangeBounds` overlapping another
|
||||
@ -333,8 +333,8 @@ where
|
||||
return Err(OverlapError);
|
||||
}
|
||||
|
||||
let start = StartBound::from(range_bounds.start_bound());
|
||||
let end = StartBound::from(range_bounds.end_bound())
|
||||
let start = BoundOrd::from(range_bounds.start_bound());
|
||||
let end = BoundOrd::from(range_bounds.end_bound())
|
||||
.into_end_bound();
|
||||
|
||||
if start > end {
|
||||
@ -342,7 +342,7 @@ where
|
||||
}
|
||||
|
||||
self.starts.insert(
|
||||
StartBound::from(range_bounds.start_bound().cloned()),
|
||||
BoundOrd::from(range_bounds.start_bound().cloned()),
|
||||
(range_bounds, value),
|
||||
);
|
||||
|
||||
@ -408,8 +408,8 @@ where
|
||||
panic!("Invalid range bounds!");
|
||||
}
|
||||
|
||||
let start = StartBound::from(range_bounds.start_bound().cloned());
|
||||
let end = StartBound::from(range_bounds.end_bound().cloned())
|
||||
let start = BoundOrd::from(range_bounds.start_bound().cloned());
|
||||
let end = BoundOrd::from(range_bounds.end_bound().cloned())
|
||||
.into_end_bound();
|
||||
|
||||
let start_range_bounds = (
|
||||
@ -430,7 +430,7 @@ where
|
||||
self.starts
|
||||
.range((
|
||||
Bound::Unbounded,
|
||||
Bound::Excluded(StartBound::from(
|
||||
Bound::Excluded(BoundOrd::from(
|
||||
range_bounds.start_bound().cloned(),
|
||||
)),
|
||||
))
|
||||
@ -521,7 +521,7 @@ where
|
||||
{
|
||||
return self
|
||||
.starts
|
||||
.get_mut(&StartBound::from(overlapping_start_bound.cloned()))
|
||||
.get_mut(&BoundOrd::from(overlapping_start_bound.cloned()))
|
||||
.map(|(_, value)| value);
|
||||
}
|
||||
return None;
|
||||
@ -627,9 +627,9 @@ where
|
||||
//or collectiong anything, may depend on a nicer upstream
|
||||
//BTreeMap remove_range function
|
||||
|
||||
let to_remove: Vec<StartBound<I>> = self
|
||||
let to_remove: Vec<BoundOrd<I>> = self
|
||||
.overlapping(range_bounds)
|
||||
.map(|(key, _)| (StartBound::from(key.start_bound().cloned())))
|
||||
.map(|(key, _)| (BoundOrd::from(key.start_bound().cloned())))
|
||||
.collect();
|
||||
|
||||
let mut output = Vec::new();
|
||||
@ -936,10 +936,10 @@ where
|
||||
|
||||
let touching_left_start_bound = self
|
||||
.touching_left(&range_bounds)
|
||||
.map(|x| StartBound::from(x.start_bound().cloned()));
|
||||
.map(|x| BoundOrd::from(x.start_bound().cloned()));
|
||||
let touching_right_start_bound = self
|
||||
.touching_right(&range_bounds)
|
||||
.map(|x| StartBound::from(x.start_bound().cloned()));
|
||||
.map(|x| BoundOrd::from(x.start_bound().cloned()));
|
||||
|
||||
let start_bound = match touching_left_start_bound {
|
||||
Some(ref x) => self.starts.get(x).unwrap().0.start_bound().cloned(),
|
||||
@ -965,18 +965,18 @@ where
|
||||
|
||||
// In with the new!
|
||||
self.starts.insert(
|
||||
StartBound::from(new_range_bounds.start_bound().cloned()),
|
||||
BoundOrd::from(new_range_bounds.start_bound().cloned()),
|
||||
(new_range_bounds, value),
|
||||
);
|
||||
|
||||
return Ok(&self.starts.get(&StartBound::from(start_bound)).unwrap().0);
|
||||
return Ok(&self.starts.get(&BoundOrd::from(start_bound)).unwrap().0);
|
||||
}
|
||||
fn touching_left(&self, range_bounds: &K) -> Option<&K> {
|
||||
return self
|
||||
.starts
|
||||
.range((
|
||||
Bound::Unbounded,
|
||||
Bound::Excluded(StartBound::from(
|
||||
Bound::Excluded(BoundOrd::from(
|
||||
range_bounds.start_bound().cloned(),
|
||||
)),
|
||||
))
|
||||
@ -988,7 +988,7 @@ where
|
||||
return self
|
||||
.starts
|
||||
.range((
|
||||
Bound::Excluded(StartBound::from(
|
||||
Bound::Excluded(BoundOrd::from(
|
||||
range_bounds.start_bound().cloned(),
|
||||
)),
|
||||
Bound::Unbounded,
|
||||
@ -1065,11 +1065,11 @@ where
|
||||
|
||||
// In with the new!
|
||||
self.starts.insert(
|
||||
StartBound::from(new_range_bounds.start_bound().cloned()),
|
||||
BoundOrd::from(new_range_bounds.start_bound().cloned()),
|
||||
(new_range_bounds, value),
|
||||
);
|
||||
|
||||
return Ok(&self.starts.get(&StartBound::from(start_bound)).unwrap().0);
|
||||
return Ok(&self.starts.get(&BoundOrd::from(start_bound)).unwrap().0);
|
||||
}
|
||||
fn overlapping_swell<'a>(
|
||||
&'a self,
|
||||
@ -1079,18 +1079,18 @@ where
|
||||
|
||||
let start_bound = match overlapping.peek() {
|
||||
Some((first, _)) => std::cmp::min(
|
||||
StartBound::from(first.start_bound()),
|
||||
StartBound::from(range_bounds.start_bound()),
|
||||
BoundOrd::from(first.start_bound()),
|
||||
BoundOrd::from(range_bounds.start_bound()),
|
||||
),
|
||||
None => StartBound::from(range_bounds.start_bound()),
|
||||
None => BoundOrd::from(range_bounds.start_bound()),
|
||||
};
|
||||
let end_bound = match overlapping.next_back() {
|
||||
Some((last, _)) => std::cmp::max(
|
||||
StartBound::from(last.end_bound()).into_end_bound(),
|
||||
StartBound::from(range_bounds.end_bound()).into_end_bound(),
|
||||
BoundOrd::from(last.end_bound()).into_end_bound(),
|
||||
BoundOrd::from(range_bounds.end_bound()).into_end_bound(),
|
||||
)
|
||||
.into_start_bound(),
|
||||
None => StartBound::from(range_bounds.end_bound()),
|
||||
None => BoundOrd::from(range_bounds.end_bound()),
|
||||
};
|
||||
|
||||
return (Bound::from(start_bound), Bound::from(end_bound));
|
||||
@ -1172,11 +1172,11 @@ where
|
||||
|
||||
self.remove_overlapping(&new_range_bounds).next();
|
||||
self.starts.insert(
|
||||
StartBound::from(start_bound.clone()),
|
||||
BoundOrd::from(start_bound.clone()),
|
||||
(new_range_bounds, value),
|
||||
);
|
||||
|
||||
return Ok(&self.starts.get(&StartBound::from(start_bound)).unwrap().0);
|
||||
return Ok(&self.starts.get(&BoundOrd::from(start_bound)).unwrap().0);
|
||||
}
|
||||
|
||||
/// Adds a new (`RangeBounds`, `Value`) pair to the map and
|
||||
@ -1300,8 +1300,8 @@ where
|
||||
let (cut_start_bound, cut_end_bound) =
|
||||
(cut_range_bounds.start_bound(), cut_range_bounds.end_bound());
|
||||
|
||||
let left_section = match StartBound::from(cut_start_bound)
|
||||
> StartBound::from(base_start_bound)
|
||||
let left_section = match BoundOrd::from(cut_start_bound)
|
||||
> BoundOrd::from(base_start_bound)
|
||||
{
|
||||
false => None,
|
||||
true => Some((
|
||||
@ -1309,8 +1309,8 @@ where
|
||||
flip_bound(cut_start_bound).cloned(),
|
||||
)),
|
||||
};
|
||||
let right_section = match StartBound::from(cut_end_bound).into_end_bound()
|
||||
< StartBound::from(base_end_bound).into_end_bound()
|
||||
let right_section = match BoundOrd::from(cut_end_bound).into_end_bound()
|
||||
< BoundOrd::from(base_end_bound).into_end_bound()
|
||||
{
|
||||
false => None,
|
||||
true => {
|
||||
@ -1356,7 +1356,7 @@ where
|
||||
let b_end = b.end_bound();
|
||||
|
||||
let (left_end, right_start) =
|
||||
match StartBound::from(a_start).cmp(&StartBound::from(b_start)) {
|
||||
match BoundOrd::from(a_start).cmp(&BoundOrd::from(b_start)) {
|
||||
Ordering::Less => (a_end, b_start),
|
||||
Ordering::Greater => (b_end, a_start),
|
||||
Ordering::Equal => return true,
|
||||
@ -1390,7 +1390,7 @@ where
|
||||
let b_end = b.end_bound();
|
||||
|
||||
let (left_end, right_start) =
|
||||
match StartBound::from(a_start).cmp(&StartBound::from(b_start)) {
|
||||
match BoundOrd::from(a_start).cmp(&BoundOrd::from(b_start)) {
|
||||
Ordering::Less => (a_end, b_start),
|
||||
Ordering::Greater => (b_end, a_start),
|
||||
Ordering::Equal => return false,
|
||||
@ -1419,7 +1419,7 @@ mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::bounds::StartBound;
|
||||
use crate::bound_ord::BoundOrd;
|
||||
|
||||
type TestBounds = (Bound<u8>, Bound<u8>);
|
||||
|
||||
@ -1580,8 +1580,8 @@ mod tests {
|
||||
}
|
||||
//make our expected_overlapping the correct order
|
||||
if expected_overlapping.len() > 1 {
|
||||
if StartBound::from(expected_overlapping[0].start_bound())
|
||||
> StartBound::from(
|
||||
if BoundOrd::from(expected_overlapping[0].start_bound())
|
||||
> BoundOrd::from(
|
||||
expected_overlapping[1].start_bound(),
|
||||
) {
|
||||
expected_overlapping.swap(0, 1);
|
||||
|
9
todo.md
9
todo.md
@ -4,19 +4,18 @@
|
||||
- replace MultiBounds::\* with mee() and mii()
|
||||
- make a StartBoundWrapper that uses StartBound to implement ord and
|
||||
use that instead of storing the startbound twice
|
||||
- change startBound to BoundOrd with constructors for either start or
|
||||
end_bounds
|
||||
|
||||
# features
|
||||
|
||||
- RangeMap, RangeSet, RangeInclusiveMap...
|
||||
- RangeMap, RangeSet, RangeInclusiveMap... types for signature
|
||||
simplification
|
||||
- add coalesce if same-value otherwise overwrite) function to make
|
||||
finally make range_bounds_map a superset of rangemap
|
||||
|
||||
# docs
|
||||
|
||||
- write something somewhere about wrapper types for RangeBoundsMap
|
||||
that can simplify function signatures due to known invariants. For
|
||||
example a wrapper for using K=std::ops::Range which simplifies a LOT
|
||||
probaly in caveats + github issue
|
||||
- write docs for undocced things
|
||||
|
||||
# time based
|
||||
|
Loading…
x
Reference in New Issue
Block a user