tinc_build/codegen/cel/functions/
is_inf.rs

1use syn::parse_quote;
2use tinc_cel::CelValue;
3
4use super::Function;
5use crate::codegen::cel::compiler::{CompileError, CompiledExpr, CompilerCtx, ConstantCompiledExpr};
6use crate::codegen::cel::types::CelType;
7use crate::types::{ProtoType, ProtoValueType};
8
9#[derive(Debug, Clone, Default)]
10pub(crate) struct IsInf;
11
12// this.isInf(arg) -> arg in this
13impl Function for IsInf {
14    fn name(&self) -> &'static str {
15        "isInf"
16    }
17
18    fn syntax(&self) -> &'static str {
19        "<this>.isInf()"
20    }
21
22    fn compile(&self, ctx: CompilerCtx) -> Result<CompiledExpr, CompileError> {
23        let Some(this) = &ctx.this else {
24            return Err(CompileError::syntax("missing this", self));
25        };
26
27        if !ctx.args.is_empty() {
28            return Err(CompileError::syntax("does not take any arguments", self));
29        }
30
31        let this = this.clone().into_cel()?;
32
33        match this {
34            CompiledExpr::Constant(ConstantCompiledExpr { value }) => {
35                Ok(CompiledExpr::constant(CelValue::cel_is_inf(value)?))
36            }
37            this => Ok(CompiledExpr::runtime(
38                CelType::Proto(ProtoType::Value(ProtoValueType::Bool)),
39                parse_quote! {{
40                    ::tinc::__private::cel::CelValue::cel_is_inf(
41                        #this,
42                    )?
43                }},
44            )),
45        }
46    }
47}
48
49#[cfg(test)]
50#[cfg(feature = "prost")]
51#[cfg_attr(coverage_nightly, coverage(off))]
52mod tests {
53    use syn::parse_quote;
54    use tinc_cel::{CelValue, NumberTy};
55
56    use crate::codegen::cel::compiler::{CompiledExpr, Compiler, CompilerCtx};
57    use crate::codegen::cel::functions::{Function, IsInf};
58    use crate::codegen::cel::types::CelType;
59    use crate::extern_paths::ExternPaths;
60    use crate::path_set::PathSet;
61    use crate::types::{ProtoType, ProtoTypeRegistry, ProtoValueType};
62
63    #[test]
64    fn test_is_inf_syntax() {
65        let registry = ProtoTypeRegistry::new(crate::Mode::Prost, ExternPaths::new(crate::Mode::Prost), PathSet::default());
66        let compiler = Compiler::new(&registry);
67        insta::assert_debug_snapshot!(IsInf.compile(CompilerCtx::new(compiler.child(), None, &[])), @r#"
68        Err(
69            InvalidSyntax {
70                message: "missing this",
71                syntax: "<this>.isInf()",
72            },
73        )
74        "#);
75
76        insta::assert_debug_snapshot!(IsInf.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant(CelValue::Number(NumberTy::from(2.0)))), &[])), @r"
77        Ok(
78            Constant(
79                ConstantCompiledExpr {
80                    value: Bool(
81                        false,
82                    ),
83                },
84            ),
85        )
86        ");
87
88        insta::assert_debug_snapshot!(IsInf.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant(CelValue::Number(NumberTy::from(f64::INFINITY)))), &[])), @r"
89        Ok(
90            Constant(
91                ConstantCompiledExpr {
92                    value: Bool(
93                        true,
94                    ),
95                },
96            ),
97        )
98        ");
99
100        insta::assert_debug_snapshot!(IsInf.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant(CelValue::List(Default::default()))), &[
101            cel_parser::parse("1 + 1").unwrap(), // not an ident
102        ])), @r#"
103        Err(
104            InvalidSyntax {
105                message: "does not take any arguments",
106                syntax: "<this>.isInf()",
107            },
108        )
109        "#);
110    }
111
112    #[test]
113    #[cfg(not(valgrind))]
114    fn test_is_inf_runtime() {
115        let registry = ProtoTypeRegistry::new(crate::Mode::Prost, ExternPaths::new(crate::Mode::Prost), PathSet::default());
116        let compiler = Compiler::new(&registry);
117
118        let double_value =
119            CompiledExpr::runtime(CelType::Proto(ProtoType::Value(ProtoValueType::Double)), parse_quote!(input));
120
121        let output = IsInf
122            .compile(CompilerCtx::new(compiler.child(), Some(double_value), &[]))
123            .unwrap();
124
125        insta::assert_snapshot!(postcompile::compile_str!(
126            postcompile::config! {
127                test: true,
128                dependencies: vec![
129                    postcompile::Dependency::path("tinc", ".."),
130                ],
131            },
132            quote::quote! {
133                fn is_inf(input: f64) -> Result<bool, ::tinc::__private::cel::CelError<'static>> {
134                    Ok(#output)
135                }
136
137                #[test]
138                fn test_is_inf() {
139                    assert_eq!(is_inf(f64::INFINITY).unwrap(), true);
140                    assert_eq!(is_inf(2.0).unwrap(), false);
141                }
142            },
143        ));
144    }
145}