odsek 0.1.0

Lazy, pull-based composition of mathematical interval sets with open/closed endpoints, no_std-compatible.
Documentation
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::BitAnd;

/// Intersection 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 = (A, B)>` — each output interval covers
/// the overlap and carries the pair of values from the two contributing
/// inputs.
///
/// Usually constructed via the [`and`] free function or the `&` operator
/// (with the `operators` feature). Use [`and_cached`] when the inputs are
/// expensive to query and may be hit multiple times.
///
/// ```
/// use odsek::*;
///
/// // [a, b] tagged v
/// fn cc<T>(a: i32, b: i32, v: T) -> Interval<EndpointOC<i32>, T> {
///   Interval::new(EndpointOC::Closed(a), EndpointOC::Closed(b), v)
/// }
/// // (a, b) tagged v
/// fn oo<T>(a: i32, b: i32, v: T) -> Interval<EndpointOC<i32>, T> {
///   Interval::new(EndpointOC::Open(a), EndpointOC::Open(b), v)
/// }
/// // (a, b] tagged v
/// fn oc<T>(a: i32, b: i32, v: T) -> Interval<EndpointOC<i32>, T> {
///   Interval::new(EndpointOC::Open(a), EndpointOC::Closed(b), v)
/// }
///
/// let ia = IntervalsSingle::new(cc(1, 3, "A"));
/// let ib = IntervalsSingle::new(oo(2, 4, "B"));
///
/// // (2, 3] tagged ("A", "B")
/// let result: Vec<_> = and(ia, ib).into_iter().collect();
/// assert_eq!(result, vec![oc(2, 3, ("A", "B"))]);
/// ```
pub struct IntervalsAnd<Ia, Ib> {
    i_a: Ia,
    i_b: Ib,
}

impl<Ia, Ib> IntervalsAnd<Ia, Ib> {
    /// Build an intersection 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 IntervalsAnd<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 = (Ia::Value, Ib::Value);

    fn head(&mut self, pos: Option<LeftT<Self::Endpoint>>) -> Option<Interval<E, Self::Value>> {
        let mut ha = self.i_a.head(pos.clone())?;
        let mut pos = match pos {
            None => ha.left(),
            Some(p) => ha.left().max(p),
        };
        let mut hb = self.i_b.head(Some(pos.clone()))?;
        pos = hb.left().max(pos.clone());
        loop {
            let mut ok = true;
            if pos >= ha.right().into_left() {
                ok = false;
                pos = hb.left().max(pos);
                ha = self.i_a.head(Some(pos.clone()))?;
            }
            if pos >= hb.right().into_left() {
                ok = false;
                pos = ha.left().max(pos);
                hb = self.i_b.head(Some(pos.clone()))?;
            }
            if ok {
                break;
            }
        }
        let e1 = ha.left().max(hb.left());
        let e2 = ha.right().min(hb.right());
        Some(Interval::new_lr(e1, e2, (ha.value(), hb.value())))
    }
}

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

/// Like [`and`], but wraps the result in an [`IntervalsCache`].
///
/// Use when the resulting stream will be queried multiple times at the same
/// or adjacent positions — for example, when the result feeds into another
/// `&` / `|` composition that will pull from it more than once per output.
pub fn and_cached<Ia, Ib>(a: Ia, b: Ib) -> IntervalsCache<IntervalsAnd<Ia, Ib>>
where
    IntervalsAnd<Ia, Ib>: Intervals,
{
    let io = IntervalsAnd::new(a, b);
    IntervalsCache::new(io)
}

#[cfg(feature = "operators")]
impl<I, Rhs> BitAnd<Rhs> for IntervalsWrap<I>
where
    IntervalsAnd<Self, Rhs>: Intervals,
    I: Intervals,
    Rhs: Intervals,
{
    type Output = IntervalsWrap<IntervalsAnd<Self, Rhs>>;
    fn bitand(self, c: Rhs) -> Self::Output {
        and(self, c)
    }
}

#[cfg(feature = "operators")]
impl<T, V, Ic> BitAnd<Ic> for IntervalsSingle<T, V>
where
    Self: Intervals,
    Ic: Intervals<Endpoint = <Self as Intervals>::Endpoint>,
{
    type Output = IntervalsWrap<IntervalsAnd<Self, Ic>>;
    fn bitand(self, c: Ic) -> Self::Output {
        and(self, c)
    }
}

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

#[cfg(feature = "operators")]
impl<It, V, Ic> BitAnd<Ic> for IntervalsMap<It, V>
where
    Self: Intervals,
    Ic: Intervals<Endpoint = <Self as Intervals>::Endpoint>,
{
    type Output = IntervalsWrap<IntervalsAnd<Self, Ic>>;
    fn bitand(self, c: Ic) -> Self::Output {
        and(self, c)
    }
}

#[cfg(feature = "operators")]
impl<It, F, G, Tin, Tout, Ic> BitAnd<Ic> for IntervalsEndpointMap<It, F, G, Tin, Tout>
where
    Self: Intervals,
    Ic: Intervals<Endpoint = <Self as Intervals>::Endpoint>,
{
    type Output = IntervalsWrap<IntervalsAnd<Self, Ic>>;
    fn bitand(self, c: Ic) -> Self::Output {
        and(self, c)
    }
}