checkpoint
This commit is contained in:
parent
db51d49328
commit
a9cb31d024
25
Cargo.lock
generated
25
Cargo.lock
generated
@ -2,12 +2,6 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "btree_monstrousity"
|
||||
version = "0.0.4"
|
||||
@ -46,24 +40,6 @@ version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.3"
|
||||
@ -109,7 +85,6 @@ version = "0.3.2"
|
||||
dependencies = [
|
||||
"btree_monstrousity",
|
||||
"either",
|
||||
"ordered-float",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
]
|
||||
|
@ -21,5 +21,4 @@ btree_monstrousity = {version ="0.0.4", features = ["btree_drain_filter", "btree
|
||||
either = "1.8.1"
|
||||
|
||||
[dev-dependencies]
|
||||
ordered-float = "3.4.0"
|
||||
pretty_assertions = "1.3.0"
|
||||
|
@ -1,3 +1,4 @@
|
||||
# todo put back to normal
|
||||
hard_tabs=true
|
||||
imports_granularity="Module"
|
||||
group_imports="StdExternalCrate"
|
||||
|
@ -230,6 +230,8 @@ pub mod range_bounds_map;
|
||||
pub mod range_bounds_set;
|
||||
|
||||
pub use crate::range_bounds_map::{
|
||||
OverlapError, OverlapOrTryFromDiscreteBoundsError, RangeBoundsMap, TryFromDiscreteBoundsError,
|
||||
OverlapError, OverlapOrTryFromDiscreteBoundsError, RangeBoundsMap,
|
||||
};
|
||||
pub use crate::range_bounds_set::RangeBoundsSet;
|
||||
pub use crate::try_from_discrete_bounds::{TryFromDiscreteBounds, TryFromDiscreteBoundsError};
|
||||
pub use crate::discrete_bounds::DiscreteBounds;
|
||||
|
@ -33,7 +33,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use crate::discrete_bound_ord::DiscreteBoundOrd;
|
||||
use crate::discrete_bounds::{DiscreteBound, DiscreteBounds};
|
||||
use crate::stepable::Stepable;
|
||||
use crate::try_from_discrete_bounds::TryFromDiscreteBounds;
|
||||
use crate::try_from_discrete_bounds::{TryFromDiscreteBounds, TryFromDiscreteBoundsError};
|
||||
use crate::utils::{cmp_discrete_bound_ord_with_range, cut_range, is_valid_range, overlaps};
|
||||
|
||||
/// An ordered map of non-overlapping ranges based on [`BTreeMap`].
|
||||
@ -78,34 +78,31 @@ use crate::utils::{cmp_discrete_bound_ord_with_range, cut_range, is_valid_range,
|
||||
/// ```
|
||||
/// use std::ops::{Bound, RangeBounds};
|
||||
///
|
||||
/// use ordered_float::NotNan;
|
||||
/// use range_bounds_map::RangeBoundsMap;
|
||||
///
|
||||
/// // An Exclusive-Exclusive range of [`f32`]s is not provided by any
|
||||
/// // std::ops ranges.
|
||||
/// // An Exclusive-Exclusive range is not provided by any
|
||||
/// // std::ops ranges so let't make our own!.
|
||||
///
|
||||
/// // We use [`ordered_float::NotNan`]s as the inner type must be Ord
|
||||
/// // similar to a normal [`BTreeMap`].
|
||||
/// #[derive(Debug, Copy, Clone, PartialEq)]
|
||||
/// struct ExEx {
|
||||
/// start: NotNan<f32>,
|
||||
/// end: NotNan<f32>,
|
||||
/// start: u8,
|
||||
/// end: u8,
|
||||
/// }
|
||||
/// impl ExEx {
|
||||
/// fn new(start: u8, end: u8) -> ExEx {
|
||||
/// ExEx {
|
||||
/// start,
|
||||
/// end,
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// # impl ExEx {
|
||||
/// # fn new(start: f32, end: f32) -> ExEx {
|
||||
/// # ExEx {
|
||||
/// # start: NotNan::new(start).unwrap(),
|
||||
/// # end: NotNan::new(end).unwrap(),
|
||||
/// # }
|
||||
/// # }
|
||||
/// # }
|
||||
///
|
||||
/// // Implement RangeBounds<f32> on our new type
|
||||
/// impl RangeBounds<NotNan<f32>> for ExEx {
|
||||
/// fn start_bound(&self) -> Bound<&NotNan<f32>> {
|
||||
/// Bound::Excluded(&self.start)
|
||||
/// // Implement RangeBounds<u8> on our new type
|
||||
/// impl RangeBounds<u8> for ExEx {
|
||||
/// fn start_bound(&self) -> Bound<&u8> {
|
||||
/// Bound::Excluded(&self.start)
|
||||
/// }
|
||||
/// fn end_bound(&self) -> Bound<&NotNan<f32>> {
|
||||
/// fn end_bound(&self) -> Bound<&u8> {
|
||||
/// Bound::Excluded(&self.end)
|
||||
/// }
|
||||
/// }
|
||||
@ -113,20 +110,20 @@ use crate::utils::{cmp_discrete_bound_ord_with_range, cut_range, is_valid_range,
|
||||
/// // Now we can make a [`RangeBoundsMap`] of [`ExEx`]s to `i8`
|
||||
/// let mut map = RangeBoundsMap::new();
|
||||
///
|
||||
/// map.insert_strict(ExEx::new(0.0, 5.0), 8).unwrap();
|
||||
/// map.insert_strict(ExEx::new(5.0, 7.5), 32).unwrap();
|
||||
/// map.insert_strict(ExEx::new(0, 5), 8).unwrap();
|
||||
/// map.insert_strict(ExEx::new(5, 7), 32).unwrap();
|
||||
///
|
||||
/// assert_eq!(map.contains_point(NotNan::new(5.0).unwrap()), false);
|
||||
/// assert_eq!(map.contains_point(5), false);
|
||||
///
|
||||
/// assert_eq!(map.get_at_point(NotNan::new(9.0).unwrap()), None);
|
||||
/// assert_eq!(map.get_at_point(9), None);
|
||||
/// assert_eq!(
|
||||
/// map.get_at_point(NotNan::new(7.0).unwrap()),
|
||||
/// map.get_at_point(6),
|
||||
/// Some(&32)
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// map.get_entry_at_point(NotNan::new(2.0).unwrap()),
|
||||
/// Ok((&ExEx::new(0.0, 5.0), &8))
|
||||
/// map.get_entry_at_point(2),
|
||||
/// Ok((&ExEx::new(0, 5), &8))
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
@ -143,133 +140,6 @@ pub struct RangeBoundsMap<I, K, V> {
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct OverlapError;
|
||||
|
||||
/// An error type to represent a failed [`TryFromDiscreteBounds`] within a
|
||||
/// method.
|
||||
///
|
||||
/// There are several methods that return this error, and some of the
|
||||
/// causes of this error can be very subtle, so here are some examples
|
||||
/// showing all the reasons this error might be returned.
|
||||
///
|
||||
/// # Example with [`RangeBoundsMap::cut()`]
|
||||
///
|
||||
/// The first way you may recieve [`TryFromDiscreteBoundsError`] is from
|
||||
/// [`RangeBoundsMap::cut()`].
|
||||
///
|
||||
/// In this example we try to cut `ii(4, 6)` out of a `RangeBoundsMap`
|
||||
/// that contains `ie(2, 8)`. If this was successful then the
|
||||
/// `RangeBoundsMap` would hold `ie(2, 4)` and `(Bound::Exclusive(6),
|
||||
/// Bound::Exclusive(8))`. However, since the `RangeBounds` type of
|
||||
/// this `RangeBoundsMap` is `Range<{integer}>` the latter of the two
|
||||
/// new `RangeBounds` is "unrepresentable", and hence will fail to be
|
||||
/// created via [`TryFromDiscreteBounds`] and [`RangeBoundsMap::cut()`] will
|
||||
/// return Err(TryFromDiscreteBoundsError).
|
||||
///
|
||||
/// ```
|
||||
/// use range_bounds_map::test_ranges::{ie_strict, ii};
|
||||
/// use range_bounds_map::{RangeBoundsMap, TryFromDiscreteBoundsError};
|
||||
///
|
||||
/// let mut map =
|
||||
/// RangeBoundsMap::from_slice_strict([(ie_strict(2, 8), true)])
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert!(map.cut(ii(4, 6)).is_err());
|
||||
/// ```
|
||||
///
|
||||
/// # Example with `insert_merge_*` functions.
|
||||
///
|
||||
/// The second and final way you may recieve a [`TryFromDiscreteBoundsError`]
|
||||
/// is via merging methods such as
|
||||
/// [`RangeBoundsMap::insert_merge_touching`].
|
||||
///
|
||||
/// In the first example it was fairly easy to create an invalid
|
||||
/// `RangeBounds` by cutting with a different `RangeBounds` than the
|
||||
/// underlying `RangeBoundsMap`'s `RangeBounds` type. However, the
|
||||
/// `insert_merge_*` functions all take `range: K` as an
|
||||
/// argument so it is not possible to create an invalid `K` type
|
||||
/// directly. However upon "merging" of two ranges (even if
|
||||
/// both of them are type `K`), you can create a range that *cannot* be
|
||||
/// of type `K`.
|
||||
///
|
||||
/// In this example we use a `RangeBounds` type that can be either
|
||||
/// Inclusive-Inclusive OR Exclusive-Exclusive. We then try to use
|
||||
/// [`RangeBoundsMap::insert_merge_touching()`] to "merge" an
|
||||
/// Inclusive-Inclusive and a Exclusive-Exclusive `MultiBounds`. This
|
||||
/// will however fail as the resulting "merged" `RangeBounds` would
|
||||
/// have to be Inclusive-Exclusive which `MultiBounds` does not support.
|
||||
///
|
||||
/// ```
|
||||
/// use std::ops::{Bound, RangeBounds};
|
||||
///
|
||||
/// use range_bounds_map::{
|
||||
/// OverlapOrTryFromDiscreteBoundsError, RangeBoundsMap, TryFromDiscreteBounds,
|
||||
/// TryFromDiscreteBoundsError,
|
||||
/// };
|
||||
///
|
||||
/// #[derive(Debug, Copy, Clone, PartialEq)]
|
||||
/// enum MultiBounds {
|
||||
/// Inclusive(i8, i8),
|
||||
/// Exclusive(i8, i8),
|
||||
/// }
|
||||
///
|
||||
/// impl RangeBounds<i8> for MultiBounds {
|
||||
/// fn start_bound(&self) -> Bound<&i8> {
|
||||
/// match self {
|
||||
/// MultiBounds::Inclusive(start, _) => {
|
||||
/// Bound::Included(start)
|
||||
/// }
|
||||
/// MultiBounds::Exclusive(start, _) => {
|
||||
/// Bound::Excluded(start)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// fn end_bound(&self) -> Bound<&i8> {
|
||||
/// match self {
|
||||
/// MultiBounds::Inclusive(_, end) => {
|
||||
/// Bound::Included(end)
|
||||
/// }
|
||||
/// MultiBounds::Exclusive(_, end) => {
|
||||
/// Bound::Excluded(end)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl TryFromDiscreteBounds<i8> for MultiBounds {
|
||||
/// fn try_from_bounds(
|
||||
/// start_bound: Bound<i8>,
|
||||
/// end_bound: Bound<i8>,
|
||||
/// ) -> Result<Self, TryFromDiscreteBoundsError> {
|
||||
/// match (start_bound, end_bound) {
|
||||
/// (Bound::Included(start), Bound::Included(end)) => {
|
||||
/// Ok(MultiBounds::Inclusive(start, end))
|
||||
/// }
|
||||
/// (Bound::Excluded(start), Bound::Excluded(end)) => {
|
||||
/// Ok(MultiBounds::Exclusive(start, end))
|
||||
/// }
|
||||
/// _ => Err(TryFromDiscreteBoundsError),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut map = RangeBoundsMap::from_slice_strict([(
|
||||
/// MultiBounds::Inclusive(2, 4),
|
||||
/// true,
|
||||
/// )])
|
||||
/// .unwrap();
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// map.insert_merge_touching(
|
||||
/// MultiBounds::Exclusive(4, 6),
|
||||
/// false
|
||||
/// ),
|
||||
/// Err(OverlapOrTryFromDiscreteBoundsError::TryFromDiscreteBounds(
|
||||
/// TryFromDiscreteBoundsError
|
||||
/// ))
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct TryFromDiscreteBoundsError;
|
||||
|
||||
/// An error type to represent either an [`OverlapError`] or a
|
||||
/// [`TryFromDiscreteBoundsError`].
|
||||
#[derive(PartialEq, Debug)]
|
||||
@ -289,10 +159,10 @@ where
|
||||
/// ```
|
||||
/// use std::ops::Range;
|
||||
///
|
||||
/// use range_bounds_map::test_ranges::AnyRange;
|
||||
/// use range_bounds_map::RangeBoundsMap;
|
||||
/// use range_bounds_map::DiscreteBounds;
|
||||
///
|
||||
/// let map: RangeBoundsMap<i8, AnyRange, bool> =
|
||||
/// let map: RangeBoundsMap<i8, DiscreteBounds<i8>, bool> =
|
||||
/// RangeBoundsMap::new();
|
||||
/// ```
|
||||
pub fn new() -> Self {
|
||||
@ -537,7 +407,7 @@ where
|
||||
/// ```
|
||||
/// use std::ops::Bound;
|
||||
///
|
||||
/// use range_bounds_map::test_ranges::ie;
|
||||
/// use range_bounds_map::test_ranges::{ie, iu};
|
||||
/// use range_bounds_map::RangeBoundsMap;
|
||||
///
|
||||
/// let map = RangeBoundsMap::from_slice_strict([
|
||||
@ -551,35 +421,36 @@ where
|
||||
/// assert_eq!(map.get_entry_at_point(5), Ok((&ie(4, 6), &true)));
|
||||
/// assert_eq!(
|
||||
/// map.get_entry_at_point(7),
|
||||
/// Err((Bound::Included(6), Bound::Excluded(8)))
|
||||
/// Err(ie(6, 8))
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// map.get_entry_at_point(101),
|
||||
/// Err((Bound::Included(100), Bound::Unbounded))
|
||||
/// Err(iu(100))
|
||||
/// );
|
||||
/// ```
|
||||
pub fn get_entry_at_point(&self, point: I) -> Result<(&K, &V), DiscreteBounds<I>> {
|
||||
self.inner
|
||||
.get_key_value(overlapping_comp(DiscreteBoundOrd::Included(point)))
|
||||
.ok_or_else(|| {
|
||||
let lower = self.inner.upper_bound(
|
||||
overlapping_comp(DiscreteBoundOrd::Included(point)),
|
||||
SearchBoundCustom::Included,
|
||||
);
|
||||
let upper = self.inner.lower_bound(
|
||||
overlapping_comp(DiscreteBoundOrd::Included(point)),
|
||||
SearchBoundCustom::Included,
|
||||
);
|
||||
.ok_or_else(|| self.get_gap_at_raw(DiscreteBoundOrd::Included(point)))
|
||||
}
|
||||
fn get_gap_at_raw(&self, discrete_bound_ord: DiscreteBoundOrd<I>) -> DiscreteBounds<I> {
|
||||
let lower = self.inner.upper_bound(
|
||||
overlapping_comp(discrete_bound_ord),
|
||||
SearchBoundCustom::Included,
|
||||
);
|
||||
let upper = self.inner.lower_bound(
|
||||
overlapping_comp(discrete_bound_ord),
|
||||
SearchBoundCustom::Included,
|
||||
);
|
||||
|
||||
DiscreteBounds {
|
||||
start: lower.key().map_or(DiscreteBound::Unbounded, |lower| {
|
||||
DiscreteBound::from(lower.end()).up_if_finite()
|
||||
}),
|
||||
end: upper.key().map_or(DiscreteBound::Unbounded, |upper| {
|
||||
DiscreteBound::from(upper.start()).down_if_finite()
|
||||
}),
|
||||
}
|
||||
})
|
||||
DiscreteBounds {
|
||||
start: lower.key().map_or(DiscreteBound::Unbounded, |lower| {
|
||||
DiscreteBound::from(lower.end()).up_if_finite()
|
||||
}),
|
||||
end: upper.key().map_or(DiscreteBound::Unbounded, |upper| {
|
||||
DiscreteBound::from(upper.start()).down_if_finite()
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over every entry in the map in ascending
|
||||
@ -723,13 +594,12 @@ where
|
||||
/// assert_eq!(
|
||||
/// base.cut(ie(2, 40)).unwrap().collect::<Vec<_>>(),
|
||||
/// [
|
||||
/// ((Bound::Included(2), Bound::Excluded(4)), false),
|
||||
/// ((Bound::Included(4), Bound::Excluded(8)), true),
|
||||
/// ((Bound::Included(8), Bound::Excluded(40)), false),
|
||||
/// (ie(2, 4), false),
|
||||
/// (ie(4, 8), true),
|
||||
/// (ie(8, 40), false),
|
||||
/// ]
|
||||
/// );
|
||||
/// assert_eq!(base, after_cut);
|
||||
/// assert!(base.cut(ii(60, 80)).is_err());
|
||||
/// ```
|
||||
pub fn cut<'a, Q>(
|
||||
&'a mut self,
|
||||
@ -900,9 +770,7 @@ where
|
||||
/// assert_eq!(
|
||||
/// gaps.collect::<Vec<_>>(),
|
||||
/// [
|
||||
/// (Bound::Included(3), Bound::Excluded(5)),
|
||||
/// (Bound::Included(7), Bound::Excluded(9)),
|
||||
/// (Bound::Included(100), Bound::Unbounded)
|
||||
/// ie(3, 5),ie(7, 9),iu(100)
|
||||
/// ]
|
||||
/// );
|
||||
/// ```
|
||||
@ -919,32 +787,59 @@ where
|
||||
|
||||
// If the start or end point of outer_range is not
|
||||
// contained within a RangeBounds in the map then we need to
|
||||
// generate a artificial RangeBounds to use instead.
|
||||
//
|
||||
// We also have to flip the artificial ones ahead of time as
|
||||
// we actually want the range endpoints included
|
||||
// not excluded unlike with other bounds in artificials
|
||||
|
||||
//todo check if stepable first before adding artificials
|
||||
let artificial_start = (outer_range.start(), outer_range.start().down_if_finite());
|
||||
let artificial_end = (outer_range.end().up_if_finite(), outer_range.start());
|
||||
let mut artificials = once(artificial_start)
|
||||
.chain(overlapping)
|
||||
.chain(once(artificial_end));
|
||||
|
||||
let start_contained = self
|
||||
// generate the gaps.
|
||||
let start_gap = (!self
|
||||
.inner
|
||||
.contains_key(overlapping_comp(outer_range.start()));
|
||||
let end_contained = self.inner.contains_key(overlapping_comp(outer_range.end()));
|
||||
.contains_key(overlapping_comp(outer_range.start())))
|
||||
.then(|| self.get_gap_at_raw(outer_range.start()));
|
||||
let end_gap = (!self.inner.contains_key(overlapping_comp(outer_range.end())))
|
||||
.then(|| self.get_gap_at_raw(outer_range.end()));
|
||||
|
||||
if start_contained {
|
||||
artificials.next();
|
||||
}
|
||||
if end_contained {
|
||||
artificials.next_back();
|
||||
}
|
||||
let (trimmed_start_gap, trimmed_end_gap) = match (start_gap, end_gap) {
|
||||
(Some(mut start_gap), Some(mut end_gap)) => {
|
||||
if start_gap.start() == end_gap.end() {
|
||||
//it's the same gap
|
||||
if let DiscreteBoundOrd::Included(outer_range_start) = outer_range.start() {
|
||||
start_gap.start = DiscreteBound::Included(outer_range_start);
|
||||
}
|
||||
if let DiscreteBoundOrd::Included(outer_range_end) = outer_range.end() {
|
||||
start_gap.end = DiscreteBound::Included(outer_range_end);
|
||||
}
|
||||
|
||||
return artificials
|
||||
(Some(start_gap), None)
|
||||
} else {
|
||||
//it's different gaps
|
||||
//
|
||||
//trim the start gap to the outer range
|
||||
if let DiscreteBoundOrd::Included(outer_range_start) = outer_range.start() {
|
||||
start_gap.start = DiscreteBound::Included(outer_range_start);
|
||||
}
|
||||
//trim the end gap to the outer range
|
||||
if let DiscreteBoundOrd::Included(outer_range_end) = outer_range.end() {
|
||||
end_gap.end = DiscreteBound::Included(outer_range_end);
|
||||
}
|
||||
|
||||
(Some(start_gap), Some(end_gap))
|
||||
}
|
||||
}
|
||||
(Some(mut start_gap), None) => {
|
||||
//trim the start gap to the outer range
|
||||
if let DiscreteBoundOrd::Included(outer_range_start) = outer_range.start() {
|
||||
start_gap.start = DiscreteBound::Included(outer_range_start);
|
||||
}
|
||||
(Some(start_gap), None)
|
||||
}
|
||||
(None, Some(mut end_gap)) => {
|
||||
//trim the end gap to the outer range
|
||||
if let DiscreteBoundOrd::Included(outer_range_end) = outer_range.end() {
|
||||
end_gap.end = DiscreteBound::Included(outer_range_end);
|
||||
}
|
||||
(None, Some(end_gap))
|
||||
}
|
||||
(None, None) => (None, None),
|
||||
};
|
||||
|
||||
let inner_gaps = overlapping
|
||||
//optimisation find an implementation of windows()
|
||||
//somewhere that supports DoubleEndedIterator, I couldn't
|
||||
//find one at the time of writing
|
||||
@ -958,6 +853,12 @@ where
|
||||
//optimisation this would also then be unneccessary
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter();
|
||||
|
||||
//possibly add the trimmed start and end gaps
|
||||
return trimmed_start_gap
|
||||
.into_iter()
|
||||
.chain(inner_gaps)
|
||||
.chain(trimmed_end_gap.into_iter());
|
||||
}
|
||||
|
||||
/// Returns `true` if the map covers every point in the given
|
||||
@ -2055,6 +1956,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn gaps_tests() {
|
||||
eprintln!("hererererererer");
|
||||
assert_gaps(basic(), ii(50, 60), [ii(50, 60)]);
|
||||
assert_gaps(basic(), iu(50), [iu(50)]);
|
||||
assert_gaps(basic(), ee(3, 16), [ei(4, 5), ee(7, 14)]);
|
||||
@ -2065,6 +1967,12 @@ mod tests {
|
||||
assert_gaps(basic(), ii(6, 6), []);
|
||||
assert_gaps(basic(), ii(7, 7), []);
|
||||
assert_gaps(basic(), ii(8, 8), [ii(8, 8)]);
|
||||
|
||||
assert_gaps(
|
||||
basic(),
|
||||
ii(i8::MIN, i8::MAX),
|
||||
[ei(4, 5), ee(7, 14), ii(16, i8::MAX)],
|
||||
);
|
||||
}
|
||||
fn assert_gaps<const N: usize>(
|
||||
map: RangeBoundsMap<i8, DiscreteBounds<i8>, bool>,
|
||||
|
@ -1,5 +1,8 @@
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
|
||||
use crate::discrete_bounds::{DiscreteBound, DiscreteBounds};
|
||||
use crate::stepable::Stepable;
|
||||
use crate::{TryFromDiscreteBounds, TryFromDiscreteBoundsError};
|
||||
|
||||
pub fn uu() -> DiscreteBounds<i8> {
|
||||
DiscreteBounds {
|
||||
@ -52,3 +55,39 @@ pub fn ee(x1: i8, x2: i8) -> DiscreteBounds<i8> {
|
||||
end: DiscreteBound::Included(x2.down().unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct IEStrict {
|
||||
start: i8,
|
||||
end: i8,
|
||||
}
|
||||
|
||||
pub fn ie_strict(start: i8, end: i8) -> IEStrict {
|
||||
IEStrict { start, end }
|
||||
}
|
||||
|
||||
impl RangeBounds<i8> for IEStrict {
|
||||
fn start_bound(&self) -> std::ops::Bound<&i8> {
|
||||
Bound::Included(&self.start)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&i8> {
|
||||
Bound::Excluded(&self.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromDiscreteBounds<i8> for IEStrict {
|
||||
fn try_from_discrete_bounds(
|
||||
discrete_bounds: DiscreteBounds<i8>,
|
||||
) -> Result<Self, TryFromDiscreteBoundsError>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match (discrete_bounds.start, discrete_bounds.end) {
|
||||
(DiscreteBound::Included(start), DiscreteBound::Included(end)) => Ok(IEStrict {
|
||||
start,
|
||||
end: end.checked_add(1).ok_or(TryFromDiscreteBoundsError)?,
|
||||
}),
|
||||
_ => Err(TryFromDiscreteBoundsError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
use crate::{discrete_bounds::DiscreteBounds, TryFromDiscreteBoundsError};
|
||||
use crate::discrete_bounds::DiscreteBounds;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct TryFromDiscreteBoundsError;
|
||||
|
||||
pub trait TryFromDiscreteBounds<I> {
|
||||
fn try_from_discrete_bounds(
|
||||
|
Loading…
x
Reference in New Issue
Block a user