odsek 0.1.0

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

use crate::ivs::endpoint_map::IntervalsEndpointMap;

/// Translate an [`Intervals`](crate::Intervals) stream by a constant offset.
///
/// `IntervalShift::new(intervals, offset)` returns a stream where every
/// endpoint has had `offset` added to it; queries are translated back through
/// subtraction. Internally this is just a specialization of
/// [`IntervalsEndpointMap`] with `+offset` / `-offset` as the forward / inverse.
pub struct IntervalShift;

impl IntervalShift {
    /// Build an offset-translated stream.
    ///
    /// `Ev` is the underlying endpoint value type and must support `+` and `-`.
    #[allow(clippy::new_ret_no_self)]
    pub fn new<Is, Ev>(
        intervals: Is,
        offset: Ev,
    ) -> IntervalsEndpointMap<Is, impl Fn(Ev) -> Ev + Clone, impl Fn(Ev) -> Ev + Clone, Ev, Ev>
    where
        Ev: Add<Output = Ev> + Sub<Output = Ev> + Clone,
    {
        let off_fwd = offset.clone();
        let off_inv = offset;
        IntervalsEndpointMap::new(
            intervals,
            move |v: Ev| v + off_fwd.clone(),
            move |v: Ev| v - off_inv.clone(),
        )
    }
}

#[cfg(test)]
mod tests {
    use crate::EndpointOC;
    use crate::Interval;
    use crate::IntervalShift;
    use crate::Intervals;
    use crate::IntervalsSingle;

    #[test]
    fn shift_test() {
        let i = Interval::new(EndpointOC::Closed(1), EndpointOC::Open(4), ());
        let is = IntervalsSingle::new(i);
        let mut ism = IntervalShift::new(is, 5);

        let a = ism.head(None);
        let expected = Interval::new(EndpointOC::Closed(6), EndpointOC::Open(9), ());
        assert!(a == Some(expected));

        let a = ism.head(Some(crate::LeftT::Left(EndpointOC::Closed(8))));
        let expected = Interval::new(EndpointOC::Closed(8), EndpointOC::Open(9), ());
        assert!(a == Some(expected));

        let a = ism.head(Some(crate::LeftT::Left(EndpointOC::Closed(9))));
        let expected = None;
        assert!(a == expected);
    }
}