tinc_build/codegen/cel/functions/
double.rs1use 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(®istry);
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(), ])), @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(®istry);
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}