Skip to main content

txtx_core/std/functions/
operators.rs

1use txtx_addon_kit::types::AuthorizationContext;
2use txtx_addon_kit::{
3    define_function, indoc,
4    types::{
5        diagnostics::Diagnostic,
6        functions::{FunctionImplementation, FunctionSpecification},
7        types::{Type, Value},
8    },
9};
10
11use super::arg_checker;
12
13lazy_static! {
14    pub static ref OPERATORS_FUNCTIONS: Vec<FunctionSpecification> = vec![
15        define_function! {
16            BinaryAndBool => {
17                name: "and_bool",
18                documentation: "`and_bool` returns the binary AND of the left- and right-hand-side arguments.",
19                example: indoc!{r#"
20                output "my_bool" { 
21                  value = false && true
22                }
23                // > my_bool: false
24                "#},
25                inputs: [
26                    lhs: {
27                        documentation: "A `boolean` value.",
28                        typing: vec![Type::bool()]
29                    },
30                    rhs: {
31                        documentation: "A `boolean` value.",
32                        typing: vec![Type::bool()]
33                    }
34                ],
35                output: {
36                    documentation: "The result of a binary AND between the two arguments.",
37                    typing: Type::bool()
38                },
39            }
40        },
41        define_function! {
42            BinaryOrBool => {
43                name: "or_bool",
44                documentation: "`or_bool` returns the binary OR of the left- and right-hand-side arguments.",
45                example: indoc!{r#"
46                output "my_bool" { 
47                  value = false || true
48                }
49                // > my_bool: true
50                "#},
51                inputs: [
52                    lhs: {
53                        documentation: "A `boolean` value.",
54                        typing: vec![Type::bool()]
55                    },
56                    rhs: {
57                        documentation: "A `boolean` value.",
58                        typing: vec![Type::bool()]
59                    }
60                ],
61                output: {
62                    documentation: "The result of a binary OR between the two arguments.",
63                    typing: Type::bool()
64                },
65            }
66        },
67        define_function! {
68            BinaryDivSignedInteger => {
69                name: "div",
70                documentation: "`div` returns the integer division of the left-hand-side argument by the right-hand-side argument, rounding any remainder down to the nearest integer.",
71                example: indoc!{r#"
72                output "my_int" { 
73                  value = 11 / -3
74                }
75                // > my_int: -3
76                "#},
77                inputs: [
78                    lhs: {
79                        documentation: "The `int` dividend.",
80                        typing: vec![Type::integer()]
81                    },
82                    rhs: {
83                        documentation: "The `int` divisor.",
84                        typing: vec![Type::integer()]
85                    }
86                ],
87                output: {
88                    documentation: "The result of dividing the dividend by the divisor.",
89                    typing: Type::integer()
90                },
91            }
92        },
93        define_function! {
94            BinaryEq => {
95                name: "eq",
96                documentation: "`eq` returns `true` if the left- and right-hand-side arguments are equal and `false` if they are not.",
97                example: indoc!{r#"
98                output "is_eq" { 
99                  value = "arg" == "arg"
100                }
101                // > is_eq: true
102                "#},
103                inputs: [
104                    lhs: {
105                        documentation: "Any value.",
106                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool(), Type::addon(""), Type::array(Type::null()), Type::arbitrary_object()]
107                    },
108                    rhs: {
109                        documentation: "Any value.",
110                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool(), Type::addon(""), Type::array(Type::null()), Type::arbitrary_object()]
111                    }
112                ],
113                output: {
114                    documentation: "The result of an equality check between the two inputs.",
115                    typing: Type::bool()
116                },
117            }
118        },
119        define_function! {
120            BinaryGreater => {
121                name: "gt",
122                documentation: "`gt` returns `true` if the left-hand-side argument is greater than the right-hand-side argument and `false` if it is not.",
123                example: indoc!{r#"
124                output "is_gt" { 
125                  value = 2 > 1
126                }
127                // > is_gt: true
128                "#},
129                inputs: [
130                    lhs: {
131                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
132                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
133                    },
134                    rhs: {
135                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
136                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
137                    }
138                ],
139                output: {
140                    documentation: "The result of checking if the left-hand-side argument is greater than the right-hand-side argument",
141                    typing: Type::bool()
142                },
143            }
144        },
145        define_function! {
146            BinaryGreaterEq => {
147                name: "gte",
148                documentation: "`gte` returns `true` if the left-hand-side argument is greater than or equal to the right-hand-side argument and `false` if it is not.",
149                example: indoc!{r#"
150                output "is_gte" { 
151                  value = 2 >= 2
152                }
153                // > is_gte: true
154                "#},
155                inputs: [
156                    lhs: {
157                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
158                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
159                    },
160                    rhs: {
161                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
162                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
163                    }
164                ],
165                output: {
166                    documentation: "The result of checking if the left-hand-side argument is greater than or equal to the right-hand-side argument",
167                    typing: Type::bool()
168                },
169            }
170        },
171        define_function! {
172            BinaryLess => {
173                name: "lt",
174                documentation: "`lt` returns `true` if the left-hand-side argument is less than the right-hand-side argument and `false` if it is not.",
175                example: indoc!{r#"
176                output "is_lt" { 
177                  value = 2 < 1
178                }
179                // > is_lt: false
180                "#},
181                inputs: [
182                    lhs: {
183                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
184                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
185                    },
186                    rhs: {
187                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
188                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
189                    }
190                ],
191                output: {
192                    documentation: "The result of checking if the left-hand-side argument is less than the right-hand-side argument",
193                    typing: Type::bool()
194                },
195            }
196        },
197        define_function! {
198            BinaryLessEq => {
199                name: "lte",
200                documentation: "`lte` returns `true` if the left-hand-side argument is less than or equal to the right-hand-side argument and `false` if it is not.",
201                example: indoc!{r#"
202                output "is_lte" { 
203                  value = 2 <= 2
204                }
205                // > is_lte: true
206                "#},
207                inputs: [
208                    lhs: {
209                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
210                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
211                    },
212                    rhs: {
213                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
214                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
215                    }
216                ],
217                output: {
218                    documentation: "The result of checking if the left-hand-side argument is less than or equal to the right-hand-side argument",
219                    typing: Type::bool()
220                },
221            }
222        },
223        define_function! {
224            BinaryNotEq => {
225                name: "neq",
226                documentation: "`enq` returns `true` if the left- and right-hand-side arguments are not equal and `false` otherwise.",
227                example: indoc!{r#"
228                output "is_neq" { 
229                  value = "arg" != "arg"
230                }
231                // > is_neq: false
232                "#},
233                inputs: [
234                    lhs: {
235                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
236                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
237                    },
238                    rhs: {
239                        documentation: "An `integer`, `float`, `string`, `boolean` or `null` value.",
240                        typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool()]
241                    }
242                ],
243                output: {
244                    documentation: "The result of a negated equality check between the two inputs.",
245                    typing: Type::bool()
246                },
247            }
248        },
249        define_function! {
250            BinaryMinus => {
251                name: "minus",
252                documentation: "`minus` returns the result of subtracting the right-hand-side `integer` argument from the left-hand-side `integer` argument.",
253                example: indoc!{r#"
254                output "my_integer" { 
255                  value = 10 - 6
256                }
257                // > my_integer: 4
258                "#},
259                inputs: [
260                    lhs: {
261                      documentation: "The `integer` minuend.",
262                      typing: vec![Type::integer()]
263                    },
264                    rhs: {
265                        documentation: "The `integer` subtrahend.",
266                        typing: vec![Type::integer()]
267                    }
268                ],
269                output: {
270                    documentation: "The result of the subtraction operation.",
271                    typing: Type::integer()
272                },
273            }
274        },
275        define_function! {
276            BinaryModulo => {
277                name: "modulo",
278                documentation: "`modulo` returns the remainder of dividing the left-hand-side `integer` argument by the right-hand-side `integer` argument.",
279                example: indoc!{r#"
280                  output "my_mod" { 
281                      value = 10 % 3
282                  }
283                  // > my_mod: 1
284              "#},
285                inputs: [
286                    lhs: {
287                        documentation: "The `integer` dividend.",
288                        typing: vec![Type::integer()]
289                    },
290                    rhs: {
291                        documentation: "The `integer` divisor.",
292                        typing: vec![Type::integer()]
293                    }
294                ],
295                output: {
296                    documentation: "The remainder of the division operation.",
297                    typing: Type::integer()
298                },
299            }
300        },
301        define_function! {
302            BinaryMul => {
303                name: "multiply",
304                documentation: "`multiply` returns the product of the left-hand-side `integer` argument and the right-hand-side `integer` argument.",
305                example: indoc!{r#"
306                  output "my_product" { 
307                      value = 10 * 5
308                  }
309                  // > my_product: 50
310              "#},
311                inputs: [
312                    lhs: {
313                        documentation: "The first `integer` operand.",
314                        typing: vec![Type::integer()],
315                        optional: false
316                    },
317                    rhs: {
318                        documentation: "The second `integer` operand.",
319                        typing: vec![Type::integer()],
320                        optional: false
321                    }
322                ],
323                output: {
324                    documentation: "The result of the multiplication operation.",
325                    typing: Type::integer()
326                },
327            }
328        },
329        define_function! {
330            BinaryPlus => {
331                name: "add",
332                documentation: "`add` returns the sum of the left-hand-side `integer` argument and the right-hand-side `integer` argument.",
333                example: indoc!{r#"
334                  output "my_sum" { 
335                      value = 10 + 5
336                  }
337                  // > my_sum: 15
338              "#},
339                inputs: [
340                    lhs: {
341                        documentation: "The first `integer` operand.",
342                        typing: vec![Type::integer()]
343                    },
344                    rhs: {
345                        documentation: "The second `integer` operand.",
346                        typing: vec![Type::integer()]
347                    }
348                ],
349                output: {
350                    documentation: "The result of the addition operation.",
351                    typing: Type::integer()
352                },
353            }
354        },
355        define_function! {
356            UnaryNegInteger => {
357                name: "neg_integer",
358                documentation: "Returns the negation of the given integer.",
359                example: "// Coming soon",
360                inputs: [
361                    value: {
362                        documentation: "An integer value.",
363                        typing: vec![Type::integer()]
364                    }
365                ],
366                output: {
367                    documentation: "The negated integer value.",
368                    typing: Type::integer()
369                },
370            }
371        },
372        define_function! {
373            UnaryNotBool => {
374                name: "not_bool",
375                documentation: "Returns the logical negation of the given boolean value.",
376                example: "// Coming soon",
377                inputs: [
378                    value: {
379                        documentation: "A boolean value.",
380                        typing: vec![Type::bool()]
381                    }
382                ],
383                output: {
384                    documentation: "The logical negation of the input boolean value.",
385                    typing: Type::bool()
386                },
387            }
388        },
389    ];
390}
391
392pub struct UnaryNegInteger;
393impl FunctionImplementation for UnaryNegInteger {
394    fn check_instantiability(
395        _fn_spec: &FunctionSpecification,
396        _auth_ctx: &AuthorizationContext,
397        _args: &Vec<Type>,
398    ) -> Result<Type, Diagnostic> {
399        unimplemented!()
400    }
401
402    fn run(
403        _fn_spec: &FunctionSpecification,
404        _auth_ctx: &AuthorizationContext,
405        _args: &Vec<Value>,
406    ) -> Result<Value, Diagnostic> {
407        unimplemented!()
408    }
409}
410
411pub struct UnaryNotBool;
412impl FunctionImplementation for UnaryNotBool {
413    fn check_instantiability(
414        _fn_spec: &FunctionSpecification,
415        _auth_ctx: &AuthorizationContext,
416        _args: &Vec<Type>,
417    ) -> Result<Type, Diagnostic> {
418        unimplemented!()
419    }
420
421    fn run(
422        _fn_spec: &FunctionSpecification,
423        _auth_ctx: &AuthorizationContext,
424        _args: &Vec<Value>,
425    ) -> Result<Value, Diagnostic> {
426        unimplemented!()
427    }
428}
429
430pub struct BinaryAndBool;
431impl FunctionImplementation for BinaryAndBool {
432    fn check_instantiability(
433        _fn_spec: &FunctionSpecification,
434        _auth_ctx: &AuthorizationContext,
435        _args: &Vec<Type>,
436    ) -> Result<Type, Diagnostic> {
437        unimplemented!()
438    }
439
440    fn run(
441        _fn_spec: &FunctionSpecification,
442        _auth_ctx: &AuthorizationContext,
443        args: &Vec<Value>,
444    ) -> Result<Value, Diagnostic> {
445        let Some(Value::Bool(lhs)) = args.get(0) else { unreachable!() };
446        let Some(Value::Bool(rhs)) = args.get(1) else { unreachable!() };
447        Ok(Value::bool(*lhs && *rhs))
448    }
449}
450
451pub struct BinaryOrBool;
452impl FunctionImplementation for BinaryOrBool {
453    fn check_instantiability(
454        _fn_spec: &FunctionSpecification,
455        _auth_ctx: &AuthorizationContext,
456        _args: &Vec<Type>,
457    ) -> Result<Type, Diagnostic> {
458        unimplemented!()
459    }
460
461    fn run(
462        _fn_spec: &FunctionSpecification,
463        _auth_ctx: &AuthorizationContext,
464        args: &Vec<Value>,
465    ) -> Result<Value, Diagnostic> {
466        let Some(Value::Bool(lhs)) = args.get(0) else { unreachable!() };
467        let Some(Value::Bool(rhs)) = args.get(1) else { unreachable!() };
468        Ok(Value::bool(*lhs || *rhs))
469    }
470}
471
472pub struct BinaryDivSignedInteger;
473impl FunctionImplementation for BinaryDivSignedInteger {
474    fn check_instantiability(
475        _fn_spec: &FunctionSpecification,
476        _auth_ctx: &AuthorizationContext,
477        _args: &Vec<Type>,
478    ) -> Result<Type, Diagnostic> {
479        unimplemented!()
480    }
481
482    fn run(
483        _fn_spec: &FunctionSpecification,
484        _auth_ctx: &AuthorizationContext,
485        args: &Vec<Value>,
486    ) -> Result<Value, Diagnostic> {
487        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
488        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
489        if rhs.eq(&0) {
490            Err(Diagnostic::error_from_string("cannot divide by zero".to_string()))
491        } else {
492            Ok(Value::integer(lhs.saturating_div(*rhs)))
493        }
494    }
495}
496
497pub struct BinaryEq;
498impl FunctionImplementation for BinaryEq {
499    fn check_instantiability(
500        _fn_spec: &FunctionSpecification,
501        _auth_ctx: &AuthorizationContext,
502        _args: &Vec<Type>,
503    ) -> Result<Type, Diagnostic> {
504        unimplemented!()
505    }
506
507    fn run(
508        fn_spec: &FunctionSpecification,
509        _auth_ctx: &AuthorizationContext,
510        args: &Vec<Value>,
511    ) -> Result<Value, Diagnostic> {
512        arg_checker(fn_spec, args)?;
513        let lhs = args.get(0).unwrap();
514        let rhs = args.get(1).unwrap();
515        Ok(Value::bool(lhs.eq(rhs)))
516    }
517}
518
519pub struct BinaryGreater;
520impl FunctionImplementation for BinaryGreater {
521    fn check_instantiability(
522        _fn_spec: &FunctionSpecification,
523        _auth_ctx: &AuthorizationContext,
524        _args: &Vec<Type>,
525    ) -> Result<Type, Diagnostic> {
526        unimplemented!()
527    }
528
529    fn run(
530        _fn_spec: &FunctionSpecification,
531        _auth_ctx: &AuthorizationContext,
532        args: &Vec<Value>,
533    ) -> Result<Value, Diagnostic> {
534        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
535        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
536        Ok(Value::bool(lhs.gt(&rhs)))
537    }
538}
539
540pub struct BinaryGreaterEq;
541impl FunctionImplementation for BinaryGreaterEq {
542    fn check_instantiability(
543        _fn_spec: &FunctionSpecification,
544        _auth_ctx: &AuthorizationContext,
545        _args: &Vec<Type>,
546    ) -> Result<Type, Diagnostic> {
547        unimplemented!()
548    }
549
550    fn run(
551        _fn_spec: &FunctionSpecification,
552        _auth_ctx: &AuthorizationContext,
553        args: &Vec<Value>,
554    ) -> Result<Value, Diagnostic> {
555        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
556        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
557        Ok(Value::bool(lhs.ge(&rhs)))
558    }
559}
560
561pub struct BinaryLess;
562impl FunctionImplementation for BinaryLess {
563    fn check_instantiability(
564        _fn_spec: &FunctionSpecification,
565        _auth_ctx: &AuthorizationContext,
566        _args: &Vec<Type>,
567    ) -> Result<Type, Diagnostic> {
568        unimplemented!()
569    }
570
571    fn run(
572        _fn_spec: &FunctionSpecification,
573        _auth_ctx: &AuthorizationContext,
574        args: &Vec<Value>,
575    ) -> Result<Value, Diagnostic> {
576        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
577        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
578        Ok(Value::bool(lhs.lt(&rhs)))
579    }
580}
581
582pub struct BinaryLessEq;
583impl FunctionImplementation for BinaryLessEq {
584    fn check_instantiability(
585        _fn_spec: &FunctionSpecification,
586        _auth_ctx: &AuthorizationContext,
587        _args: &Vec<Type>,
588    ) -> Result<Type, Diagnostic> {
589        unimplemented!()
590    }
591
592    fn run(
593        _fn_spec: &FunctionSpecification,
594        _auth_ctx: &AuthorizationContext,
595        args: &Vec<Value>,
596    ) -> Result<Value, Diagnostic> {
597        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
598        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
599        Ok(Value::bool(lhs.le(&rhs)))
600    }
601}
602
603pub struct BinaryNotEq;
604impl FunctionImplementation for BinaryNotEq {
605    fn check_instantiability(
606        _fn_spec: &FunctionSpecification,
607        _auth_ctx: &AuthorizationContext,
608        _args: &Vec<Type>,
609    ) -> Result<Type, Diagnostic> {
610        unimplemented!()
611    }
612
613    fn run(
614        _fn_spec: &FunctionSpecification,
615        _auth_ctx: &AuthorizationContext,
616        args: &Vec<Value>,
617    ) -> Result<Value, Diagnostic> {
618        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
619        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
620        Ok(Value::bool(!lhs.eq(&rhs)))
621    }
622}
623
624pub struct BinaryMinus;
625impl FunctionImplementation for BinaryMinus {
626    fn check_instantiability(
627        _fn_spec: &FunctionSpecification,
628        _auth_ctx: &AuthorizationContext,
629        _args: &Vec<Type>,
630    ) -> Result<Type, Diagnostic> {
631        unimplemented!()
632    }
633
634    fn run(
635        _fn_spec: &FunctionSpecification,
636        _auth_ctx: &AuthorizationContext,
637        args: &Vec<Value>,
638    ) -> Result<Value, Diagnostic> {
639        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
640        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
641        Ok(Value::integer(lhs - rhs))
642    }
643}
644
645pub struct BinaryModulo;
646impl FunctionImplementation for BinaryModulo {
647    fn check_instantiability(
648        _fn_spec: &FunctionSpecification,
649        _auth_ctx: &AuthorizationContext,
650        _args: &Vec<Type>,
651    ) -> Result<Type, Diagnostic> {
652        unimplemented!()
653    }
654
655    fn run(
656        _fn_spec: &FunctionSpecification,
657        _auth_ctx: &AuthorizationContext,
658        args: &Vec<Value>,
659    ) -> Result<Value, Diagnostic> {
660        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
661        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
662        Ok(Value::integer(lhs.rem_euclid(*rhs)))
663    }
664}
665
666pub struct BinaryMul;
667impl FunctionImplementation for BinaryMul {
668    fn check_instantiability(
669        _fn_spec: &FunctionSpecification,
670        _auth_ctx: &AuthorizationContext,
671        _args: &Vec<Type>,
672    ) -> Result<Type, Diagnostic> {
673        unimplemented!()
674    }
675
676    fn run(
677        fn_spec: &FunctionSpecification,
678        _auth_ctx: &AuthorizationContext,
679        args: &Vec<Value>,
680    ) -> Result<Value, Diagnostic> {
681        arg_checker(fn_spec, args)?;
682        let lhs = args.get(0).unwrap().as_integer().unwrap();
683        let rhs = args.get(1).unwrap().as_integer().unwrap();
684        Ok(Value::integer(lhs.saturating_mul(rhs)))
685    }
686}
687
688pub struct BinaryPlus;
689impl FunctionImplementation for BinaryPlus {
690    fn check_instantiability(
691        _fn_spec: &FunctionSpecification,
692        _auth_ctx: &AuthorizationContext,
693        _args: &Vec<Type>,
694    ) -> Result<Type, Diagnostic> {
695        unimplemented!()
696    }
697
698    fn run(
699        _fn_spec: &FunctionSpecification,
700        _auth_ctx: &AuthorizationContext,
701        args: &Vec<Value>,
702    ) -> Result<Value, Diagnostic> {
703        let Some(Value::Integer(lhs)) = args.get(0) else { unreachable!() };
704        let Some(Value::Integer(rhs)) = args.get(1) else { unreachable!() };
705        Ok(Value::integer(lhs + rhs))
706    }
707}