use crate::calc::*;
use crate::conv::*;
use crate::parts::*;
use crate::shorthands::aliases::*;
use crate::shorthands::*;
use crate::util::*;
use crate::*;
use core::borrow::Borrow;
use core::ops::{Add, RangeBounds, Sub};
pub(crate) fn flip<R, T>(range: &R) -> (Option<RangeUniv<T>>, Option<RangeUniv<T>>)
where
R: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
flip_adv(range, CursorMode::Off)
}
pub(crate) fn flip_adv<R, T>(
range: &R,
mode: CursorMode,
) -> (Option<RangeUniv<T>>, Option<RangeUniv<T>>)
where
R: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
let range = &rv::new(range);
if range.is_broken() {
return (Some(RangeUniv::new(Ub, Ub)), None);
}
if range.is_cursor() {
return if mode == CursorMode::Off {
(Some(RangeUniv::new(Ub, Ub)), None)
} else {
let pos = range.cursor().unwrap();
let face = if range.is_cursor_fwd() { Ex } else { In }(pos.clone());
let back = if range.is_cursor_fwd() { In } else { Ex }(pos.clone());
let fst = Some(RangeUniv::new(Ub, face));
let snd = Some(RangeUniv::new(back, Ub));
(fst, snd)
};
}
let (s, e) = (bound(range.start_bound()), bound(range.end_bound()));
let xs = s.toggle_included().cloned();
let xe = e.toggle_included().cloned();
match (&xs, &xe) {
(Ub, Ub) => (None, None),
(_, Ub) => (Some(RangeUniv::new(Ub, xs)), None),
(Ub, _) => (Some(RangeUniv::new(xe, Ub)), None),
(_, _) => (Some(RangeUniv::new(Ub, xs)), Some(RangeUniv::new(xe, Ub))),
}
}
pub(crate) fn shl<R, T>(range: &R, value: impl Borrow<T>) -> R::Range<T>
where
R: ?Sized + RangeSrc<T>,
for<'a> &'a T: Sub<&'a T, Output = T>,
{
let s = range.start_bound().map(|x| x - value.borrow());
let e = range.end_bound().map(|x| x - value.borrow());
<R as RangeSrc<T>>::new((s, e)).unwrap()
}
pub(crate) fn shr<R, T>(range: &R, value: impl Borrow<T>) -> R::Range<T>
where
R: ?Sized + RangeSrc<T>,
for<'a> &'a T: Add<&'a T, Output = T>,
{
let s = range.start_bound().map(|x| x + value.borrow());
let e = range.end_bound().map(|x| x + value.borrow());
<R as RangeSrc<T>>::new((s, e)).unwrap()
}
pub(crate) fn add_start<R, T>(range: &R, value: impl Borrow<T>) -> R::Range<T>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: Add<&'a T, Output = T>,
{
let s = range.start_bound().map(|x| x + value.borrow());
let e = range.end_bound().cloned();
<R as RangeSrc<T>>::new((s, e)).unwrap()
}
pub(crate) fn add_end<R, T>(range: &R, value: impl Borrow<T>) -> R::Range<T>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: Add<&'a T, Output = T>,
{
let s = range.start_bound().cloned();
let e = range.end_bound().map(|x| x + value.borrow());
<R as RangeSrc<T>>::new((s, e)).unwrap()
}
pub(crate) fn sub_start<R, T>(range: &R, value: impl Borrow<T>) -> R::Range<T>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: Sub<&'a T, Output = T>,
{
let s = range.start_bound().map(|x| x - value.borrow());
let e = range.end_bound().cloned();
<R as RangeSrc<T>>::new((s, e)).unwrap()
}
pub(crate) fn sub_end<R, T>(range: &R, value: impl Borrow<T>) -> R::Range<T>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: Sub<&'a T, Output = T>,
{
let s = range.start_bound().cloned();
let e = range.end_bound().map(|x| x - value.borrow());
<R as RangeSrc<T>>::new((s, e)).unwrap()
}
pub(crate) fn calc_start<R, T>(range: &R, width: impl Borrow<T>) -> R::Range<T>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: Sub<&'a T, Output = T>,
{
assert!(!matches!(range.start_bound(), Ub), "{}", msg::EXIST_SB);
assert!(!matches!(range.end_bound(), Ub), "{}", msg::EXIST_EB);
let (sb, eb) = (range.start_bound(), range.end_bound());
let sp = bound(eb).pos().unwrap().sub(width.borrow());
let ret = (sb.map(|_| sp), eb.cloned());
<R as RangeSrc<T>>::new(ret).unwrap()
}
pub(crate) fn calc_end<R, T>(range: &R, width: impl Borrow<T>) -> R::Range<T>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: Add<&'a T, Output = T>,
{
assert!(!matches!(range.start_bound(), Ub), "{}", msg::EXIST_SB);
assert!(!matches!(range.end_bound(), Ub), "{}", msg::EXIST_EB);
let (sb, eb) = (range.start_bound(), range.end_bound());
let ep = bound(sb).pos().unwrap().add(width.borrow());
let ret = (sb.cloned(), eb.map(|_| ep));
<R as RangeSrc<T>>::new(ret).unwrap()
}
pub(crate) fn align_start<R, T>(range: &R, value: impl Borrow<T>) -> Result<R::Range<T>, Error>
where
R: ?Sized + RangeSrc<T>,
T: Clone + PartialOrd,
for<'a> &'a T: CheckedAdd<&'a T, Output = T>,
for<'a> &'a T: CheckedSub<&'a T, Output = T>,
{
let range = &rv::new(range);
let value = value.borrow();
let [sb, eb] = <[_; _]>::from(range.bounds()).map(bound);
let Some(sp) = sb.pos() else {
return Err(Error::StartUnbounded);
};
let Some(ep) = eb.pos() else {
return Ok(<R as RangeSrc<T>>::new((sb.map(|_| value).cloned(), Ub))?);
};
if !util::is_ordered(&[Some(value), sb.pos(), eb.pos()]) {
return Err(Error::Unorderd);
}
if let Some(offset) = Signed::checked_distance(sp, value) {
let s = sb.map(|_| value).cloned();
let e = eb.try_map(|x| Signed::checked_add(x, &offset));
return Ok(<R as RangeSrc<T>>::new((s, e.ok_or(Error::Overflow)?))?);
}
if let Some(width) = Signed::checked_distance(sp, ep) {
let s = sb.map(|_| value).cloned();
let e = eb.try_map(|_| Signed::checked_add(value, &width));
return Ok(<R as RangeSrc<T>>::new((s, e.ok_or(Error::Overflow)?))?);
}
Err(Error::Overflow)
}
pub(crate) fn align_end<R, T>(range: &R, value: impl Borrow<T>) -> Result<R::Range<T>, Error>
where
R: ?Sized + RangeSrc<T>,
T: Clone + PartialOrd,
for<'a> &'a T: CheckedAdd<&'a T, Output = T>,
for<'a> &'a T: CheckedSub<&'a T, Output = T>,
{
let range = &rv::new(range);
let value = value.borrow();
let [sb, eb] = <[_; _]>::from(range.bounds()).map(bound);
let Some(ep) = eb.pos() else {
return Err(Error::EndUnbounded);
};
let Some(sp) = sb.pos() else {
return Ok(<R as RangeSrc<T>>::new((Ub, eb.map(|_| value).cloned()))?);
};
if !util::is_ordered(&[Some(value), sb.pos(), eb.pos()]) {
return Err(Error::Unorderd);
}
if let Some(offset) = Signed::checked_distance(ep, value) {
let s = sb.try_map(|x| Signed::checked_add(x, &offset));
let e = eb.map(|_| value).cloned();
return Ok(<R as RangeSrc<T>>::new((s.ok_or(Error::Overflow)?, e))?);
}
if let Some(width) = Signed::checked_distance(sp, ep) {
let s = sb.try_map(|_| Signed::checked_sub(value, &width));
let e = eb.map(|_| value).cloned();
return Ok(<R as RangeSrc<T>>::new((s.ok_or(Error::Overflow)?, e))?);
}
Err(Error::Overflow)
}
pub(crate) fn checked_shl<R, T>(range: &R, value: impl Borrow<T>) -> Option<R::Range<T>>
where
R: ?Sized + RangeSrc<T>,
for<'a> &'a T: CheckedSub<&'a T, Output = T>,
{
let (s, e) = (range.start_bound(), range.end_bound());
let s = bound(s).try_map(|x| CheckedSub::checked_sub(x, value.borrow()))?;
let e = bound(e).try_map(|x| CheckedSub::checked_sub(x, value.borrow()))?;
Some(<R as RangeSrc<T>>::new((s, e)).unwrap())
}
pub(crate) fn checked_shr<R, T>(range: &R, value: impl Borrow<T>) -> Option<R::Range<T>>
where
R: ?Sized + RangeSrc<T>,
for<'a> &'a T: CheckedAdd<&'a T, Output = T>,
{
let (s, e) = (range.start_bound(), range.end_bound());
let s = bound(s).try_map(|x| CheckedAdd::checked_add(x, value.borrow()))?;
let e = bound(e).try_map(|x| CheckedAdd::checked_add(x, value.borrow()))?;
Some(<R as RangeSrc<T>>::new((s, e)).unwrap())
}
pub(crate) fn checked_add_start<R, T>(range: &R, value: impl Borrow<T>) -> Option<R::Range<T>>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: CheckedAdd<&'a T, Output = T>,
{
let (s, e) = (range.start_bound(), range.end_bound());
let s = bound(s).try_map(|x| CheckedAdd::checked_add(x, value.borrow()))?;
Some(<R as RangeSrc<T>>::new((s, e.cloned())).unwrap())
}
pub(crate) fn checked_add_end<R, T>(range: &R, value: impl Borrow<T>) -> Option<R::Range<T>>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: CheckedAdd<&'a T, Output = T>,
{
let (s, e) = (range.start_bound(), range.end_bound());
let e = bound(e).try_map(|x| CheckedAdd::checked_add(x, value.borrow()))?;
Some(<R as RangeSrc<T>>::new((s.cloned(), e)).unwrap())
}
pub(crate) fn checked_sub_start<R, T>(range: &R, value: impl Borrow<T>) -> Option<R::Range<T>>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: CheckedSub<&'a T, Output = T>,
{
let (s, e) = (range.start_bound(), range.end_bound());
let s = bound(s).try_map(|x| CheckedSub::checked_sub(x, value.borrow()))?;
Some(<R as RangeSrc<T>>::new((s, e.cloned())).unwrap())
}
pub(crate) fn checked_sub_end<R, T>(range: &R, value: impl Borrow<T>) -> Option<R::Range<T>>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: CheckedSub<&'a T, Output = T>,
{
let (s, e) = (range.start_bound(), range.end_bound());
let e = bound(e).try_map(|x| CheckedSub::checked_sub(x, value.borrow()))?;
Some(<R as RangeSrc<T>>::new((s.cloned(), e)).unwrap())
}
pub(crate) fn checked_calc_start<R, T>(range: &R, width: impl Borrow<T>) -> Option<R::Range<T>>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: CheckedSub<&'a T, Output = T>,
{
assert!(!matches!(range.start_bound(), Ub), "{}", msg::EXIST_SB);
assert!(!matches!(range.end_bound(), Ub), "{}", msg::EXIST_EB);
let (sb, eb) = (range.start_bound(), range.end_bound());
let sp = bound(eb).pos().unwrap().checked_sub(width.borrow())?;
let ret = (sb.map(|_| sp), eb.cloned());
Some(<R as RangeSrc<T>>::new(ret).unwrap())
}
pub(crate) fn checked_calc_end<R, T>(range: &R, width: impl Borrow<T>) -> Option<R::Range<T>>
where
R: ?Sized + RangeSrc<T>,
T: Clone,
for<'a> &'a T: CheckedAdd<&'a T, Output = T>,
{
assert!(!matches!(range.start_bound(), Ub), "{}", msg::EXIST_SB);
assert!(!matches!(range.end_bound(), Ub), "{}", msg::EXIST_EB);
let (sb, eb) = (range.start_bound(), range.end_bound());
let ep = bound(sb).pos().unwrap().checked_add(width.borrow())?;
let ret = (sb.cloned(), eb.map(|_| ep));
Some(<R as RangeSrc<T>>::new(ret).unwrap())
}
pub(crate) fn cut<R, T>(
range: &R,
pos: &T,
mode: CutMode,
) -> (Option<RangeUniv<T>>, Option<RangeUniv<T>>)
where
R: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
let range = &rv::new(range);
if range.is_broken() {
return (None, None);
}
if bound(range.start_bound()).pos().is_some_and(|s| pos <= s) {
return (None, Some(range.to_univ()));
}
if bound(range.end_bound()).pos().is_some_and(|e| e <= pos) {
return (Some(range.to_univ()), None);
}
let fst_stt = range.start_bound().cloned();
let fst_end = mode.for_end(pos.clone());
let snd_stt = mode.for_start(pos.clone());
let snd_end = range.end_bound().cloned();
let fst = RangeUniv::new(fst_stt, fst_end);
let snd = RangeUniv::new(snd_stt, snd_end);
(Some(fst), Some(snd))
}
pub(crate) fn interval<RX, RY, T>(rx: &RX, ry: &RY) -> Option<RangeUniv<T>>
where
RX: ?Sized + RangeBounds<T>,
RY: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
debug_assert!(calc::is_mixable(rx, ry));
interval_adv(rx, ry, CursorMode::Off)
}
pub(crate) fn interval_adv<RX, RY, T>(rx: &RX, ry: &RY, mode: CursorMode) -> Option<RangeUniv<T>>
where
RX: ?Sized + RangeBounds<T>,
RY: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
debug_assert!(calc::is_mixable(rx, ry));
let (rx, ry) = (&rv::new(rx), &rv::new(ry));
let (bx, by) = (rx.bounds(), ry.bounds());
if rx.is_full() || ry.is_full() {
return None;
}
let ord = calc::cmp(rx, ry)?;
let fst = if ord.is_le() { bx } else { by };
let snd = if ord.is_le() { by } else { bx };
let s = bound(fst.1.cloned()).toggle_included();
let e = bound(snd.0.cloned()).toggle_included();
mode.proc(RangeUniv::new(s, e))
}
pub(crate) fn prod<RX, RY, T>(rx: &RX, ry: &RY) -> Option<RangeUniv<T>>
where
RX: ?Sized + RangeBounds<T>,
RY: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
debug_assert!(calc::is_mixable(rx, ry));
let (rx, ry) = (&rv::new(rx), &rv::new(ry));
let (ex, ey) = (rx.edges(), ry.edges());
if !rx.intersects(ry) {
return None;
}
if let (Some(x), Some(y)) = (rx.cursor(), ry.cursor()) {
let rx_win = rx.is_cursor_fwd() || ry.is_cursor_bwd();
let (rx, ry) = (rx.to_univ(), ry.to_univ());
return x.eq(y).then_some(if rx_win { rx } else { ry });
}
let s = MixMode::Normal.max_bound(ex.0, ey.0).cloned();
let e = MixMode::Normal.min_bound(ex.1, ey.1).cloned();
Some(RangeUniv::new(s, e))
}
pub(crate) fn enwrap<RX, RY, T>(rx: &RX, ry: &RY) -> Option<RangeUniv<T>>
where
RX: ?Sized + RangeBounds<T>,
RY: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
debug_assert!(calc::is_mixable(rx, ry));
let (rx, ry) = (&rv::new(rx), &rv::new(ry));
let (ex, ey) = (rx.edges(), ry.edges());
if rx.is_empty() && ry.is_empty() {
return None;
} else if rx.is_empty() {
return Some(ry.to_univ());
} else if ry.is_empty() {
return Some(rx.to_univ());
}
let s = MixMode::Normal.min_bound(ex.0, ey.0).cloned();
let e = MixMode::Normal.max_bound(ex.1, ey.1).cloned();
Some(RangeUniv::new(s, e))
}
pub(crate) fn union<RX, RY, T>(rx: &RX, ry: &RY) -> (RangeUniv<T>, Option<RangeUniv<T>>)
where
RX: ?Sized + RangeBounds<T>,
RY: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
debug_assert!(calc::is_mixable(rx, ry));
let (rx, ry) = (&rv::new(rx), &rv::new(ry));
let (ex, ey) = (rx.edges(), ry.edges());
if rx.is_broken() || ry.is_broken() {
let (rx, ry) = (rx.to_univ(), ry.to_univ());
return (rx, Some(ry));
}
if rx.is_cursor() && rx.cursor() == ry.cursor() {
let (rx, ry) = (rx.to_univ(), ry.to_univ());
let rx_win = rx.is_cursor_fwd() || ry.is_cursor_bwd();
return (if rx_win { rx } else { ry }, None);
}
if rx.intersects(ry) || rx.touches(ry) {
let s = MixMode::Union.min_bound(ex.0, ey.0).cloned();
let e = MixMode::Union.max_bound(ex.1, ey.1).cloned();
let ret = RangeUniv::new(s, e);
(ret, None)
} else {
let (rx, ry) = (rx.to_univ(), ry.to_univ());
let rx_win = ex.0 <= ey.0;
let pair = util::swap_if(!rx_win, (rx, ry));
(pair.0, Some(pair.1))
}
}
pub(crate) fn diff<RX, RY, T>(rx: &RX, ry: &RY) -> (Option<RangeUniv<T>>, Option<RangeUniv<T>>)
where
RX: ?Sized + RangeBounds<T>,
RY: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
debug_assert!(calc::is_mixable(rx, ry));
diff_adv(rx, ry, CursorMode::Off)
}
pub(crate) fn diff_adv<RX, RY, T>(
rx: &RX,
ry: &RY,
mode: CursorMode,
) -> (Option<RangeUniv<T>>, Option<RangeUniv<T>>)
where
RX: ?Sized + RangeBounds<T>,
RY: ?Sized + RangeBounds<T>,
T: Clone + PartialOrd,
{
debug_assert!(calc::is_mixable(rx, ry));
let (rx, ry) = (&rv::new(rx), &rv::new(ry));
let (ex, ey) = (rx.edges(), ry.edges());
if mode == CursorMode::Off && ry.is_cursor() {
return (Some(rx.to_univ()), None);
}
if !rx.intersects(ry) {
return (Some(rx.to_univ()), None);
}
if rx.cursor().is_some() && rx.cursor() == ry.cursor() {
return (None, None);
}
if ry.cursor().is_some_and(|x| rx.at_edge(x)) {
return (Some(rx.to_univ()), None);
}
let has_fst = !ex.0.is_contained(&ry.bounds());
let has_snd = !ex.1.is_contained(&ry.bounds());
let fst_end = MixMode::Diff.min_bound(ex.1, ey.0);
let snd_stt = MixMode::Diff.max_bound(ex.0, ey.1);
let fst = RangeUniv::new(rx.start_bound().cloned(), fst_end.cloned());
let snd = RangeUniv::new(snd_stt.cloned(), rx.end_bound().cloned());
let fst = (has_fst && !rv::new(&fst).is_broken()).then_some(fst);
let snd = (has_snd && !rv::new(&snd).is_broken()).then_some(snd);
match (&fst, &snd) {
(None, None) => (None, None),
(Some(_), None) => (fst, None),
(None, Some(_)) => (snd, None),
(Some(_), Some(_)) => (fst, snd),
}
}
pub(crate) fn closed_prod<R, T>(range: &R, value: &R) -> R
where
R: RangeSrc<T, Range<T> = R>,
T: Clone + PartialOrd + HasLimits,
{
self::prod(range, value)
.map_or_else(<R as RangeSrc<T>>::new_broken, <R as RangeSrc<T>>::new_from)
.unwrap()
}
pub(crate) fn closed_union<R, T>(range: &R, value: &R) -> R
where
R: RangeSrc<T, Range<T> = R>,
T: Clone + PartialOrd,
{
let unions = self::union(range, value);
let snd = unions.1.as_ref();
let snd = snd.is_some_and(|x| x.bounds() == rv::new(range).bounds());
let ret = if !snd { unions.0 } else { unions.1.unwrap() };
<R as RangeSrc<_>>::new_from(ret).unwrap()
}
pub(crate) fn closed_enwrap<R, T>(range: &R, value: &R) -> R
where
R: RangeSrc<T, Range<T> = R>,
T: Clone + PartialOrd + HasLimits,
{
self::enwrap(range, value)
.map_or_else(<R as RangeSrc<T>>::new_broken, <R as RangeSrc<T>>::new_from)
.unwrap()
}