tinc_build/codegen/cel/compiler/
helpers.rs

1use syn::parse_quote;
2use tinc_cel::CelValue;
3
4use super::{CompileError, CompiledExpr, Compiler, ConstantCompiledExpr, RuntimeCompiledExpr};
5use crate::codegen::cel::types::CelType;
6use crate::types::{ProtoModifiedValueType, ProtoType, ProtoValueType, ProtoWellKnownType};
7
8impl CompiledExpr {
9    pub(crate) fn into_bool(self, compiler: &Compiler) -> CompiledExpr {
10        match &self {
11            CompiledExpr::Runtime(RuntimeCompiledExpr {
12                expr,
13                ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::OneOf(_))),
14            }) => CompiledExpr::Runtime(RuntimeCompiledExpr {
15                expr: parse_quote! { (#expr).is_some() },
16                ty: CelType::Proto(ProtoType::Value(ProtoValueType::Bool)),
17            }),
18            CompiledExpr::Runtime(RuntimeCompiledExpr {
19                expr,
20                ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::Optional(ty))),
21            }) => {
22                let value_to_bool = CompiledExpr::Runtime(RuntimeCompiledExpr {
23                    expr: parse_quote! { ___to_bool_value },
24                    ty: CelType::Proto(ProtoType::Value(ty.clone())),
25                })
26                .into_bool(compiler);
27
28                CompiledExpr::Runtime(RuntimeCompiledExpr {
29                    expr: parse_quote! {
30                        match #expr {
31                            Some(___to_bool_value) => #value_to_bool,
32                            None => false,
33                        }
34                    },
35                    ty: CelType::Proto(ProtoType::Value(ProtoValueType::Bool)),
36                })
37            }
38            CompiledExpr::Runtime(RuntimeCompiledExpr {
39                ty: CelType::Proto(ProtoType::Value(ProtoValueType::Message { .. })),
40                ..
41            }) => CompiledExpr::Constant(ConstantCompiledExpr {
42                value: tinc_cel::CelValue::Bool(true),
43            }),
44            CompiledExpr::Runtime(RuntimeCompiledExpr { expr, .. }) => CompiledExpr::Runtime(RuntimeCompiledExpr {
45                expr: parse_quote! {
46                    ::tinc::__private::cel::to_bool(#expr)
47                },
48                ty: CelType::Proto(ProtoType::Value(ProtoValueType::Bool)),
49            }),
50            CompiledExpr::Constant(ConstantCompiledExpr {
51                value: CelValue::Enum(cel_enum),
52            }) => CompiledExpr::Constant(ConstantCompiledExpr {
53                value: tinc_cel::CelValue::Bool(
54                    compiler
55                        .registry
56                        .get_enum(&cel_enum.tag)
57                        .is_some_and(|e| e.variants.values().any(|v| v.value == cel_enum.value)),
58                ),
59            }),
60            CompiledExpr::Constant(ConstantCompiledExpr { value }) => CompiledExpr::Constant(ConstantCompiledExpr {
61                value: tinc_cel::CelValue::Bool(value.to_bool()),
62            }),
63        }
64    }
65
66    pub(crate) fn into_cel(self) -> Result<CompiledExpr, CompileError> {
67        match self {
68            CompiledExpr::Runtime(RuntimeCompiledExpr {
69                expr,
70                ty: ty @ CelType::CelValue,
71            }) => Ok(CompiledExpr::Runtime(RuntimeCompiledExpr { expr, ty })),
72            CompiledExpr::Runtime(RuntimeCompiledExpr {
73                expr,
74                ty:
75                    CelType::Proto(ProtoType::Value(
76                        ProtoValueType::Bool
77                        | ProtoValueType::Bytes
78                        | ProtoValueType::Double
79                        | ProtoValueType::Float
80                        | ProtoValueType::Int32
81                        | ProtoValueType::Int64
82                        | ProtoValueType::String
83                        | ProtoValueType::UInt32
84                        | ProtoValueType::UInt64
85                        | ProtoValueType::WellKnown(
86                            ProtoWellKnownType::Duration
87                            | ProtoWellKnownType::Empty
88                            | ProtoWellKnownType::ListValue
89                            | ProtoWellKnownType::Struct
90                            | ProtoWellKnownType::Timestamp
91                            | ProtoWellKnownType::Value,
92                        ),
93                    )),
94            }) => Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
95                expr: parse_quote! {
96                    ::tinc::__private::cel::CelValueConv::conv(#expr)
97                },
98                ty: CelType::CelValue,
99            })),
100            CompiledExpr::Runtime(RuntimeCompiledExpr {
101                expr,
102                ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::Map(key_ty, value_ty))),
103            }) => {
104                let key_to_cel = CompiledExpr::Runtime(RuntimeCompiledExpr {
105                    expr: parse_quote!(key),
106                    ty: CelType::Proto(ProtoType::Value(key_ty)),
107                })
108                .into_cel()?;
109
110                let value_to_cel = CompiledExpr::Runtime(RuntimeCompiledExpr {
111                    expr: parse_quote!(value),
112                    ty: CelType::Proto(ProtoType::Value(value_ty)),
113                })
114                .into_cel()?;
115
116                Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
117                    expr: parse_quote! {
118                        ::tinc::__private::cel::CelValue::Map(
119                            (#expr).into_iter().map(|(key, value)| {
120                                (
121                                    #key_to_cel,
122                                    #value_to_cel,
123                                )
124                            }).collect()
125                        )
126                    },
127                    ty: CelType::CelValue,
128                }))
129            }
130            CompiledExpr::Runtime(RuntimeCompiledExpr {
131                expr,
132                ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::Optional(some_ty))),
133            }) => {
134                let some_to_cel = CompiledExpr::Runtime(RuntimeCompiledExpr {
135                    expr: parse_quote!(item),
136                    ty: CelType::Proto(ProtoType::Value(some_ty)),
137                })
138                .into_cel()?;
139
140                Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
141                    expr: parse_quote! {{
142                        match (#expr) {
143                            ::core::option::Option::Some(item) => #some_to_cel,
144                            ::core::option::Option::None => ::tinc::__private::cel::CelValue::Null,
145                        }
146                    }},
147                    ty: CelType::CelValue,
148                }))
149            }
150            CompiledExpr::Runtime(RuntimeCompiledExpr {
151                expr,
152                ty: CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::Repeated(item_ty))),
153            }) => {
154                let item_to_cel = CompiledExpr::Runtime(RuntimeCompiledExpr {
155                    expr: parse_quote!(item),
156                    ty: CelType::Proto(ProtoType::Value(item_ty)),
157                })
158                .into_cel()?;
159
160                Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
161                    expr: parse_quote! {
162                        ::tinc::__private::cel::CelValue::List((#expr).into_iter().map(|item| #item_to_cel).collect())
163                    },
164                    ty: CelType::CelValue,
165                }))
166            }
167            CompiledExpr::Runtime(RuntimeCompiledExpr {
168                expr,
169                ty: CelType::Proto(ProtoType::Value(ProtoValueType::Enum(path))),
170            }) => {
171                let path = path.as_ref();
172                Ok(CompiledExpr::Runtime(RuntimeCompiledExpr {
173                    expr: parse_quote! {
174                        ::tinc::__private::cel::CelValue::cel_to_enum(
175                            #expr,
176                            #path,
177                        )?
178                    },
179                    ty: CelType::CelValue,
180                }))
181            }
182            // Not sure how to represent oneofs in cel.
183            CompiledExpr::Runtime(RuntimeCompiledExpr {
184                ty: ty @ CelType::Proto(ProtoType::Modified(ProtoModifiedValueType::OneOf(_))),
185                ..
186            }) => Err(CompileError::TypeConversion {
187                ty: Box::new(ty),
188                message: "oneofs cannot be converted into cel types".into(),
189            }),
190            // Nor messages
191            CompiledExpr::Runtime(RuntimeCompiledExpr {
192                ty: ty @ CelType::Proto(ProtoType::Value(ProtoValueType::Message(_))),
193                ..
194            }) => Err(CompileError::TypeConversion {
195                ty: Box::new(ty),
196                message: "message types cannot be converted into cel types".into(),
197            }),
198            // Currently any is not supported.
199            CompiledExpr::Runtime(RuntimeCompiledExpr {
200                ty: ty @ CelType::Proto(ProtoType::Value(ProtoValueType::WellKnown(ProtoWellKnownType::Any))),
201                ..
202            }) => Err(CompileError::TypeConversion {
203                ty: Box::new(ty),
204                message: "any cannot be converted into cel types".into(),
205            }),
206            CompiledExpr::Constant(c) => Ok(CompiledExpr::Constant(c)),
207        }
208    }
209}