intuicio_frontend_simpleton/library/
math.rs

1use crate::{Boolean, Integer, Real, Reference};
2use intuicio_core::{define_native_struct, registry::Registry};
3use intuicio_derive::intuicio_function;
4use rand::Rng;
5use std::ops::Rem;
6
7#[intuicio_function(module_name = "math", use_registry)]
8pub fn min(registry: &Registry, a: Reference, b: Reference) -> Reference {
9    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
10        return Reference::new_integer(a.min(*b), registry);
11    }
12    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
13        return Reference::new_real(a.min(*b), registry);
14    }
15    Reference::null()
16}
17
18#[intuicio_function(module_name = "math", use_registry)]
19pub fn max(registry: &Registry, a: Reference, b: Reference) -> Reference {
20    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
21        return Reference::new_integer(a.max(*b), registry);
22    }
23    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
24        return Reference::new_real(a.max(*b), registry);
25    }
26    Reference::null()
27}
28
29#[intuicio_function(module_name = "math", use_registry)]
30pub fn add(registry: &Registry, a: Reference, b: Reference) -> Reference {
31    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
32        return Reference::new_integer(*a + *b, registry);
33    }
34    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
35        return Reference::new_real(*a + *b, registry);
36    }
37    Reference::null()
38}
39
40#[intuicio_function(module_name = "math", use_registry)]
41pub fn sub(registry: &Registry, a: Reference, b: Reference) -> Reference {
42    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
43        return Reference::new_integer(*a - *b, registry);
44    }
45    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
46        return Reference::new_real(*a - *b, registry);
47    }
48    Reference::null()
49}
50
51#[intuicio_function(module_name = "math", use_registry)]
52pub fn mul(registry: &Registry, a: Reference, b: Reference) -> Reference {
53    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
54        return Reference::new_integer(*a * *b, registry);
55    }
56    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
57        return Reference::new_real(*a * *b, registry);
58    }
59    Reference::null()
60}
61
62#[intuicio_function(module_name = "math", use_registry)]
63pub fn div(registry: &Registry, a: Reference, b: Reference) -> Reference {
64    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
65        return Reference::new_integer(*a / *b, registry);
66    }
67    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
68        return Reference::new_real(*a / *b, registry);
69    }
70    Reference::null()
71}
72
73#[intuicio_function(module_name = "math", use_registry)]
74pub fn negate(registry: &Registry, value: Reference) -> Reference {
75    if let Some(value) = value.read::<Integer>() {
76        return Reference::new_integer(-*value, registry);
77    }
78    if let Some(value) = value.read::<Real>() {
79        return Reference::new_real(-*value, registry);
80    }
81    if let Some(value) = value.read::<Boolean>() {
82        return Reference::new_boolean(!*value, registry);
83    }
84    Reference::null()
85}
86
87#[intuicio_function(module_name = "math", use_registry)]
88pub fn abs(registry: &Registry, value: Reference) -> Reference {
89    if let Some(value) = value.read::<Integer>() {
90        return Reference::new_integer(value.abs(), registry);
91    }
92    if let Some(value) = value.read::<Real>() {
93        return Reference::new_real(value.abs(), registry);
94    }
95    Reference::null()
96}
97
98#[intuicio_function(module_name = "math", use_registry)]
99pub fn pow(registry: &Registry, value: Reference, exp: Reference) -> Reference {
100    if let (Some(value), Some(exp)) = (value.read::<Integer>(), exp.read::<Integer>()) {
101        return Reference::new_integer(value.pow(*exp as _), registry);
102    }
103    if let (Some(value), Some(exp)) = (value.read::<Real>(), exp.read::<Real>()) {
104        return Reference::new_real(value.powf(*exp), registry);
105    }
106    Reference::null()
107}
108
109#[intuicio_function(module_name = "math", use_registry)]
110pub fn modulo(registry: &Registry, a: Reference, b: Reference) -> Reference {
111    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
112        return Reference::new_integer(a.rem(*b), registry);
113    }
114    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
115        return Reference::new_real(a.rem(*b), registry);
116    }
117    Reference::null()
118}
119
120#[intuicio_function(module_name = "math", use_registry)]
121pub fn log(registry: &Registry, a: Reference, b: Reference) -> Reference {
122    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
123        return Reference::new_integer(a.ilog(*b) as Integer, registry);
124    }
125    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
126        return Reference::new_real(a.log(*b), registry);
127    }
128    Reference::null()
129}
130
131#[intuicio_function(module_name = "math", use_registry)]
132pub fn signum(registry: &Registry, value: Reference) -> Reference {
133    if let Some(value) = value.read::<Integer>() {
134        return Reference::new_integer(value.signum(), registry);
135    }
136    if let Some(value) = value.read::<Real>() {
137        return Reference::new_real(value.signum(), registry);
138    }
139    Reference::null()
140}
141
142#[intuicio_function(module_name = "math", use_registry)]
143pub fn sin(registry: &Registry, value: Reference) -> Reference {
144    if let Some(value) = value.read::<Real>() {
145        return Reference::new_real(value.sin(), registry);
146    }
147    Reference::null()
148}
149
150#[intuicio_function(module_name = "math", use_registry)]
151pub fn cos(registry: &Registry, value: Reference) -> Reference {
152    if let Some(value) = value.read::<Real>() {
153        return Reference::new_real(value.cos(), registry);
154    }
155    Reference::null()
156}
157
158#[intuicio_function(module_name = "math", use_registry)]
159pub fn tan(registry: &Registry, value: Reference) -> Reference {
160    if let Some(value) = value.read::<Real>() {
161        return Reference::new_real(value.tan(), registry);
162    }
163    Reference::null()
164}
165
166#[intuicio_function(module_name = "math", use_registry)]
167pub fn asin(registry: &Registry, value: Reference) -> Reference {
168    if let Some(value) = value.read::<Real>() {
169        return Reference::new_real(value.asin(), registry);
170    }
171    Reference::null()
172}
173
174#[intuicio_function(module_name = "math", use_registry)]
175pub fn acos(registry: &Registry, value: Reference) -> Reference {
176    if let Some(value) = value.read::<Real>() {
177        return Reference::new_real(value.acos(), registry);
178    }
179    Reference::null()
180}
181
182#[intuicio_function(module_name = "math", use_registry)]
183pub fn atan(registry: &Registry, value: Reference) -> Reference {
184    if let Some(value) = value.read::<Real>() {
185        return Reference::new_real(value.atan(), registry);
186    }
187    Reference::null()
188}
189
190#[intuicio_function(module_name = "math", use_registry)]
191pub fn atan2(registry: &Registry, a: Reference, b: Reference) -> Reference {
192    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
193        return Reference::new_real(a.atan2(*b), registry);
194    }
195    Reference::null()
196}
197
198#[intuicio_function(module_name = "math", use_registry)]
199pub fn degrees(registry: &Registry, value: Reference) -> Reference {
200    if let Some(value) = value.read::<Real>() {
201        return Reference::new_real(value.to_degrees(), registry);
202    }
203    Reference::null()
204}
205
206#[intuicio_function(module_name = "math", use_registry)]
207pub fn radians(registry: &Registry, value: Reference) -> Reference {
208    if let Some(value) = value.read::<Real>() {
209        return Reference::new_real(value.to_radians(), registry);
210    }
211    Reference::null()
212}
213
214#[intuicio_function(module_name = "math", use_registry)]
215pub fn sqrt(registry: &Registry, value: Reference) -> Reference {
216    if let Some(value) = value.read::<Real>() {
217        return Reference::new_real(value.sqrt(), registry);
218    }
219    Reference::null()
220}
221
222#[intuicio_function(module_name = "math", use_registry)]
223pub fn floor(registry: &Registry, value: Reference) -> Reference {
224    if let Some(value) = value.read::<Real>() {
225        return Reference::new_real(value.floor(), registry);
226    }
227    Reference::null()
228}
229
230#[intuicio_function(module_name = "math", use_registry)]
231pub fn ceil(registry: &Registry, value: Reference) -> Reference {
232    if let Some(value) = value.read::<Real>() {
233        return Reference::new_real(value.ceil(), registry);
234    }
235    Reference::null()
236}
237
238#[intuicio_function(module_name = "math", use_registry)]
239pub fn round(registry: &Registry, value: Reference) -> Reference {
240    if let Some(value) = value.read::<Real>() {
241        return Reference::new_real(value.round(), registry);
242    }
243    Reference::null()
244}
245
246#[intuicio_function(module_name = "math", use_registry)]
247pub fn clamp(registry: &Registry, value: Reference, from: Reference, to: Reference) -> Reference {
248    if let (Some(value), Some(from), Some(to)) = (
249        value.read::<Integer>(),
250        from.read::<Integer>(),
251        to.read::<Integer>(),
252    ) {
253        return Reference::new_integer(value.clamp(*from, *to), registry);
254    }
255    if let (Some(value), Some(from), Some(to)) =
256        (value.read::<Real>(), from.read::<Real>(), to.read::<Real>())
257    {
258        return Reference::new_real(value.clamp(*from, *to), registry);
259    }
260    Reference::null()
261}
262
263#[intuicio_function(module_name = "math", use_registry)]
264pub fn fract(registry: &Registry, value: Reference) -> Reference {
265    if let Some(value) = value.read::<Real>() {
266        return Reference::new_real(value.fract(), registry);
267    }
268    Reference::null()
269}
270
271#[intuicio_function(module_name = "math", use_registry)]
272pub fn and(registry: &Registry, a: Reference, b: Reference) -> Reference {
273    if let (Some(a), Some(b)) = (a.read::<Boolean>(), b.read::<Boolean>()) {
274        return Reference::new_boolean(*a && *b, registry);
275    }
276    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
277        return Reference::new_integer(*a & *b, registry);
278    }
279    Reference::null()
280}
281
282#[intuicio_function(module_name = "math", use_registry)]
283pub fn or(registry: &Registry, a: Reference, b: Reference) -> Reference {
284    if let (Some(a), Some(b)) = (a.read::<Boolean>(), b.read::<Boolean>()) {
285        return Reference::new_boolean(*a || *b, registry);
286    }
287    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
288        return Reference::new_integer(*a | *b, registry);
289    }
290    Reference::null()
291}
292
293#[intuicio_function(module_name = "math", use_registry)]
294pub fn xor(registry: &Registry, a: Reference, b: Reference) -> Reference {
295    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
296        return Reference::new_integer(*a ^ *b, registry);
297    }
298    Reference::null()
299}
300
301#[intuicio_function(module_name = "math", use_registry)]
302pub fn shift_left(registry: &Registry, a: Reference, b: Reference) -> Reference {
303    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
304        return Reference::new_integer(*a << *b, registry);
305    }
306    Reference::null()
307}
308
309#[intuicio_function(module_name = "math", use_registry)]
310pub fn shift_right(registry: &Registry, a: Reference, b: Reference) -> Reference {
311    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
312        return Reference::new_integer(*a >> *b, registry);
313    }
314    Reference::null()
315}
316
317#[intuicio_function(module_name = "math", use_registry)]
318pub fn random_boolean(registry: &Registry) -> Reference {
319    Reference::new_boolean(rand::thread_rng().gen::<Boolean>(), registry)
320}
321
322#[intuicio_function(module_name = "math", use_registry)]
323pub fn random_integer(registry: &Registry, from: Reference, to: Reference) -> Reference {
324    let from = from
325        .read::<Integer>()
326        .map(|value| *value)
327        .unwrap_or(Integer::MIN);
328    let to = to
329        .read::<Integer>()
330        .map(|value| *value)
331        .unwrap_or(Integer::MAX);
332    let result = rand::thread_rng().gen_range(from..to);
333    Reference::new_integer(result, registry)
334}
335
336#[intuicio_function(module_name = "math", use_registry)]
337pub fn random_real(registry: &Registry, from: Reference, to: Reference) -> Reference {
338    let from = from.read::<Real>().map(|value| *value).unwrap_or(Real::MIN);
339    let to = to.read::<Real>().map(|value| *value).unwrap_or(Real::MAX);
340    let result = rand::thread_rng().gen_range(from..to);
341    Reference::new_real(result, registry)
342}
343
344#[intuicio_function(module_name = "math", use_registry)]
345pub fn equals(registry: &Registry, a: Reference, b: Reference) -> Reference {
346    if let (Some(a), Some(b)) = (a.read::<Boolean>(), b.read::<Boolean>()) {
347        return Reference::new_boolean(*a == *b, registry);
348    }
349    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
350        return Reference::new_boolean(*a == *b, registry);
351    }
352    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
353        return Reference::new_boolean(*a == *b, registry);
354    }
355    Reference::null()
356}
357
358#[intuicio_function(module_name = "math", use_registry)]
359pub fn not_equals(registry: &Registry, a: Reference, b: Reference) -> Reference {
360    if let (Some(a), Some(b)) = (a.read::<Boolean>(), b.read::<Boolean>()) {
361        return Reference::new_boolean(*a != *b, registry);
362    }
363    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
364        return Reference::new_boolean(*a != *b, registry);
365    }
366    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
367        return Reference::new_boolean(*a != *b, registry);
368    }
369    Reference::null()
370}
371
372#[intuicio_function(module_name = "math", use_registry)]
373pub fn less_than(registry: &Registry, a: Reference, b: Reference) -> Reference {
374    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
375        return Reference::new_boolean(*a < *b, registry);
376    }
377    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
378        return Reference::new_boolean(*a < *b, registry);
379    }
380    Reference::null()
381}
382
383#[intuicio_function(module_name = "math", use_registry)]
384pub fn less_than_or_equal(registry: &Registry, a: Reference, b: Reference) -> Reference {
385    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
386        return Reference::new_boolean(*a <= *b, registry);
387    }
388    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
389        return Reference::new_boolean(*a <= *b, registry);
390    }
391    Reference::null()
392}
393
394#[intuicio_function(module_name = "math", use_registry)]
395pub fn greater_than(registry: &Registry, a: Reference, b: Reference) -> Reference {
396    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
397        return Reference::new_boolean(*a > *b, registry);
398    }
399    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
400        return Reference::new_boolean(*a > *b, registry);
401    }
402    Reference::null()
403}
404
405#[intuicio_function(module_name = "math", use_registry)]
406pub fn greater_than_or_equal(registry: &Registry, a: Reference, b: Reference) -> Reference {
407    if let (Some(a), Some(b)) = (a.read::<Integer>(), b.read::<Integer>()) {
408        return Reference::new_boolean(*a >= *b, registry);
409    }
410    if let (Some(a), Some(b)) = (a.read::<Real>(), b.read::<Real>()) {
411        return Reference::new_boolean(*a >= *b, registry);
412    }
413    Reference::null()
414}
415
416pub fn install(registry: &mut Registry) {
417    registry.add_type(define_native_struct! {
418        registry => mod math struct Boolean (Boolean) {}
419    });
420    registry.add_type(define_native_struct! {
421        registry => mod math struct Integer (Integer) {}
422    });
423    registry.add_type(define_native_struct! {
424        registry => mod math struct Real (Real) {}
425    });
426    registry.add_function(min::define_function(registry));
427    registry.add_function(max::define_function(registry));
428    registry.add_function(add::define_function(registry));
429    registry.add_function(sub::define_function(registry));
430    registry.add_function(mul::define_function(registry));
431    registry.add_function(div::define_function(registry));
432    registry.add_function(negate::define_function(registry));
433    registry.add_function(abs::define_function(registry));
434    registry.add_function(pow::define_function(registry));
435    registry.add_function(modulo::define_function(registry));
436    registry.add_function(log::define_function(registry));
437    registry.add_function(signum::define_function(registry));
438    registry.add_function(sin::define_function(registry));
439    registry.add_function(cos::define_function(registry));
440    registry.add_function(tan::define_function(registry));
441    registry.add_function(asin::define_function(registry));
442    registry.add_function(acos::define_function(registry));
443    registry.add_function(atan::define_function(registry));
444    registry.add_function(atan2::define_function(registry));
445    registry.add_function(degrees::define_function(registry));
446    registry.add_function(radians::define_function(registry));
447    registry.add_function(sqrt::define_function(registry));
448    registry.add_function(floor::define_function(registry));
449    registry.add_function(ceil::define_function(registry));
450    registry.add_function(round::define_function(registry));
451    registry.add_function(clamp::define_function(registry));
452    registry.add_function(fract::define_function(registry));
453    registry.add_function(and::define_function(registry));
454    registry.add_function(or::define_function(registry));
455    registry.add_function(xor::define_function(registry));
456    registry.add_function(shift_left::define_function(registry));
457    registry.add_function(shift_right::define_function(registry));
458    registry.add_function(random_boolean::define_function(registry));
459    registry.add_function(random_integer::define_function(registry));
460    registry.add_function(random_real::define_function(registry));
461    registry.add_function(equals::define_function(registry));
462    registry.add_function(not_equals::define_function(registry));
463    registry.add_function(less_than::define_function(registry));
464    registry.add_function(less_than_or_equal::define_function(registry));
465    registry.add_function(greater_than::define_function(registry));
466    registry.add_function(greater_than_or_equal::define_function(registry));
467}