tinc_build/codegen/cel/functions/
bytes.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 Bytes;
10
11impl Function for Bytes {
12    fn name(&self) -> &'static str {
13        "bytes"
14    }
15
16    fn syntax(&self) -> &'static str {
17        "<this>.bytes()"
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_bytes(value)?))
32            }
33            CompiledExpr::Runtime(RuntimeCompiledExpr { expr, .. }) => Ok(CompiledExpr::runtime(
34                CelType::CelValue,
35                parse_quote!(::tinc::__private::cel::CelValue::cel_to_bytes(#expr)?),
36            )),
37        }
38    }
39}
40
41#[cfg(test)]
42#[cfg(feature = "prost")]
43#[cfg_attr(coverage_nightly, coverage(off))]
44mod tests {
45    use quote::quote;
46    use syn::parse_quote;
47    use tinc_cel::CelValue;
48
49    use crate::codegen::cel::compiler::{CompiledExpr, Compiler, CompilerCtx};
50    use crate::codegen::cel::functions::{Bytes, Function};
51    use crate::codegen::cel::types::CelType;
52    use crate::extern_paths::ExternPaths;
53    use crate::path_set::PathSet;
54    use crate::types::{ProtoType, ProtoTypeRegistry, ProtoValueType};
55
56    #[test]
57    fn test_bytes_syntax() {
58        let registry = ProtoTypeRegistry::new(crate::Mode::Prost, ExternPaths::new(crate::Mode::Prost), PathSet::default());
59        let compiler = Compiler::new(&registry);
60        insta::assert_debug_snapshot!(Bytes.compile(CompilerCtx::new(compiler.child(), None, &[])), @r#"
61        Err(
62            InvalidSyntax {
63                message: "missing this",
64                syntax: "<this>.bytes()",
65            },
66        )
67        "#);
68
69        insta::assert_debug_snapshot!(Bytes.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant(CelValue::String("hi".into()))), &[])), @r"
70        Ok(
71            Constant(
72                ConstantCompiledExpr {
73                    value: Bytes(
74                        Borrowed(
75                            [
76                                104,
77                                105,
78                            ],
79                        ),
80                    ),
81                },
82            ),
83        )
84        ");
85
86        insta::assert_debug_snapshot!(Bytes.compile(CompilerCtx::new(compiler.child(), Some(CompiledExpr::constant(CelValue::List(Default::default()))), &[
87            cel_parser::parse("1 + 1").unwrap(), // not an ident
88        ])), @r#"
89        Err(
90            InvalidSyntax {
91                message: "takes no arguments",
92                syntax: "<this>.bytes()",
93            },
94        )
95        "#);
96    }
97
98    #[test]
99    #[cfg(not(valgrind))]
100    fn test_bytes_runtime() {
101        let registry = ProtoTypeRegistry::new(crate::Mode::Prost, ExternPaths::new(crate::Mode::Prost), PathSet::default());
102        let compiler = Compiler::new(&registry);
103
104        let string_value =
105            CompiledExpr::runtime(CelType::Proto(ProtoType::Value(ProtoValueType::String)), parse_quote!(input));
106
107        let output = Bytes
108            .compile(CompilerCtx::new(compiler.child(), Some(string_value), &[]))
109            .unwrap();
110
111        insta::assert_snapshot!(postcompile::compile_str!(
112            postcompile::config! {
113                test: true,
114                dependencies: vec![
115                    postcompile::Dependency::version("tinc", "*"),
116                ],
117            },
118            quote! {
119                fn to_bytes(input: &str) -> Result<::tinc::__private::cel::CelValue<'_>, ::tinc::__private::cel::CelError<'_>> {
120                    Ok(#output)
121                }
122
123                #[test]
124                fn test_to_bytes() {
125                    assert_eq!(to_bytes("some string").unwrap(), ::tinc::__private::cel::CelValueConv::conv(b"some string"));
126                }
127            },
128        ));
129    }
130}