tinc_build/codegen/cel/functions/
double.rs

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