odsek 0.1.0

Lazy, pull-based composition of mathematical interval sets with open/closed endpoints, no_std-compatible.
Documentation
use core::cmp::Ordering;

use crate::interval::*;
use crate::intervals::*;
use crate::IntervalsCache;

#[cfg(feature = "operators")]
use crate::IntervalsEndpointMap;
#[cfg(feature = "operators")]
use crate::IntervalsFromArray;
#[cfg(feature = "operators")]
use crate::IntervalsMap;
#[cfg(feature = "operators")]
use crate::IntervalsSingle;
#[cfg(feature = "operators")]
use core::ops::BitOr;

/// Union of two [`Intervals`] streams.
///
/// If the inputs are `Intervals<Endpoint = E, Value = A>` and
/// `Intervals<Endpoint = E, Value = B>`, the result is
/// `Intervals<Endpoint = E, Value = (Option<A>, Option<B>)>` — each output
/// interval covers a region present in at least one input, and the value
/// tuple records which input(s) contributed.
///
/// Usually constructed via the [`or`] free function or the `|` operator
/// (with the `operators` feature). Use [`or_cached`] when the inputs may be
/// queried multiple times per output.
pub struct IntervalsOr<Ia, Ib> {
    i_a: Ia,
    i_b: Ib,
}

impl<Ia, Ib> IntervalsOr<Ia, Ib> {
    /// Build a union stream from two inputs that share the same `Endpoint`.
    pub fn new(i_a: Ia, i_b: Ib) -> Self {
        Self { i_a, i_b }
    }
}

impl<Ia, Ib, E> Intervals for IntervalsOr<Ia, Ib>
where
    Ia: Intervals<Endpoint = E>,
    Ib: Intervals<Endpoint = E>,
    E: Clone + EndpointToggle,
    LeftT<E>: Ord,
    RightT<E>: Ord,
    Ia::Value: Copy,
    Ib::Value: Copy,
{
    type Endpoint = E;
    type Value = (Option<Ia::Value>, Option<Ib::Value>);

    fn head(&mut self, pos: Option<LeftT<Self::Endpoint>>) -> Option<Interval<E, Self::Value>> {
        let i_a = self.i_a.head(pos.clone());
        let i_b = self.i_b.head(pos.clone());
        // one is none
        if i_a.is_none() {
            return i_b.map(|v| {
                let left = match pos {
                    None => v.left().clone(),
                    Some(p) => v.left().max(p),
                };
                Interval::new_lr(left, v.right(), (None, Some(v.value())))
            });
        }
        if i_b.is_none() {
            return i_a.map(|v| {
                let left = match pos {
                    None => v.left().clone(),
                    Some(p) => v.left().max(p),
                };
                Interval::new_lr(left, v.right(), (Some(v.value()), None))
            });
        }

        let a = i_a.unwrap();
        let a1 = match pos.clone() {
            Some(p) => a.left().max(p),
            None => a.left(),
        };

        let b = i_b.unwrap();
        let b1 = match pos {
            Some(p) => b.left().max(p),
            None => b.left(),
        };

        use Ordering::*;

        let r = match a1.partial_cmp(&b1).unwrap() {
            Less => {
                let right = a.right().min(b1.into_right());
                Interval::new_lr(a1, right, (Some(a.value()), None))
            }
            Greater => {
                let right: RightT<E> = b.right().min(a1.into_right());
                Interval::new_lr(b1, right, (None, Some(b.value())))
            }
            Equal => {
                let c = a.right().min(b.right());
                Interval::new_lr(a1, c, (Some(a.value()), Some(b.value())))
            }
        };
        Some(r)
    }
}

/// Compose two [`Intervals`] into their union.
///
/// Both inputs must share the same `Endpoint` type. Equivalent to `a | b`
/// when the `operators` feature is enabled.
pub fn or<Ia, Ib>(a: Ia, b: Ib) -> IntervalsWrap<IntervalsOr<Ia, Ib>> {
    let ior = IntervalsOr::new(a, b);
    IntervalsWrap::new(ior)
}

/// Like [`or`], but wraps the result in an [`IntervalsCache`].
///
/// Use when the resulting stream will be queried multiple times at the same
/// or adjacent positions.
pub fn or_cached<Ia, Ib>(a: Ia, b: Ib) -> IntervalsCache<IntervalsOr<Ia, Ib>>
where
    IntervalsOr<Ia, Ib>: Intervals,
{
    let io = IntervalsOr::new(a, b);
    IntervalsCache::new(io)
}

#[cfg(feature = "operators")]
impl<I, Rhs> BitOr<Rhs> for IntervalsWrap<I>
where
    IntervalsOr<Self, Rhs>: Intervals,
{
    type Output = IntervalsWrap<IntervalsOr<Self, Rhs>>;
    fn bitor(self, c: Rhs) -> Self::Output {
        or(self, c)
    }
}

#[cfg(feature = "operators")]
impl<T, V, Ic> BitOr<Ic> for IntervalsSingle<T, V> {
    type Output = IntervalsWrap<IntervalsOr<Self, Ic>>;
    fn bitor(self, c: Ic) -> Self::Output {
        or(self, c)
    }
}

#[cfg(feature = "operators")]
impl<'a, E, V, Rhs> BitOr<Rhs> for IntervalsFromArray<'a, E, V>
where
    Self: Intervals,
    Rhs: Intervals<Endpoint = <Self as Intervals>::Endpoint>,
{
    type Output = IntervalsWrap<IntervalsOr<Self, Rhs>>;
    fn bitor(self, c: Rhs) -> Self::Output {
        or(self, c)
    }
}

#[cfg(feature = "operators")]
impl<It, F, Ic> BitOr<Ic> for IntervalsMap<It, F> {
    type Output = IntervalsWrap<IntervalsOr<Self, Ic>>;
    fn bitor(self, c: Ic) -> Self::Output {
        or(self, c)
    }
}

#[cfg(feature = "operators")]
impl<It, F, G, Tin, Tout, Ic> BitOr<Ic> for IntervalsEndpointMap<It, F, G, Tin, Tout> {
    type Output = IntervalsWrap<IntervalsOr<Self, Ic>>;
    fn bitor(self, c: Ic) -> Self::Output {
        or(self, c)
    }
}

#[cfg(feature = "operators")]
impl<It, Rhs> BitOr<Rhs> for IntervalsCache<It>
where
    It: Intervals,
    IntervalsOr<Self, Rhs>: Intervals,
{
    type Output = IntervalsCache<IntervalsOr<Self, Rhs>>;
    fn bitor(self, c: Rhs) -> Self::Output {
        or_cached(self, c)
    }
}