hayro_syntax/function/
mod.rs1mod type0;
7mod type2;
8mod type3;
9mod type4;
10
11use crate::function::type0::Type0;
12use crate::function::type2::Type2;
13use crate::function::type3::Type3;
14use crate::function::type4::Type4;
15use crate::object::Dict;
16use crate::object::dict::keys::{DOMAIN, FUNCTION_TYPE, RANGE};
17use crate::object::{Object, dict_or_stream};
18use log::warn;
19use smallvec::SmallVec;
20use std::sync::Arc;
21
22pub type Values = SmallVec<[f32; 4]>;
24type TupleVec = SmallVec<[(f32, f32); 4]>;
25
26#[derive(Debug)]
27enum FunctionType {
28 Type0(Type0),
29 Type2(Type2),
30 Type3(Type3),
31 Type4(Type4),
32}
33
34#[derive(Debug, Clone)]
36pub struct Function(Arc<FunctionType>);
37
38impl Function {
39 pub fn new(obj: &Object) -> Option<Function> {
41 let (dict, stream) = dict_or_stream(obj)?;
42
43 let function_type = match dict.get::<u8>(FUNCTION_TYPE)? {
44 0 => FunctionType::Type0(Type0::new(&stream?)?),
45 2 => FunctionType::Type2(Type2::new(&dict)?),
46 3 => FunctionType::Type3(Type3::new(&dict)?),
47 4 => FunctionType::Type4(Type4::new(&stream?)?),
48 _ => return None,
49 };
50
51 Some(Self(Arc::new(function_type)))
52 }
53
54 pub fn eval(&self, input: Values) -> Option<Values> {
56 match self.0.as_ref() {
57 FunctionType::Type0(t0) => t0.eval(input),
58 FunctionType::Type2(t2) => Some(t2.eval(*input.first()?)),
59 FunctionType::Type3(t3) => t3.eval(*input.first()?),
60 FunctionType::Type4(t4) => Some(t4.eval(input)?),
61 }
62 }
63}
64
65#[derive(Debug, Clone)]
66struct Clamper {
67 domain: TupleVec,
68 range: Option<TupleVec>,
69}
70
71impl Clamper {
72 fn new(dict: &Dict) -> Option<Self> {
73 let domain = dict.get::<TupleVec>(DOMAIN)?;
74 let range = dict.get::<TupleVec>(RANGE);
75
76 Some(Self { domain, range })
77 }
78
79 fn clamp_input(&self, input: &mut [f32]) {
80 if input.len() != self.domain.len() {
81 warn!("the domain of the function didn't match the input arguments");
82 }
83
84 for ((min, max), val) in self.domain.iter().zip(input.iter_mut()) {
85 *val = val.clamp(*min, *max);
86 }
87 }
88
89 fn clamp_output(&self, output: &mut [f32]) {
90 if let Some(range) = &self.range {
91 if range.len() != output.len() {
92 warn!("the range of the function didn't match the output arguments");
93 }
94
95 for ((min, max), val) in range.iter().zip(output.iter_mut()) {
96 *val = val.clamp(*min, *max);
97 }
98 }
99 }
100}
101
102pub fn interpolate(x: f32, x_min: f32, x_max: f32, y_min: f32, y_max: f32) -> f32 {
105 y_min + (x - x_min) * (y_max - y_min) / (x_max - x_min)
106}