#[macro_use]
extern crate derive_new;
use std::cmp::Ordering;
#[derive(new)]
pub struct DualBoundedFunction<B, O> {
pub func: Box<dyn Fn(B) -> O>,
pub lower: B,
pub higher: B,
}
pub struct PartialFunction<B, O> {
funcs: Vec<DualBoundedFunction<B, O>>,
}
impl<B: PartialOrd, O> PartialFunction<B, O> {
pub fn builder() -> PartialFunctionBuilder<B, O> {
PartialFunctionBuilder::new()
}
pub fn eval(&self, x: B) -> Option<O> {
let iter = self.funcs.iter().enumerate();
for (i, bounded) in iter {
let next = self.funcs.get(i + 1);
if (x >= bounded.lower && x < bounded.higher)
|| (next.is_none() && x == bounded.higher)
|| (next.is_some() && next.unwrap().lower != bounded.higher)
{
let f = &bounded.func;
return Some(f(x));
}
}
None
}
}
#[derive(new, Default)]
pub struct PartialFunctionBuilder<B, O> {
#[new(default)]
funcs: Vec<DualBoundedFunction<B, O>>,
}
impl<B: PartialOrd, O> PartialFunctionBuilder<B, O> {
pub fn with(mut self, lower: B, higher: B, func: Box<dyn Fn(B) -> O>) -> Self {
debug_assert!(self.can_insert(&lower, &higher));
let f = DualBoundedFunction {
func,
lower,
higher,
};
self.funcs.push(f);
self
}
pub fn can_insert(&self, lower: &B, higher: &B) -> bool {
!self.funcs.iter().any(|b| {
(lower >= &b.lower && lower < &b.higher)
|| (higher > &b.lower && higher <= &b.higher)
|| (lower <= &b.lower && higher >= &b.higher)
})
}
pub fn build(mut self) -> PartialFunction<B, O> {
self.funcs.sort_by(|a, b| {
a.lower
.partial_cmp(&b.lower)
.unwrap_or(a.higher.partial_cmp(&b.higher).unwrap_or(Ordering::Equal))
});
PartialFunction { funcs: self.funcs }
}
}
#[derive(new)]
struct LowerBoundedFunction<B, O> {
pub func: Box<dyn Fn(B) -> O>,
pub lower: B,
}
#[derive(Default)]
pub struct LowerPartialFunction<B, O>
where
B: PartialOrd,
{
funcs: Vec<LowerBoundedFunction<B, O>>,
}
impl<B, O> LowerPartialFunction<B, O>
where
B: PartialOrd,
{
pub fn builder() -> LowerPartialFunctionBuilder<B, O> {
LowerPartialFunctionBuilder::new()
}
pub fn eval(&self, x: B) -> Option<O> {
let iter = self.funcs.iter().enumerate();
for (i, bounded) in iter {
let next = self.funcs.get(i + 1);
if x >= bounded.lower && ((next.is_some() && next.unwrap().lower > x) || next.is_none())
{
let f = &bounded.func;
return Some(f(x));
}
}
None
}
}
#[derive(new, Default)]
pub struct LowerPartialFunctionBuilder<B, O> {
#[new(default)]
funcs: Vec<LowerBoundedFunction<B, O>>,
}
impl<B: PartialOrd, O> LowerPartialFunctionBuilder<B, O> {
pub fn with(mut self, lower: B, func: Box<dyn Fn(B) -> O>) -> Self {
debug_assert!(self.can_insert(&lower));
let f = LowerBoundedFunction { func, lower };
self.funcs.push(f);
self
}
pub fn can_insert(&self, lower: &B) -> bool {
!self.funcs.iter().any(|b| lower == &b.lower)
}
pub fn build(mut self) -> LowerPartialFunction<B, O> {
self.funcs
.sort_by(|a, b| a.lower.partial_cmp(&b.lower).unwrap_or(Ordering::Equal));
LowerPartialFunction { funcs: self.funcs }
}
}
#[macro_export]
macro_rules! partfn {
( $( [$start:expr, $end:expr]: $var:ident -> $f:expr,)* ) => {
{
let mut func = PartialFunction::builder();
$( func = func.with($start, $end, Box::new(|$var| $f)); )*
func.build()
}
};
}
#[macro_export]
macro_rules! lowpartfn {
( $( [$bound:expr]: $var:ident -> $f:expr,)* ) => {
{
let mut func = LowerPartialFunction::builder();
$( func = func.with($bound, Box::new(|$var| $f)); )*
func.build()
}
};
}