use core::marker::PhantomData;
use crate::interval::*;
use crate::intervals::*;
pub struct IntervalsEndpointMap<It, F, G, Tin, Tout> {
it: It,
forward: F,
inverse: G,
_phantom: PhantomData<(Tin, Tout)>,
}
impl<It, F, G, Tin, Tout> IntervalsEndpointMap<It, F, G, Tin, Tout>
where
F: Fn(Tin) -> Tout,
G: Fn(Tout) -> Tin,
{
pub fn new(it: It, forward: F, inverse: G) -> Self {
IntervalsEndpointMap {
it,
forward,
inverse,
_phantom: PhantomData,
}
}
}
impl<It, F, G, Tin, Tout> Intervals for IntervalsEndpointMap<It, F, G, Tin, Tout>
where
It: Intervals,
It::Endpoint: EndpointMapInto<Tout, EndpointValue = Tin> + Clone,
<It::Endpoint as EndpointMapInto<Tout>>::Output:
EndpointMapInto<Tin, EndpointValue = Tout, Output = It::Endpoint>,
F: Fn(Tin) -> Tout,
G: Fn(Tout) -> Tin,
It::Value: Copy,
{
type Endpoint = <It::Endpoint as EndpointMapInto<Tout>>::Output;
type Value = It::Value;
fn head(
&mut self,
pos: Option<LeftT<Self::Endpoint>>,
) -> Option<Interval<Self::Endpoint, Self::Value>> {
let p_in: Option<LeftT<It::Endpoint>> =
pos.map(|e| e.map_endpoint_into(|v| (self.inverse)(v)));
let r = self.it.head(p_in);
r.map(|it| {
let a = it.left().map_endpoint_into(|v| (self.forward)(v));
let b = it.right().map_endpoint_into(|v| (self.forward)(v));
let val = it.value();
Interval::new_lr(a, b, val)
})
}
}
pub trait InIntervalsMapEndpoints: Sized {
fn map_endpoints<F, G, Tin, Tout>(
self,
forward: F,
inverse: G,
) -> IntervalsEndpointMap<Self, F, G, Tin, Tout>
where
F: Fn(Tin) -> Tout,
G: Fn(Tout) -> Tin;
}
impl<I> InIntervalsMapEndpoints for I
where
I: Intervals + Sized,
{
fn map_endpoints<F, G, Tin, Tout>(
self,
forward: F,
inverse: G,
) -> IntervalsEndpointMap<Self, F, G, Tin, Tout>
where
F: Fn(Tin) -> Tout,
G: Fn(Tout) -> Tin,
{
IntervalsEndpointMap::new(self, forward, inverse)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{EndpointOC, EndpointSymmetric, IntervalsSingle};
#[test]
fn scale_same_type() {
let i = Interval::new(EndpointOC::Closed(1), EndpointOC::Open(4), ());
let is = IntervalsSingle::new(i);
let mut m = IntervalsEndpointMap::new(is, |x: i32| x * 3, |x: i32| x / 3);
let a = m.head(None);
let expected = Interval::new(EndpointOC::Closed(3), EndpointOC::Open(12), ());
assert_eq!(a, Some(expected));
let a = m.head(Some(LeftT::Left(EndpointOC::Closed(6))));
let expected = Interval::new(EndpointOC::Closed(6), EndpointOC::Open(12), ());
assert_eq!(a, Some(expected));
let a = m.head(Some(LeftT::Left(EndpointOC::Closed(12))));
assert_eq!(a, None);
}
#[test]
fn type_change_i32_to_i64() {
let i = Interval::new(EndpointOC::Closed(1_i32), EndpointOC::Open(4_i32), ());
let is = IntervalsSingle::new(i);
let mut m =
IntervalsEndpointMap::new(is, |x: i32| x as i64 * 1_000, |x: i64| (x / 1_000) as i32);
let a = m.head(None);
let expected = Interval::new(
EndpointOC::Closed(1_000_i64),
EndpointOC::Open(4_000_i64),
(),
);
assert_eq!(a, Some(expected));
}
#[test]
fn symmetric_endpoint() {
let i = Interval::new(EndpointSymmetric(2), EndpointSymmetric(5), "A");
let is = IntervalsSingle::new(i);
let mut m = IntervalsEndpointMap::new(is, |x: i32| x + 10, |x: i32| x - 10);
let a = m.head(None);
let expected = Interval::new(EndpointSymmetric(12), EndpointSymmetric(15), "A");
assert_eq!(a, Some(expected));
}
#[test]
fn builder_method() {
let i = Interval::new(EndpointOC::Closed(1), EndpointOC::Open(4), ());
let mut m = IntervalsSingle::new(i).map_endpoints(|x: i32| x + 5, |x: i32| x - 5);
let a = m.head(None);
let expected = Interval::new(EndpointOC::Closed(6), EndpointOC::Open(9), ());
assert_eq!(a, Some(expected));
}
}