rhai/packages/
logic.rs

1use crate::def_package;
2use crate::plugin::*;
3#[cfg(feature = "no_std")]
4use std::prelude::v1::*;
5
6#[cfg(any(
7    not(feature = "no_float"),
8    all(not(feature = "only_i32"), not(feature = "only_i64"))
9))]
10macro_rules! gen_cmp_functions {
11    ($mod_name:ident => $($arg_type:ident),+) => {
12        $({
13            #[export_module]
14            #[allow(clippy::missing_const_for_fn)]
15            pub mod cmp_functions {
16                #[rhai_fn(name = "<")] pub fn lt(x: $arg_type, y: $arg_type) -> bool { x < y }
17                #[rhai_fn(name = "<=")] pub fn lte(x: $arg_type, y: $arg_type) -> bool { x <= y }
18                #[rhai_fn(name = ">")] pub fn gt(x: $arg_type, y: $arg_type) -> bool { x > y }
19                #[rhai_fn(name = ">=")] pub fn gte(x: $arg_type, y: $arg_type) -> bool { x >= y }
20                #[rhai_fn(name = "==")] pub fn eq(x: $arg_type, y: $arg_type) -> bool { x == y }
21                #[rhai_fn(name = "!=")] pub fn ne(x: $arg_type, y: $arg_type) -> bool { x != y }
22                pub fn max(x: $arg_type, y: $arg_type) -> $arg_type { if x >= y { x } else { y } }
23                pub fn min(x: $arg_type, y: $arg_type) -> $arg_type { if x <= y { x } else { y } }
24            }
25
26            combine_with_exported_module!($mod_name, concat!("logic_", stringify($arg_type)), cmp_functions);
27        })*
28    };
29}
30
31def_package! {
32    /// Package of basic logic operators.
33    pub LogicPackage(lib) {
34        lib.set_standard_lib(true);
35
36        #[cfg(not(feature = "only_i32"))]
37        #[cfg(not(feature = "only_i64"))]
38        {
39            gen_cmp_functions!(lib => i8, u8, i16, u16, i32, u32, u64);
40
41            #[cfg(not(target_family = "wasm"))]
42            gen_cmp_functions!(lib => i128, u128);
43        }
44
45        #[cfg(not(feature = "no_float"))]
46        {
47            combine_with_exported_module!(lib, "float", float_functions);
48
49            #[cfg(not(feature = "f32_float"))]
50            {
51                gen_cmp_functions!(lib => f32);
52                combine_with_exported_module!(lib, "f32", f32_functions);
53            }
54            #[cfg(feature = "f32_float")]
55            {
56                gen_cmp_functions!(lib => f64);
57                combine_with_exported_module!(lib, "f64", f64_functions);
58            }
59        }
60
61        #[cfg(feature = "decimal")]
62        combine_with_exported_module!(lib, "decimal", decimal_functions);
63
64        combine_with_exported_module!(lib, "logic", logic_functions);
65
66        combine_with_exported_module!(lib, "min_max", min_max_functions);
67    }
68}
69
70#[export_module]
71mod logic_functions {
72    #[rhai_fn(name = "!")]
73    pub const fn not(x: bool) -> bool {
74        !x
75    }
76}
77
78#[export_module]
79mod min_max_functions {
80    use crate::INT;
81
82    /// Return the number that is larger than the other number.
83    ///
84    /// # Example
85    ///
86    /// ```rhai
87    /// max(42, 123);   // returns 132
88    /// ```
89    pub const fn max(x: INT, y: INT) -> INT {
90        if x >= y {
91            x
92        } else {
93            y
94        }
95    }
96    /// Return the number that is smaller than the other number.
97    ///
98    /// # Example
99    ///
100    /// ```rhai
101    /// min(42, 123);   // returns 42
102    /// ```
103    pub const fn min(x: INT, y: INT) -> INT {
104        if x <= y {
105            x
106        } else {
107            y
108        }
109    }
110}
111
112#[cfg(not(feature = "no_float"))]
113#[allow(clippy::cast_precision_loss)]
114#[export_module]
115mod float_functions {
116    use crate::INT;
117
118    #[rhai_fn(name = "max")]
119    pub fn max_ff_32(x: f32, y: f32) -> f32 {
120        if x >= y {
121            x
122        } else {
123            y
124        }
125    }
126    #[rhai_fn(name = "max")]
127    pub fn max_if_32(x: INT, y: f32) -> f32 {
128        let (x, y) = (x as f32, y);
129        if x >= y {
130            x
131        } else {
132            y
133        }
134    }
135    #[rhai_fn(name = "max")]
136    pub fn max_fi_32(x: f32, y: INT) -> f32 {
137        let (x, y) = (x, y as f32);
138        if x >= y {
139            x
140        } else {
141            y
142        }
143    }
144    #[rhai_fn(name = "min")]
145    pub fn min_ff_32(x: f32, y: f32) -> f32 {
146        if x <= y {
147            x
148        } else {
149            y
150        }
151    }
152    #[rhai_fn(name = "min")]
153    pub fn min_if_32(x: INT, y: f32) -> f32 {
154        let (x, y) = (x as f32, y);
155        if x <= y {
156            x
157        } else {
158            y
159        }
160    }
161    #[rhai_fn(name = "min")]
162    pub fn min_fi_32(x: f32, y: INT) -> f32 {
163        let (x, y) = (x, y as f32);
164        if x <= y {
165            x
166        } else {
167            y
168        }
169    }
170    #[rhai_fn(name = "max")]
171    pub fn max_ff_64(x: f64, y: f64) -> f64 {
172        if x >= y {
173            x
174        } else {
175            y
176        }
177    }
178    #[rhai_fn(name = "max")]
179    pub fn max_if_64(x: INT, y: f64) -> f64 {
180        let (x, y) = (x as f64, y);
181        if x >= y {
182            x
183        } else {
184            y
185        }
186    }
187    #[rhai_fn(name = "max")]
188    pub fn max_fi_64(x: f64, y: INT) -> f64 {
189        let (x, y) = (x, y as f64);
190        if x >= y {
191            x
192        } else {
193            y
194        }
195    }
196    #[rhai_fn(name = "min")]
197    pub fn min_ff_64(x: f64, y: f64) -> f64 {
198        if x <= y {
199            x
200        } else {
201            y
202        }
203    }
204    #[rhai_fn(name = "min")]
205    pub fn min_if_64(x: INT, y: f64) -> f64 {
206        let (x, y) = (x as f64, y);
207        if x <= y {
208            x
209        } else {
210            y
211        }
212    }
213    #[rhai_fn(name = "min")]
214    pub fn min_fi_64(x: f64, y: INT) -> f64 {
215        let (x, y) = (x, y as f64);
216        if x <= y {
217            x
218        } else {
219            y
220        }
221    }
222}
223
224#[cfg(not(feature = "no_float"))]
225#[cfg(not(feature = "f32_float"))]
226#[allow(clippy::cast_precision_loss)]
227#[export_module]
228mod f32_functions {
229    use crate::{FLOAT, INT};
230    #[cfg(feature = "no_std")]
231    use num_traits::Float;
232
233    #[rhai_fn(name = "==")]
234    pub fn eq_if(x: INT, y: f32) -> bool {
235        #[cfg(feature = "unchecked")]
236        return (x as f32) == y;
237
238        #[cfg(not(feature = "unchecked"))]
239        {
240            let x = x as f32;
241            let max = if x * y == 0.0 {
242                1.0
243            } else {
244                x.abs().max(y.abs())
245            };
246            if max == 0.0 {
247                return true;
248            }
249            (x - y).abs() / max <= f32::EPSILON
250        }
251    }
252    #[rhai_fn(name = "==")]
253    pub fn eq_fi(x: f32, y: INT) -> bool {
254        #[cfg(feature = "unchecked")]
255        return x == (y as f32);
256
257        #[cfg(not(feature = "unchecked"))]
258        {
259            let y = y as f32;
260            let max = if x * y == 0.0 {
261                1.0
262            } else {
263                x.abs().max(y.abs())
264            };
265            if max == 0.0 {
266                return true;
267            }
268            (x - y).abs() / max <= f32::EPSILON
269        }
270    }
271    #[rhai_fn(name = "!=")]
272    pub fn neq_if(x: INT, y: f32) -> bool {
273        #[cfg(feature = "unchecked")]
274        return (x as f32) != y;
275
276        #[cfg(not(feature = "unchecked"))]
277        {
278            let x = x as f32;
279            let max = if x * y == 0.0 {
280                1.0
281            } else {
282                x.abs().max(y.abs())
283            };
284            if max == 0.0 {
285                return false;
286            }
287            (x - y).abs() / max > f32::EPSILON
288        }
289    }
290    #[rhai_fn(name = "!=")]
291    pub fn neq_fi(x: f32, y: INT) -> bool {
292        #[cfg(feature = "unchecked")]
293        return x != (y as f32);
294
295        #[cfg(not(feature = "unchecked"))]
296        {
297            let y = y as f32;
298            let max = if x * y == 0.0 {
299                1.0
300            } else {
301                x.abs().max(y.abs())
302            };
303            if max == 0.0 {
304                return false;
305            }
306            (x - y).abs() / max > f32::EPSILON
307        }
308    }
309    #[rhai_fn(name = ">")]
310    pub fn gt_if(x: INT, y: f32) -> bool {
311        #[cfg(feature = "unchecked")]
312        return (x as f32) > y;
313
314        #[cfg(not(feature = "unchecked"))]
315        {
316            let x = x as f32;
317            let max = if x * y == 0.0 {
318                1.0
319            } else {
320                x.abs().max(y.abs())
321            };
322            if max == 0.0 {
323                return false;
324            }
325            (x - y) / max > f32::EPSILON
326        }
327    }
328    #[rhai_fn(name = ">")]
329    pub fn gt_fi(x: f32, y: INT) -> bool {
330        #[cfg(feature = "unchecked")]
331        return x > (y as f32);
332
333        #[cfg(not(feature = "unchecked"))]
334        {
335            let y = y as f32;
336            let max = if x * y == 0.0 {
337                1.0
338            } else {
339                x.abs().max(y.abs())
340            };
341            if max == 0.0 {
342                return false;
343            }
344            (x - y) / max > f32::EPSILON
345        }
346    }
347    #[rhai_fn(name = ">=")]
348    pub fn gte_if(x: INT, y: f32) -> bool {
349        #[cfg(feature = "unchecked")]
350        return (x as f32) >= y;
351
352        #[cfg(not(feature = "unchecked"))]
353        {
354            let x = x as f32;
355            let max = if x * y == 0.0 {
356                1.0
357            } else {
358                x.abs().max(y.abs())
359            };
360            if max == 0.0 {
361                return true;
362            }
363            (x - y) / max > -f32::EPSILON
364        }
365    }
366    #[rhai_fn(name = ">=")]
367    pub fn gte_fi(x: f32, y: INT) -> bool {
368        #[cfg(feature = "unchecked")]
369        return x >= (y as f32);
370
371        #[cfg(not(feature = "unchecked"))]
372        {
373            let y = y as f32;
374            let max = if x * y == 0.0 {
375                1.0
376            } else {
377                x.abs().max(y.abs())
378            };
379            if max == 0.0 {
380                return true;
381            }
382            (x - y) / max > -f32::EPSILON
383        }
384    }
385    #[rhai_fn(name = "<")]
386    pub fn lt_if(x: INT, y: f32) -> bool {
387        #[cfg(feature = "unchecked")]
388        return (x as f32) < y;
389
390        #[cfg(not(feature = "unchecked"))]
391        {
392            let x = x as f32;
393            let max = if x * y == 0.0 {
394                1.0
395            } else {
396                x.abs().max(y.abs())
397            };
398            if max == 0.0 {
399                return false;
400            }
401            (y - x) / max > f32::EPSILON
402        }
403    }
404    #[rhai_fn(name = "<")]
405    pub fn lt_fi(x: f32, y: INT) -> bool {
406        #[cfg(feature = "unchecked")]
407        return x < (y as f32);
408
409        #[cfg(not(feature = "unchecked"))]
410        {
411            let y = y as f32;
412            let max = if x * y == 0.0 {
413                1.0
414            } else {
415                x.abs().max(y.abs())
416            };
417            if max == 0.0 {
418                return false;
419            }
420            (y - x) / max > f32::EPSILON
421        }
422    }
423    #[rhai_fn(name = "<=")]
424    pub fn lte_if(x: INT, y: f32) -> bool {
425        #[cfg(feature = "unchecked")]
426        return (x as f32) <= y;
427
428        #[cfg(not(feature = "unchecked"))]
429        {
430            let x = x as f32;
431            let max = if x * y == 0.0 {
432                1.0
433            } else {
434                x.abs().max(y.abs())
435            };
436            if max == 0.0 {
437                return true;
438            }
439            (y - x) / max > -f32::EPSILON
440        }
441    }
442    #[rhai_fn(name = "<=")]
443    pub fn lte_fi(x: f32, y: INT) -> bool {
444        #[cfg(feature = "unchecked")]
445        return x <= (y as f32);
446
447        #[cfg(not(feature = "unchecked"))]
448        {
449            let y = y as f32;
450            let max = if x * y == 0.0 {
451                1.0
452            } else {
453                x.abs().max(y.abs())
454            };
455            if max == 0.0 {
456                return true;
457            }
458            (y - x) / max > -f32::EPSILON
459        }
460    }
461
462    #[rhai_fn(name = "max")]
463    pub fn max_64_32(x: FLOAT, y: f32) -> FLOAT {
464        let (x, y) = (x, y as FLOAT);
465        if x >= y {
466            x
467        } else {
468            y
469        }
470    }
471    #[rhai_fn(name = "max")]
472    pub fn max_32_64(x: f32, y: FLOAT) -> FLOAT {
473        let (x, y) = (x as FLOAT, y);
474        if x >= y {
475            x
476        } else {
477            y
478        }
479    }
480    #[rhai_fn(name = "min")]
481    pub fn min_64_32(x: FLOAT, y: f32) -> FLOAT {
482        let (x, y) = (x, y as FLOAT);
483        if x <= y {
484            x
485        } else {
486            y
487        }
488    }
489    #[rhai_fn(name = "min")]
490    pub fn min_32_64(x: f32, y: FLOAT) -> FLOAT {
491        let (x, y) = (x as FLOAT, y);
492        if x <= y {
493            x
494        } else {
495            y
496        }
497    }
498}
499
500#[cfg(not(feature = "no_float"))]
501#[cfg(feature = "f32_float")]
502#[allow(clippy::cast_precision_loss)]
503#[export_module]
504mod f64_functions {
505    use crate::{FLOAT, INT};
506    #[cfg(feature = "no_std")]
507    use num_traits::Float;
508
509    #[rhai_fn(name = "==")]
510    pub fn eq_if(x: INT, y: f64) -> bool {
511        #[cfg(feature = "unchecked")]
512        return (x as f64) == y;
513
514        #[cfg(not(feature = "unchecked"))]
515        {
516            let x = x as f64;
517            let max = if x * y == 0.0 {
518                1.0
519            } else {
520                x.abs().max(y.abs())
521            };
522            if max == 0.0 {
523                return true;
524            }
525            return (x - y).abs() / max <= f64::EPSILON;
526        }
527    }
528    #[rhai_fn(name = "==")]
529    pub fn eq_fi(x: f64, y: INT) -> bool {
530        #[cfg(feature = "unchecked")]
531        return x == (y as f64);
532
533        #[cfg(not(feature = "unchecked"))]
534        {
535            let y = y as f64;
536            let max = if x * y == 0.0 {
537                1.0
538            } else {
539                x.abs().max(y.abs())
540            };
541            if max == 0.0 {
542                return true;
543            }
544            return (x - y).abs() / max <= f64::EPSILON;
545        }
546    }
547    #[rhai_fn(name = "!=")]
548    pub fn neq_if(x: INT, y: f64) -> bool {
549        #[cfg(feature = "unchecked")]
550        return (x as f64) != y;
551
552        #[cfg(not(feature = "unchecked"))]
553        {
554            let x = x as f64;
555            let max = if x * y == 0.0 {
556                1.0
557            } else {
558                x.abs().max(y.abs())
559            };
560            if max == 0.0 {
561                return false;
562            }
563            return (x - y).abs() / max > f64::EPSILON;
564        }
565    }
566    #[rhai_fn(name = "!=")]
567    pub fn neq_fi(x: f64, y: INT) -> bool {
568        #[cfg(feature = "unchecked")]
569        return x != (y as f64);
570
571        #[cfg(not(feature = "unchecked"))]
572        {
573            let y = y as f64;
574            let max = if x * y == 0.0 {
575                1.0
576            } else {
577                x.abs().max(y.abs())
578            };
579            if max == 0.0 {
580                return false;
581            }
582            return (x - y).abs() / max > f64::EPSILON;
583        }
584    }
585    #[rhai_fn(name = ">")]
586    pub fn gt_if(x: INT, y: f64) -> bool {
587        #[cfg(feature = "unchecked")]
588        return (x as f64) > y;
589
590        #[cfg(not(feature = "unchecked"))]
591        {
592            let x = x as f64;
593            let max = if x * y == 0.0 {
594                1.0
595            } else {
596                x.abs().max(y.abs())
597            };
598            if max == 0.0 {
599                return false;
600            }
601            return (x - y) / max > f64::EPSILON;
602        }
603    }
604    #[rhai_fn(name = ">")]
605    pub fn gt_fi(x: f64, y: INT) -> bool {
606        #[cfg(feature = "unchecked")]
607        return x > (y as f64);
608
609        #[cfg(not(feature = "unchecked"))]
610        {
611            let y = y as f64;
612            let max = if x * y == 0.0 {
613                1.0
614            } else {
615                x.abs().max(y.abs())
616            };
617            if max == 0.0 {
618                return false;
619            }
620            return (x - y) / max > f64::EPSILON;
621        }
622    }
623    #[rhai_fn(name = ">=")]
624    pub fn gte_if(x: INT, y: f64) -> bool {
625        #[cfg(feature = "unchecked")]
626        return (x as f64) >= y;
627
628        #[cfg(not(feature = "unchecked"))]
629        {
630            let x = x as f64;
631            let max = if x * y == 0.0 {
632                1.0
633            } else {
634                x.abs().max(y.abs())
635            };
636            if max == 0.0 {
637                return true;
638            }
639            return (x - y) / max > -f64::EPSILON;
640        }
641    }
642    #[rhai_fn(name = ">=")]
643    pub fn gte_fi(x: f64, y: INT) -> bool {
644        #[cfg(feature = "unchecked")]
645        return x >= (y as f64);
646
647        #[cfg(not(feature = "unchecked"))]
648        {
649            let y = y as f64;
650            let max = if x * y == 0.0 {
651                1.0
652            } else {
653                x.abs().max(y.abs())
654            };
655            if max == 0.0 {
656                return true;
657            }
658            return (x - y) / max > -f64::EPSILON;
659        }
660    }
661    #[rhai_fn(name = "<")]
662    pub fn lt_if(x: INT, y: f64) -> bool {
663        #[cfg(feature = "unchecked")]
664        return (x as f64) < y;
665
666        #[cfg(not(feature = "unchecked"))]
667        {
668            let x = x as f64;
669            let max = if x * y == 0.0 {
670                1.0
671            } else {
672                x.abs().max(y.abs())
673            };
674            if max == 0.0 {
675                return false;
676            }
677            return (y - x) / max > f64::EPSILON;
678        }
679    }
680    #[rhai_fn(name = "<")]
681    pub fn lt_fi(x: f64, y: INT) -> bool {
682        #[cfg(feature = "unchecked")]
683        return x < (y as f64);
684
685        #[cfg(not(feature = "unchecked"))]
686        {
687            let y = y as f64;
688            let max = if x * y == 0.0 {
689                1.0
690            } else {
691                x.abs().max(y.abs())
692            };
693            if max == 0.0 {
694                return false;
695            }
696            return (y - x) / max > f64::EPSILON;
697        }
698    }
699    #[rhai_fn(name = "<=")]
700    pub fn lte_if(x: INT, y: f64) -> bool {
701        #[cfg(feature = "unchecked")]
702        return (x as f64) <= y;
703
704        #[cfg(not(feature = "unchecked"))]
705        {
706            let x = x as f64;
707            let max = if x * y == 0.0 {
708                1.0
709            } else {
710                x.abs().max(y.abs())
711            };
712            if max == 0.0 {
713                return true;
714            }
715            return (y - x) / max > -f64::EPSILON;
716        }
717    }
718    #[rhai_fn(name = "<=")]
719    pub fn lte_fi(x: f64, y: INT) -> bool {
720        #[cfg(feature = "unchecked")]
721        return x <= (y as f64);
722
723        #[cfg(not(feature = "unchecked"))]
724        {
725            let y = y as f64;
726            let max = if x * y == 0.0 {
727                1.0
728            } else {
729                x.abs().max(y.abs())
730            };
731            if max == 0.0 {
732                return true;
733            }
734            return (y - x) / max > -f64::EPSILON;
735        }
736    }
737
738    #[rhai_fn(name = "max")]
739    pub fn max_32_64(x: FLOAT, y: f64) -> FLOAT {
740        let (x, y) = (x, y as FLOAT);
741        if x >= y {
742            x
743        } else {
744            y
745        }
746    }
747    #[rhai_fn(name = "max")]
748    pub fn max_64_32(x: f64, y: FLOAT) -> FLOAT {
749        let (x, y) = (x as FLOAT, y);
750        if x >= y {
751            x
752        } else {
753            y
754        }
755    }
756    #[rhai_fn(name = "min")]
757    pub fn min_32_64(x: FLOAT, y: f64) -> FLOAT {
758        let (x, y) = (x, y as FLOAT);
759        if x <= y {
760            x
761        } else {
762            y
763        }
764    }
765    #[rhai_fn(name = "min")]
766    pub fn min_64_32(x: f64, y: FLOAT) -> FLOAT {
767        let (x, y) = (x as FLOAT, y);
768        if x <= y {
769            x
770        } else {
771            y
772        }
773    }
774}
775
776#[cfg(feature = "decimal")]
777#[export_module]
778mod decimal_functions {
779    use crate::INT;
780    use rust_decimal::Decimal;
781
782    #[rhai_fn(name = "max")]
783    pub fn max_dd(x: Decimal, y: Decimal) -> Decimal {
784        if x >= y {
785            x
786        } else {
787            y
788        }
789    }
790    #[rhai_fn(name = "max")]
791    pub fn max_id(x: INT, y: Decimal) -> Decimal {
792        let x = x.into();
793        if x >= y {
794            x
795        } else {
796            y
797        }
798    }
799    #[rhai_fn(name = "max")]
800    pub fn max_di(x: Decimal, y: INT) -> Decimal {
801        let y = y.into();
802        if x >= y {
803            x
804        } else {
805            y
806        }
807    }
808    #[rhai_fn(name = "min")]
809    pub fn min_dd(x: Decimal, y: Decimal) -> Decimal {
810        if x <= y {
811            x
812        } else {
813            y
814        }
815    }
816    #[rhai_fn(name = "min")]
817    pub fn min_id(x: INT, y: Decimal) -> Decimal {
818        let x = x.into();
819        if x <= y {
820            x
821        } else {
822            y
823        }
824    }
825    #[rhai_fn(name = "min")]
826    pub fn min_di(x: Decimal, y: INT) -> Decimal {
827        let y = y.into();
828        if x <= y {
829            x
830        } else {
831            y
832        }
833    }
834}