1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
use safecast::TryCastInto; use tc_error::*; use tc_value::{Number, NumberInstance, Value}; use tcgeneric::PathSegment; use crate::route::{GetHandler, Handler, Route}; use crate::state::State; struct Dual<F> { op: F, } impl<F> Dual<F> { fn new(op: F) -> Self { Self { op } } } impl<'a, F> Handler<'a> for Dual<F> where F: Fn(Number) -> Number + Send + 'a, { fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b>> where 'b: 'a, { Some(Box::new(|_txn, value| { Box::pin(async move { let value = value.try_cast_into(|v| TCError::bad_request("not a Number", v))?; Ok(State::from(Value::from((self.op)(value)))) }) })) } } struct Unary<F> { name: &'static str, op: F, } impl<F> Unary<F> { fn new(name: &'static str, op: F) -> Self { Self { name, op } } } impl<'a, F> Handler<'a> for Unary<F> where F: Fn() -> Number + Send + 'a, { fn get<'b>(self: Box<Self>) -> Option<GetHandler<'a, 'b>> where 'b: 'a, { Some(Box::new(|_txn, value| { Box::pin(async move { if value.is_some() { return Err(TCError::unsupported(format!( "{} does not have any parameters (found {})", self.name, value ))); } Ok(State::from(Value::from((self.op)()))) }) })) } } impl Route for Number { fn route<'a>(&'a self, path: &'a [PathSegment]) -> Option<Box<dyn Handler<'a> + 'a>> { if path.len() != 1 { return None; } let handler: Box<dyn Handler<'a> + 'a> = match path[0].as_str() { "abs" => Box::new(Unary::new("abs", move || self.abs())), "add" => Box::new(Dual::new(move |other| *self + other)), "div" => Box::new(Dual::new(move |other| *self / other)), "mul" => Box::new(Dual::new(move |other| *self * other)), "sub" => Box::new(Dual::new(move |other| *self - other)), "pow" => Box::new(Dual::new(move |other| self.pow(other))), "gt" => Box::new(Dual::new(move |other| (*self > other).into())), "gte" => Box::new(Dual::new(move |other| (*self >= other).into())), "lt" => Box::new(Dual::new(move |other| (*self < other).into())), "lte" => Box::new(Dual::new(move |other| (*self <= other).into())), _ => return None, }; Some(handler) } }