1#[macro_use]
2extern crate derive_new;
3
4use std::cmp::Ordering;
5
6#[derive(new)]
10pub struct DualBoundedFunction<B, O> {
11 pub func: Box<dyn Fn(B) -> O>,
13 pub lower: B,
15 pub higher: B,
17}
18
19pub struct PartialFunction<B, O> {
25 funcs: Vec<DualBoundedFunction<B, O>>,
26}
27
28impl<B: PartialOrd, O> PartialFunction<B, O> {
29 pub fn builder() -> PartialFunctionBuilder<B, O> {
31 PartialFunctionBuilder::new()
32 }
33
34 pub fn eval(&self, x: B) -> Option<O> {
37 let iter = self.funcs.iter().enumerate();
38 for (i, bounded) in iter {
39 let next = self.funcs.get(i + 1);
40 if (x >= bounded.lower && x < bounded.higher)
41 || (next.is_none() && x == bounded.higher)
42 || (next.is_some() && next.unwrap().lower != bounded.higher)
43 {
44 let f = &bounded.func;
45 return Some(f(x));
46 }
47 }
48 None
49 }
50}
51
52#[derive(new, Default)]
54pub struct PartialFunctionBuilder<B, O> {
55 #[new(default)]
56 funcs: Vec<DualBoundedFunction<B, O>>,
57}
58
59impl<B: PartialOrd, O> PartialFunctionBuilder<B, O> {
60 pub fn with(mut self, lower: B, higher: B, func: Box<dyn Fn(B) -> O>) -> Self {
62 debug_assert!(self.can_insert(&lower, &higher));
63 let f = DualBoundedFunction {
64 func,
65 lower,
66 higher,
67 };
68 self.funcs.push(f);
69 self
70 }
71
72 pub fn can_insert(&self, lower: &B, higher: &B) -> bool {
74 !self.funcs.iter().any(|b| {
75 (lower >= &b.lower && lower < &b.higher)
76 || (higher > &b.lower && higher <= &b.higher)
77 || (lower <= &b.lower && higher >= &b.higher)
78 })
79 }
80
81 pub fn build(mut self) -> PartialFunction<B, O> {
83 self.funcs.sort_by(|a, b| {
84 a.lower
85 .partial_cmp(&b.lower)
86 .unwrap_or(a.higher.partial_cmp(&b.higher).unwrap_or(Ordering::Equal))
87 });
88 PartialFunction { funcs: self.funcs }
89 }
90}
91
92#[derive(new)]
94struct LowerBoundedFunction<B, O> {
95 pub func: Box<dyn Fn(B) -> O>,
97 pub lower: B,
99}
100
101#[derive(Default)]
112pub struct LowerPartialFunction<B, O>
113where
114 B: PartialOrd,
115{
116 funcs: Vec<LowerBoundedFunction<B, O>>,
117}
118
119impl<B, O> LowerPartialFunction<B, O>
120where
121 B: PartialOrd,
122{
123 pub fn builder() -> LowerPartialFunctionBuilder<B, O> {
125 LowerPartialFunctionBuilder::new()
126 }
127
128 pub fn eval(&self, x: B) -> Option<O> {
131 let iter = self.funcs.iter().enumerate();
132 for (i, bounded) in iter {
133 let next = self.funcs.get(i + 1);
134 if x >= bounded.lower && ((next.is_some() && next.unwrap().lower > x) || next.is_none())
135 {
136 let f = &bounded.func;
137 return Some(f(x));
138 }
139 }
140 None
141 }
142}
143
144#[derive(new, Default)]
146pub struct LowerPartialFunctionBuilder<B, O> {
147 #[new(default)]
148 funcs: Vec<LowerBoundedFunction<B, O>>,
149}
150
151impl<B: PartialOrd, O> LowerPartialFunctionBuilder<B, O> {
152 pub fn with(mut self, lower: B, func: Box<dyn Fn(B) -> O>) -> Self {
154 debug_assert!(self.can_insert(&lower));
155 let f = LowerBoundedFunction { func, lower };
156 self.funcs.push(f);
157 self
158 }
159
160 pub fn can_insert(&self, lower: &B) -> bool {
162 !self.funcs.iter().any(|b| lower == &b.lower)
163 }
164
165 pub fn build(mut self) -> LowerPartialFunction<B, O> {
167 self.funcs
168 .sort_by(|a, b| a.lower.partial_cmp(&b.lower).unwrap_or(Ordering::Equal));
169 LowerPartialFunction { funcs: self.funcs }
170 }
171}
172
173#[macro_export]
175macro_rules! partfn {
176 ( $( [$start:expr, $end:expr]: $var:ident -> $f:expr,)* ) => {
177 {
178 let mut func = PartialFunction::builder();
179 $( func = func.with($start, $end, Box::new(|$var| $f)); )*
180 func.build()
181 }
182 };
183}
184
185#[macro_export]
187macro_rules! lowpartfn {
188 ( $( [$bound:expr]: $var:ident -> $f:expr,)* ) => {
189 {
190 let mut func = LowerPartialFunction::builder();
191 $( func = func.with($bound, Box::new(|$var| $f)); )*
192 func.build()
193 }
194 };
195}