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}