1use std::fmt::Display;
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub enum Category {
5 General,
6 PowerLog,
7 Trigonometry,
8}
9
10impl Display for Category {
11 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12 match self {
13 Category::General => write!(f, "General"),
14 Category::PowerLog => write!(f, "Power and Logarithms"),
15 Category::Trigonometry => write!(f, "Trigonometry"),
16 }
17 }
18}
19
20#[derive(Debug, Clone, Copy)]
21pub enum ArgCount {
22 One,
23 Two,
24 Atleast(u32),
25}
26
27impl ArgCount {
28 pub fn check(&self, count: usize) -> bool {
29 match self {
30 ArgCount::One => count == 1,
31 ArgCount::Two => count == 2,
32 ArgCount::Atleast(n) => count >= *n as usize,
33 }
34 }
35}
36
37impl Display for ArgCount {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 match self {
40 ArgCount::One => write!(f, "one argument"),
42 ArgCount::Two => write!(f, "two arguments"),
43 ArgCount::Atleast(n) => {
44 write!(f, "at least {n} argument{}", if *n > 1 { "s" } else { "" })
45 }
46 }
47 }
48}
49
50#[derive(Debug, Clone)]
51pub enum Args {
52 One(f64),
53 Two(f64, f64),
54 Dyn(Vec<f64>),
55}
56
57impl Args {
58 pub fn first(&self) -> f64 {
59 match self {
60 Args::One(v) => *v,
61 Args::Two(v, _) => *v,
62 Args::Dyn(v) => v[0],
63 }
64 }
65
66 pub fn second(&self) -> f64 {
67 match self {
68 Args::One(..) => unreachable!("Not enough arguments"),
69 Args::Two(_, v) => *v,
70 Args::Dyn(v) => v[1],
71 }
72 }
73
74 pub fn all(&self) -> &[f64] {
75 match self {
76 Args::One(..) => unreachable!("No dynamic arguments"),
77 Args::Two(..) => unreachable!("No dynamic arguments"),
78 Args::Dyn(v) => v.as_slice(),
79 }
80 }
81}
82
83#[allow(dead_code)]
84#[derive(Debug, Clone)]
85pub struct Func {
86 pub category: Category,
87 pub name: String,
88 pub help: String,
89 pub arg_count: ArgCount,
90 pub eval: fn(Args) -> f64,
91}
92
93pub fn all_funcs() -> Vec<Func> {
94 vec![
95 Func {
96 category: Category::General,
97 name: "floor".to_string(),
98 help: "floor value to lower integer".to_string(),
99 arg_count: ArgCount::One,
100 eval: |args| args.first().floor(),
101 },
102 Func {
103 category: Category::General,
104 name: "round".to_string(),
105 help: "round value to nearest integer".to_string(),
106 arg_count: ArgCount::One,
107 eval: |args| args.first().round(),
108 },
109 Func {
110 category: Category::General,
111 name: "ceil".to_string(),
112 help: "ceil value to upper integer".to_string(),
113 arg_count: ArgCount::One,
114 eval: |args| args.first().ceil(),
115 },
116 Func {
117 category: Category::General,
118 name: "trunc".to_string(),
119 help: "truncate value to its integer part (round towards zero)".to_string(),
120 arg_count: ArgCount::One,
121 eval: |args| args.first().trunc(),
122 },
123 Func {
124 category: Category::General,
125 name: "fract".to_string(),
126 help: "truncate value to its fractional part".to_string(),
127 arg_count: ArgCount::One,
128 eval: |args| args.first().fract(),
129 },
130 Func {
131 category: Category::General,
132 name: "abs".to_string(),
133 help: "compute absolute value".to_string(),
134 arg_count: ArgCount::One,
135 eval: |args| args.first().abs(),
136 },
137 Func {
138 category: Category::General,
139 name: "sign".to_string(),
140 help: "value sign (1 or -1)".to_string(),
141 arg_count: ArgCount::One,
142 eval: |args| args.first().signum(),
143 },
144 Func {
145 category: Category::General,
146 name: "min".to_string(),
147 help: "minimum of all arguments".to_string(),
148 arg_count: ArgCount::Atleast(1),
149 eval: |args| {
150 let args = args.all();
151 let mut min = args[0];
152 for arg in args.iter().skip(1) {
153 min = min.min(*arg);
154 }
155 min
156 },
157 },
158 Func {
159 category: Category::General,
160 name: "max".to_string(),
161 help: "maximum of all arguments".to_string(),
162 arg_count: ArgCount::Atleast(1),
163 eval: |args| {
164 let args = args.all();
165 let mut max = args[0];
166 for arg in args.iter().skip(1) {
167 max = max.max(*arg);
168 }
169 max
170 },
171 },
172 Func {
173 category: Category::PowerLog,
174 name: "pow".to_string(),
175 arg_count: ArgCount::Two,
176 help: "first argument raised to the power the second argument".to_string(),
177 eval: |args| args.first().powf(args.second()),
178 },
179 Func {
180 category: Category::PowerLog,
181 name: "sqrt".to_string(),
182 help: "square root".to_string(),
183 arg_count: ArgCount::One,
184 eval: |args| args.first().sqrt(),
185 },
186 Func {
187 category: Category::PowerLog,
188 name: "cbrt".to_string(),
189 help: "cubic root".to_string(),
190 arg_count: ArgCount::One,
191 eval: |args| args.first().cbrt(),
192 },
193 Func {
194 category: Category::PowerLog,
195 name: "exp".to_string(),
196 help: "exponential function (exp(x) = pow(e, x))".to_string(),
197 arg_count: ArgCount::One,
198 eval: |args| args.first().exp(),
199 },
200 Func {
201 category: Category::PowerLog,
202 name: "log".to_string(),
203 help: "log(b, x) is base b logarithm of x".to_string(),
204 arg_count: ArgCount::Two,
205 eval: |args| args.first().log(args.second()),
206 },
207 Func {
208 category: Category::PowerLog,
209 name: "ln".to_string(),
210 help: "natural logarithm".to_string(),
211 arg_count: ArgCount::One,
212 eval: |args| args.first().ln(),
213 },
214 Func {
215 category: Category::PowerLog,
216 name: "log2".to_string(),
217 help: "base 2 logarithm".to_string(),
218 arg_count: ArgCount::One,
219 eval: |args| args.first().log2(),
220 },
221 Func {
222 category: Category::PowerLog,
223 name: "log10".to_string(),
224 help: "base 10 logarithm".to_string(),
225 arg_count: ArgCount::One,
226 eval: |args| args.first().log10(),
227 },
228 Func {
229 category: Category::Trigonometry,
230 name: "sin".to_string(),
231 help: "sine function".to_string(),
232 arg_count: ArgCount::One,
233 eval: |args| args.first().sin(),
234 },
235 Func {
236 category: Category::Trigonometry,
237 name: "cos".to_string(),
238 help: "cosine function".to_string(),
239 arg_count: ArgCount::One,
240 eval: |args| args.first().cos(),
241 },
242 Func {
243 category: Category::Trigonometry,
244 name: "tan".to_string(),
245 help: "tangent function".to_string(),
246 arg_count: ArgCount::One,
247 eval: |args| args.first().tan(),
248 },
249 Func {
250 category: Category::Trigonometry,
251 name: "csc".to_string(),
252 help: "cosecante function (inverse of sine)".to_string(),
253 arg_count: ArgCount::One,
254 eval: |args| 1.0 / args.first().sin(),
255 },
256 Func {
257 category: Category::Trigonometry,
258 name: "sec".to_string(),
259 help: "secante function (inverse of cosine)".to_string(),
260 arg_count: ArgCount::One,
261 eval: |args| 1.0 / args.first().cos(),
262 },
263 Func {
264 category: Category::Trigonometry,
265 name: "cot".to_string(),
266 help: "cotangent function (inverse of tangent)".to_string(),
267 arg_count: ArgCount::One,
268 eval: |args| 1.0 / args.first().tan(),
269 },
270 Func {
271 category: Category::Trigonometry,
272 name: "asin".to_string(),
273 help: "arc sine function".to_string(),
274 arg_count: ArgCount::One,
275 eval: |args| args.first().asin(),
276 },
277 Func {
278 category: Category::Trigonometry,
279 name: "acos".to_string(),
280 help: "arc cosine function".to_string(),
281 arg_count: ArgCount::One,
282 eval: |args| args.first().acos(),
283 },
284 Func {
285 category: Category::Trigonometry,
286 name: "atan".to_string(),
287 help: "arc tangent function".to_string(),
288 arg_count: ArgCount::One,
289 eval: |args| args.first().atan(),
290 },
291 Func {
292 category: Category::Trigonometry,
293 name: "sinh".to_string(),
294 help: "hyperbolic sine function".to_string(),
295 arg_count: ArgCount::One,
296 eval: |args| args.first().sinh(),
297 },
298 Func {
299 category: Category::Trigonometry,
300 name: "cosh".to_string(),
301 help: "hyperbolic cosine function".to_string(),
302 arg_count: ArgCount::One,
303 eval: |args| args.first().cosh(),
304 },
305 Func {
306 category: Category::Trigonometry,
307 name: "tanh".to_string(),
308 help: "hyperbolic tangent function".to_string(),
309 arg_count: ArgCount::One,
310 eval: |args| args.first().tanh(),
311 },
312 Func {
313 category: Category::Trigonometry,
314 name: "asinh".to_string(),
315 help: "hyperbolic arc sine function".to_string(),
316 arg_count: ArgCount::One,
317 eval: |args| args.first().asinh(),
318 },
319 Func {
320 category: Category::Trigonometry,
321 name: "acosh".to_string(),
322 help: "hyperbolic arc cosine function".to_string(),
323 arg_count: ArgCount::One,
324 eval: |args| args.first().acosh(),
325 },
326 Func {
327 category: Category::Trigonometry,
328 name: "atanh".to_string(),
329 help: "hyperbolic arc tangent function".to_string(),
330 arg_count: ArgCount::One,
331 eval: |args| args.first().atanh(),
332 },
333 Func {
334 category: Category::Trigonometry,
335 name: "degs".to_string(),
336 help: "convert radians to degrees".to_string(),
337 arg_count: ArgCount::One,
338 eval: |args| args.first().to_degrees(),
339 },
340 Func {
341 category: Category::Trigonometry,
342 name: "rads".to_string(),
343 help: "convert degrees to radians".to_string(),
344 arg_count: ArgCount::One,
345 eval: |args| args.first().to_radians(),
346 },
347 ]
348}