tinc_build/codegen/cel/
mod.rs1use std::collections::HashMap;
2
3use anyhow::Context;
4use compiler::{CompiledExpr, CompilerCtx, ConstantCompiledExpr, RuntimeCompiledExpr};
5use functions::Function;
6use proc_macro2::TokenStream;
7use quote::{format_ident, quote};
8use tinc_cel::CelValue;
9
10pub(crate) mod compiler;
11pub(crate) mod functions;
12pub(crate) mod types;
13
14pub(crate) fn eval_message_fmt(
15 field_full_name: &str,
16 msg: &str,
17 ctx: &compiler::Compiler<'_>,
18) -> anyhow::Result<TokenStream> {
19 let fmt = runtime_format::ParsedFmt::new(msg).map_err(|err| anyhow::anyhow!("failed to parse message format: {err}"))?;
20
21 let mut runtime_args = Vec::new();
22 let mut compile_time_args = HashMap::new();
23
24 for key in fmt.keys() {
26 let expr = cel_parser::parse(key).context("failed to parse cel expression")?;
27 match functions::String.compile(CompilerCtx::new(ctx.child(), Some(ctx.resolve(&expr)?), &[]))? {
28 CompiledExpr::Constant(ConstantCompiledExpr { value }) => {
29 compile_time_args.insert(key, value);
31 }
32 CompiledExpr::Runtime(RuntimeCompiledExpr { expr, .. }) => {
33 let ident = format_ident!("arg_{}", runtime_args.len());
34 compile_time_args.insert(key, CelValue::String(format!("{{{ident}}}").into()));
35 runtime_args.push((key, ident, expr));
36 }
37 }
38 }
39
40 let fmt = fmt.with_args(&compile_time_args).to_string();
41
42 if runtime_args.is_empty() {
43 Ok(quote!(#fmt))
44 } else {
45 let args = runtime_args.iter().map(|(key, ident, expr)| {
46 quote! {
47 #ident = (
48 || {
49 ::core::result::Result::Ok::<_, ::tinc::__private::cel::CelError>(#expr)
50 }
51 )().map_err(|err| {
52 ::tinc::__private::ValidationError::Expression {
53 error: err.to_string().into_boxed_str(),
54 field: #field_full_name,
55 expression: #key,
56 }
57 })?
58 }
59 });
60
61 Ok(quote!(format!(#fmt, #(#args),*)))
62 }
63}
64
65#[derive(Debug, Clone, PartialEq)]
66pub(crate) struct CelExpression {
67 pub message: String,
68 pub expression: String,
69 pub jsonschemas: Vec<String>,
70 pub this: Option<CelValue<'static>>,
71}
72
73#[derive(Debug, PartialEq, Clone, Default)]
74pub(crate) struct CelExpressions {
75 pub field: Vec<CelExpression>,
76 pub map_key: Vec<CelExpression>,
77 pub map_value: Vec<CelExpression>,
78 pub repeated_item: Vec<CelExpression>,
79}