tinc_build/codegen/cel/functions/
uint.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 UInt;
10
11impl Function for UInt {
12    fn name(&self) -> &'static str {
13        "uint"
14    }
15
16    fn syntax(&self) -> &'static str {
17        "<this>.uint()"
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 }) => Ok(CompiledExpr::Constant(ConstantCompiledExpr {
31                value: CelValue::cel_to_uint(value)?,
32            })),
33            CompiledExpr::Runtime(RuntimeCompiledExpr { expr, .. }) => Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
34                ty: CelType::CelValue,
35                expr: parse_quote!(::tinc::__private::cel::CelValue::cel_to_uint(#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::{Function, UInt};
50    use crate::codegen::cel::types::CelType;
51    use crate::types::{ProtoType, ProtoTypeRegistry, ProtoValueType};
52
53    #[test]
54    fn test_uint_syntax() {
55        let registry = ProtoTypeRegistry::new(crate::Mode::Prost, crate::extern_paths::ExternPaths::new(crate::Mode::Prost));
56        let compiler = Compiler::new(&registry);
57        insta::assert_debug_snapshot!(UInt.compile(CompilerCtx::new(compiler.child(), None, &[])), @r#"
58        Err(
59            InvalidSyntax {
60                message: "missing this",
61                syntax: "<this>.uint()",
62            },
63        )
64        "#);
65
66        insta::assert_debug_snapshot!(UInt.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant(CelValue::String("13".into()))), &[])), @r"
67        Ok(
68            Constant(
69                ConstantCompiledExpr {
70                    value: Number(
71                        U64(
72                            13,
73                        ),
74                    ),
75                },
76            ),
77        )
78        ");
79
80        insta::assert_debug_snapshot!(UInt.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant(CelValue::List(Default::default()))), &[
81            cel_parser::parse("1 + 1").unwrap(), // not an ident
82        ])), @r#"
83        Err(
84            InvalidSyntax {
85                message: "takes no arguments",
86                syntax: "<this>.uint()",
87            },
88        )
89        "#);
90    }
91
92    #[test]
93    #[cfg(not(valgrind))]
94    fn test_uint_runtime() {
95        let registry = ProtoTypeRegistry::new(crate::Mode::Prost, crate::extern_paths::ExternPaths::new(crate::Mode::Prost));
96        let compiler = Compiler::new(&registry);
97
98        let string_value =
99            CompiledExpr::runtime(CelType::Proto(ProtoType::Value(ProtoValueType::String)), parse_quote!(input));
100
101        let output = UInt
102            .compile(CompilerCtx::new(compiler.child(), Some(string_value), &[]))
103            .unwrap();
104
105        insta::assert_snapshot!(postcompile::compile_str!(
106            postcompile::config! {
107                test: true,
108                dependencies: vec![
109                    postcompile::Dependency::version("tinc", "*"),
110                ],
111            },
112            quote::quote! {
113                fn to_int(input: &str) -> Result<::tinc::__private::cel::CelValue<'_>, ::tinc::__private::cel::CelError<'_>> {
114                    Ok(#output)
115                }
116
117                #[test]
118                fn test_to_int() {
119                    assert_eq!(to_int("55").unwrap(), ::tinc::__private::cel::CelValueConv::conv(55));
120                }
121            },
122        ));
123    }
124}