Skip to main content

cel_core/checker/
standard_library.rs

1//! CEL standard library function declarations.
2//!
3//! This module defines all CEL operators and built-in functions with their
4//! type signatures and overload IDs matching cel-go conventions.
5
6use std::sync::LazyLock;
7
8use crate::types::{CelType, FunctionDecl, OverloadDecl};
9
10/// The CEL standard library containing all built-in operators and functions.
11pub static STANDARD_LIBRARY: LazyLock<Vec<FunctionDecl>> = LazyLock::new(build_standard_library);
12
13fn build_standard_library() -> Vec<FunctionDecl> {
14    let mut funcs = Vec::new();
15
16    // ==================== Operators ====================
17
18    // Arithmetic: _+_
19    funcs.push(
20        FunctionDecl::new("_+_")
21            .with_overload(OverloadDecl::function("add_int64_int64", vec![CelType::Int, CelType::Int], CelType::Int))
22            .with_overload(OverloadDecl::function("add_uint64_uint64", vec![CelType::UInt, CelType::UInt], CelType::UInt))
23            .with_overload(OverloadDecl::function("add_double_double", vec![CelType::Double, CelType::Double], CelType::Double))
24            .with_overload(OverloadDecl::function("add_string_string", vec![CelType::String, CelType::String], CelType::String))
25            .with_overload(OverloadDecl::function("add_bytes_bytes", vec![CelType::Bytes, CelType::Bytes], CelType::Bytes))
26            .with_overload(OverloadDecl::function(
27                "add_list_list",
28                vec![CelType::list(CelType::type_param("T")), CelType::list(CelType::type_param("T"))],
29                CelType::list(CelType::type_param("T")),
30            ).with_type_params(vec!["T".to_string()]))
31            .with_overload(OverloadDecl::function("add_timestamp_duration", vec![CelType::Timestamp, CelType::Duration], CelType::Timestamp))
32            .with_overload(OverloadDecl::function("add_duration_timestamp", vec![CelType::Duration, CelType::Timestamp], CelType::Timestamp))
33            .with_overload(OverloadDecl::function("add_duration_duration", vec![CelType::Duration, CelType::Duration], CelType::Duration)),
34    );
35
36    // Arithmetic: _-_
37    funcs.push(
38        FunctionDecl::new("_-_")
39            .with_overload(OverloadDecl::function("subtract_int64_int64", vec![CelType::Int, CelType::Int], CelType::Int))
40            .with_overload(OverloadDecl::function("subtract_uint64_uint64", vec![CelType::UInt, CelType::UInt], CelType::UInt))
41            .with_overload(OverloadDecl::function("subtract_double_double", vec![CelType::Double, CelType::Double], CelType::Double))
42            .with_overload(OverloadDecl::function("subtract_timestamp_timestamp", vec![CelType::Timestamp, CelType::Timestamp], CelType::Duration))
43            .with_overload(OverloadDecl::function("subtract_timestamp_duration", vec![CelType::Timestamp, CelType::Duration], CelType::Timestamp))
44            .with_overload(OverloadDecl::function("subtract_duration_duration", vec![CelType::Duration, CelType::Duration], CelType::Duration)),
45    );
46
47    // Arithmetic: _*_
48    funcs.push(
49        FunctionDecl::new("_*_")
50            .with_overload(OverloadDecl::function("multiply_int64_int64", vec![CelType::Int, CelType::Int], CelType::Int))
51            .with_overload(OverloadDecl::function("multiply_uint64_uint64", vec![CelType::UInt, CelType::UInt], CelType::UInt))
52            .with_overload(OverloadDecl::function("multiply_double_double", vec![CelType::Double, CelType::Double], CelType::Double)),
53    );
54
55    // Arithmetic: _/_
56    funcs.push(
57        FunctionDecl::new("_/_")
58            .with_overload(OverloadDecl::function("divide_int64_int64", vec![CelType::Int, CelType::Int], CelType::Int))
59            .with_overload(OverloadDecl::function("divide_uint64_uint64", vec![CelType::UInt, CelType::UInt], CelType::UInt))
60            .with_overload(OverloadDecl::function("divide_double_double", vec![CelType::Double, CelType::Double], CelType::Double)),
61    );
62
63    // Arithmetic: _%_
64    funcs.push(
65        FunctionDecl::new("_%_")
66            .with_overload(OverloadDecl::function("modulo_int64_int64", vec![CelType::Int, CelType::Int], CelType::Int))
67            .with_overload(OverloadDecl::function("modulo_uint64_uint64", vec![CelType::UInt, CelType::UInt], CelType::UInt)),
68    );
69
70    // Unary: -_
71    funcs.push(
72        FunctionDecl::new("-_")
73            .with_overload(OverloadDecl::function("negate_int64", vec![CelType::Int], CelType::Int))
74            .with_overload(OverloadDecl::function("negate_double", vec![CelType::Double], CelType::Double)),
75    );
76
77    // Comparison: _==_
78    funcs.push(
79        FunctionDecl::new("_==_")
80            .with_overload(OverloadDecl::function(
81                "equals",
82                vec![CelType::type_param("T"), CelType::type_param("T")],
83                CelType::Bool,
84            ).with_type_params(vec!["T".to_string()])),
85    );
86
87    // Comparison: _!=_
88    funcs.push(
89        FunctionDecl::new("_!=_")
90            .with_overload(OverloadDecl::function(
91                "not_equals",
92                vec![CelType::type_param("T"), CelType::type_param("T")],
93                CelType::Bool,
94            ).with_type_params(vec!["T".to_string()])),
95    );
96
97    // Comparison: _<_
98    funcs.push(
99        FunctionDecl::new("_<_")
100            .with_overload(OverloadDecl::function("less_bool", vec![CelType::Bool, CelType::Bool], CelType::Bool))
101            .with_overload(OverloadDecl::function("less_int64", vec![CelType::Int, CelType::Int], CelType::Bool))
102            .with_overload(OverloadDecl::function("less_uint64", vec![CelType::UInt, CelType::UInt], CelType::Bool))
103            .with_overload(OverloadDecl::function("less_double", vec![CelType::Double, CelType::Double], CelType::Bool))
104            .with_overload(OverloadDecl::function("less_string", vec![CelType::String, CelType::String], CelType::Bool))
105            .with_overload(OverloadDecl::function("less_bytes", vec![CelType::Bytes, CelType::Bytes], CelType::Bool))
106            .with_overload(OverloadDecl::function("less_timestamp", vec![CelType::Timestamp, CelType::Timestamp], CelType::Bool))
107            .with_overload(OverloadDecl::function("less_duration", vec![CelType::Duration, CelType::Duration], CelType::Bool)),
108    );
109
110    // Comparison: _<=_
111    funcs.push(
112        FunctionDecl::new("_<=_")
113            .with_overload(OverloadDecl::function("less_equals_bool", vec![CelType::Bool, CelType::Bool], CelType::Bool))
114            .with_overload(OverloadDecl::function("less_equals_int64", vec![CelType::Int, CelType::Int], CelType::Bool))
115            .with_overload(OverloadDecl::function("less_equals_uint64", vec![CelType::UInt, CelType::UInt], CelType::Bool))
116            .with_overload(OverloadDecl::function("less_equals_double", vec![CelType::Double, CelType::Double], CelType::Bool))
117            .with_overload(OverloadDecl::function("less_equals_string", vec![CelType::String, CelType::String], CelType::Bool))
118            .with_overload(OverloadDecl::function("less_equals_bytes", vec![CelType::Bytes, CelType::Bytes], CelType::Bool))
119            .with_overload(OverloadDecl::function("less_equals_timestamp", vec![CelType::Timestamp, CelType::Timestamp], CelType::Bool))
120            .with_overload(OverloadDecl::function("less_equals_duration", vec![CelType::Duration, CelType::Duration], CelType::Bool)),
121    );
122
123    // Comparison: _>_
124    funcs.push(
125        FunctionDecl::new("_>_")
126            .with_overload(OverloadDecl::function("greater_bool", vec![CelType::Bool, CelType::Bool], CelType::Bool))
127            .with_overload(OverloadDecl::function("greater_int64", vec![CelType::Int, CelType::Int], CelType::Bool))
128            .with_overload(OverloadDecl::function("greater_uint64", vec![CelType::UInt, CelType::UInt], CelType::Bool))
129            .with_overload(OverloadDecl::function("greater_double", vec![CelType::Double, CelType::Double], CelType::Bool))
130            .with_overload(OverloadDecl::function("greater_string", vec![CelType::String, CelType::String], CelType::Bool))
131            .with_overload(OverloadDecl::function("greater_bytes", vec![CelType::Bytes, CelType::Bytes], CelType::Bool))
132            .with_overload(OverloadDecl::function("greater_timestamp", vec![CelType::Timestamp, CelType::Timestamp], CelType::Bool))
133            .with_overload(OverloadDecl::function("greater_duration", vec![CelType::Duration, CelType::Duration], CelType::Bool)),
134    );
135
136    // Comparison: _>=_
137    funcs.push(
138        FunctionDecl::new("_>=_")
139            .with_overload(OverloadDecl::function("greater_equals_bool", vec![CelType::Bool, CelType::Bool], CelType::Bool))
140            .with_overload(OverloadDecl::function("greater_equals_int64", vec![CelType::Int, CelType::Int], CelType::Bool))
141            .with_overload(OverloadDecl::function("greater_equals_uint64", vec![CelType::UInt, CelType::UInt], CelType::Bool))
142            .with_overload(OverloadDecl::function("greater_equals_double", vec![CelType::Double, CelType::Double], CelType::Bool))
143            .with_overload(OverloadDecl::function("greater_equals_string", vec![CelType::String, CelType::String], CelType::Bool))
144            .with_overload(OverloadDecl::function("greater_equals_bytes", vec![CelType::Bytes, CelType::Bytes], CelType::Bool))
145            .with_overload(OverloadDecl::function("greater_equals_timestamp", vec![CelType::Timestamp, CelType::Timestamp], CelType::Bool))
146            .with_overload(OverloadDecl::function("greater_equals_duration", vec![CelType::Duration, CelType::Duration], CelType::Bool)),
147    );
148
149    // Logical: _&&_
150    funcs.push(
151        FunctionDecl::new("_&&_")
152            .with_overload(OverloadDecl::function("logical_and", vec![CelType::Bool, CelType::Bool], CelType::Bool)),
153    );
154
155    // Logical: _||_
156    funcs.push(
157        FunctionDecl::new("_||_")
158            .with_overload(OverloadDecl::function("logical_or", vec![CelType::Bool, CelType::Bool], CelType::Bool)),
159    );
160
161    // Logical: !_
162    funcs.push(
163        FunctionDecl::new("!_")
164            .with_overload(OverloadDecl::function("logical_not", vec![CelType::Bool], CelType::Bool)),
165    );
166
167    // Ternary: _?_:_
168    funcs.push(
169        FunctionDecl::new("_?_:_")
170            .with_overload(OverloadDecl::function(
171                "conditional",
172                vec![CelType::Bool, CelType::type_param("T"), CelType::type_param("T")],
173                CelType::type_param("T"),
174            ).with_type_params(vec!["T".to_string()])),
175    );
176
177    // Membership: _in_
178    funcs.push(
179        FunctionDecl::new("@in")
180            .with_overload(OverloadDecl::function(
181                "in_list",
182                vec![CelType::type_param("T"), CelType::list(CelType::type_param("T"))],
183                CelType::Bool,
184            ).with_type_params(vec!["T".to_string()]))
185            .with_overload(OverloadDecl::function(
186                "in_map",
187                vec![CelType::type_param("K"), CelType::map(CelType::type_param("K"), CelType::type_param("V"))],
188                CelType::Bool,
189            ).with_type_params(vec!["K".to_string(), "V".to_string()])),
190    );
191
192    // Index: _[_]
193    funcs.push(
194        FunctionDecl::new("_[_]")
195            .with_overload(OverloadDecl::function(
196                "index_list",
197                vec![CelType::list(CelType::type_param("T")), CelType::Int],
198                CelType::type_param("T"),
199            ).with_type_params(vec!["T".to_string()]))
200            .with_overload(OverloadDecl::function(
201                "index_map",
202                vec![CelType::map(CelType::type_param("K"), CelType::type_param("V")), CelType::type_param("K")],
203                CelType::type_param("V"),
204            ).with_type_params(vec!["K".to_string(), "V".to_string()])),
205    );
206
207    // ==================== Type Conversions ====================
208
209    funcs.push(
210        FunctionDecl::new("bool")
211            .with_overload(OverloadDecl::function("bool_to_bool", vec![CelType::Bool], CelType::Bool))
212            .with_overload(OverloadDecl::function("string_to_bool", vec![CelType::String], CelType::Bool)),
213    );
214
215    funcs.push(
216        FunctionDecl::new("bytes")
217            .with_overload(OverloadDecl::function("bytes_to_bytes", vec![CelType::Bytes], CelType::Bytes))
218            .with_overload(OverloadDecl::function("string_to_bytes", vec![CelType::String], CelType::Bytes)),
219    );
220
221    funcs.push(
222        FunctionDecl::new("double")
223            .with_overload(OverloadDecl::function("double_to_double", vec![CelType::Double], CelType::Double))
224            .with_overload(OverloadDecl::function("int_to_double", vec![CelType::Int], CelType::Double))
225            .with_overload(OverloadDecl::function("uint_to_double", vec![CelType::UInt], CelType::Double))
226            .with_overload(OverloadDecl::function("string_to_double", vec![CelType::String], CelType::Double)),
227    );
228
229    funcs.push(
230        FunctionDecl::new("duration")
231            .with_overload(OverloadDecl::function("duration_to_duration", vec![CelType::Duration], CelType::Duration))
232            .with_overload(OverloadDecl::function("string_to_duration", vec![CelType::String], CelType::Duration)),
233    );
234
235    funcs.push(
236        FunctionDecl::new("dyn")
237            .with_overload(OverloadDecl::function(
238                "to_dyn",
239                vec![CelType::type_param("T")],
240                CelType::Dyn,
241            ).with_type_params(vec!["T".to_string()])),
242    );
243
244    funcs.push(
245        FunctionDecl::new("int")
246            .with_overload(OverloadDecl::function("int_to_int", vec![CelType::Int], CelType::Int))
247            .with_overload(OverloadDecl::function("uint_to_int", vec![CelType::UInt], CelType::Int))
248            .with_overload(OverloadDecl::function("double_to_int", vec![CelType::Double], CelType::Int))
249            .with_overload(OverloadDecl::function("string_to_int", vec![CelType::String], CelType::Int))
250            .with_overload(OverloadDecl::function("timestamp_to_int", vec![CelType::Timestamp], CelType::Int)),
251    );
252
253    funcs.push(
254        FunctionDecl::new("string")
255            .with_overload(OverloadDecl::function("string_to_string", vec![CelType::String], CelType::String))
256            .with_overload(OverloadDecl::function("bool_to_string", vec![CelType::Bool], CelType::String))
257            .with_overload(OverloadDecl::function("int_to_string", vec![CelType::Int], CelType::String))
258            .with_overload(OverloadDecl::function("uint_to_string", vec![CelType::UInt], CelType::String))
259            .with_overload(OverloadDecl::function("double_to_string", vec![CelType::Double], CelType::String))
260            .with_overload(OverloadDecl::function("bytes_to_string", vec![CelType::Bytes], CelType::String))
261            .with_overload(OverloadDecl::function("timestamp_to_string", vec![CelType::Timestamp], CelType::String))
262            .with_overload(OverloadDecl::function("duration_to_string", vec![CelType::Duration], CelType::String)),
263    );
264
265    funcs.push(
266        FunctionDecl::new("timestamp")
267            .with_overload(OverloadDecl::function("timestamp_to_timestamp", vec![CelType::Timestamp], CelType::Timestamp))
268            .with_overload(OverloadDecl::function("string_to_timestamp", vec![CelType::String], CelType::Timestamp))
269            .with_overload(OverloadDecl::function("int_to_timestamp", vec![CelType::Int], CelType::Timestamp)),
270    );
271
272    funcs.push(
273        FunctionDecl::new("type")
274            .with_overload(OverloadDecl::function(
275                "type",
276                vec![CelType::type_param("T")],
277                CelType::type_of(CelType::type_param("T")),
278            ).with_type_params(vec!["T".to_string()])),
279    );
280
281    funcs.push(
282        FunctionDecl::new("uint")
283            .with_overload(OverloadDecl::function("uint_to_uint", vec![CelType::UInt], CelType::UInt))
284            .with_overload(OverloadDecl::function("int_to_uint", vec![CelType::Int], CelType::UInt))
285            .with_overload(OverloadDecl::function("double_to_uint", vec![CelType::Double], CelType::UInt))
286            .with_overload(OverloadDecl::function("string_to_uint", vec![CelType::String], CelType::UInt)),
287    );
288
289    // ==================== Size ====================
290
291    funcs.push(
292        FunctionDecl::new("size")
293            .with_overload(OverloadDecl::function("size_string", vec![CelType::String], CelType::Int))
294            .with_overload(OverloadDecl::function("size_bytes", vec![CelType::Bytes], CelType::Int))
295            .with_overload(OverloadDecl::function(
296                "size_list",
297                vec![CelType::list(CelType::type_param("T"))],
298                CelType::Int,
299            ).with_type_params(vec!["T".to_string()]))
300            .with_overload(OverloadDecl::function(
301                "size_map",
302                vec![CelType::map(CelType::type_param("K"), CelType::type_param("V"))],
303                CelType::Int,
304            ).with_type_params(vec!["K".to_string(), "V".to_string()]))
305            // Method overloads
306            .with_overload(OverloadDecl::method("string_size", vec![CelType::String], CelType::Int))
307            .with_overload(OverloadDecl::method("bytes_size", vec![CelType::Bytes], CelType::Int))
308            .with_overload(OverloadDecl::method(
309                "list_size",
310                vec![CelType::list(CelType::type_param("T"))],
311                CelType::Int,
312            ).with_type_params(vec!["T".to_string()]))
313            .with_overload(OverloadDecl::method(
314                "map_size",
315                vec![CelType::map(CelType::type_param("K"), CelType::type_param("V"))],
316                CelType::Int,
317            ).with_type_params(vec!["K".to_string(), "V".to_string()])),
318    );
319
320    // ==================== String Functions ====================
321
322    funcs.push(
323        FunctionDecl::new("contains")
324            .with_overload(OverloadDecl::method("string_contains_string", vec![CelType::String, CelType::String], CelType::Bool)),
325    );
326
327    funcs.push(
328        FunctionDecl::new("endsWith")
329            .with_overload(OverloadDecl::method("string_ends_with_string", vec![CelType::String, CelType::String], CelType::Bool)),
330    );
331
332    funcs.push(
333        FunctionDecl::new("startsWith")
334            .with_overload(OverloadDecl::method("string_starts_with_string", vec![CelType::String, CelType::String], CelType::Bool)),
335    );
336
337    funcs.push(
338        FunctionDecl::new("matches")
339            .with_overload(OverloadDecl::function("matches_string_re", vec![CelType::String, CelType::String], CelType::Bool))
340            .with_overload(OverloadDecl::method("string_matches_re", vec![CelType::String, CelType::String], CelType::Bool)),
341    );
342
343    // ==================== Timestamp/Duration Accessors ====================
344
345    let timestamp_accessors = [
346        "getDate", "getDayOfMonth", "getDayOfWeek", "getDayOfYear",
347        "getFullYear", "getMonth",
348    ];
349
350    for name in timestamp_accessors {
351        let base_id = name.to_lowercase().replace("get", "").to_lowercase();
352        funcs.push(
353            FunctionDecl::new(name)
354                .with_overload(OverloadDecl::method(
355                    format!("timestamp_to_{}", base_id),
356                    vec![CelType::Timestamp],
357                    CelType::Int,
358                ))
359                .with_overload(OverloadDecl::method(
360                    format!("timestamp_to_{}_with_tz", base_id),
361                    vec![CelType::Timestamp, CelType::String],
362                    CelType::Int,
363                )),
364        );
365    }
366
367    // Accessors for both timestamp and duration
368    let time_accessors = ["getHours", "getMinutes", "getSeconds", "getMilliseconds"];
369
370    for name in time_accessors {
371        let base_id = name.to_lowercase().replace("get", "").to_lowercase();
372        funcs.push(
373            FunctionDecl::new(name)
374                .with_overload(OverloadDecl::method(
375                    format!("timestamp_to_{}", base_id),
376                    vec![CelType::Timestamp],
377                    CelType::Int,
378                ))
379                .with_overload(OverloadDecl::method(
380                    format!("timestamp_to_{}_with_tz", base_id),
381                    vec![CelType::Timestamp, CelType::String],
382                    CelType::Int,
383                ))
384                .with_overload(OverloadDecl::method(
385                    format!("duration_to_{}", base_id),
386                    vec![CelType::Duration],
387                    CelType::Int,
388                )),
389        );
390    }
391
392    funcs
393}
394
395/// Get a function declaration by name from the standard library.
396#[allow(dead_code)]
397pub fn get_standard_function(name: &str) -> Option<&'static FunctionDecl> {
398    STANDARD_LIBRARY.iter().find(|f| f.name == name)
399}
400
401#[cfg(test)]
402mod tests {
403    use super::*;
404
405    #[test]
406    fn test_standard_library_loads() {
407        assert!(!STANDARD_LIBRARY.is_empty());
408    }
409
410    #[test]
411    fn test_add_operator() {
412        let add = get_standard_function("_+_").unwrap();
413        assert!(add.overloads.len() >= 4);
414        assert!(add.overloads.iter().any(|o| o.id == "add_int64_int64"));
415        assert!(add.overloads.iter().any(|o| o.id == "add_string_string"));
416    }
417
418    #[test]
419    fn test_comparison_operators() {
420        assert!(get_standard_function("_==_").is_some());
421        assert!(get_standard_function("_!=_").is_some());
422        assert!(get_standard_function("_<_").is_some());
423        assert!(get_standard_function("_<=_").is_some());
424        assert!(get_standard_function("_>_").is_some());
425        assert!(get_standard_function("_>=_").is_some());
426    }
427
428    #[test]
429    fn test_logical_operators() {
430        assert!(get_standard_function("_&&_").is_some());
431        assert!(get_standard_function("_||_").is_some());
432        assert!(get_standard_function("!_").is_some());
433    }
434
435    #[test]
436    fn test_size_has_both_standalone_and_method() {
437        let size = get_standard_function("size").unwrap();
438        assert!(size.has_standalone_overloads());
439        assert!(size.has_member_overloads());
440    }
441
442    #[test]
443    fn test_contains_is_method_only() {
444        let contains = get_standard_function("contains").unwrap();
445        assert!(!contains.has_standalone_overloads());
446        assert!(contains.has_member_overloads());
447    }
448
449    #[test]
450    fn test_type_conversions() {
451        assert!(get_standard_function("bool").is_some());
452        assert!(get_standard_function("int").is_some());
453        assert!(get_standard_function("uint").is_some());
454        assert!(get_standard_function("double").is_some());
455        assert!(get_standard_function("string").is_some());
456        assert!(get_standard_function("bytes").is_some());
457        assert!(get_standard_function("timestamp").is_some());
458        assert!(get_standard_function("duration").is_some());
459        assert!(get_standard_function("dyn").is_some());
460        assert!(get_standard_function("type").is_some());
461    }
462
463    #[test]
464    fn test_timestamp_accessors() {
465        assert!(get_standard_function("getDate").is_some());
466        assert!(get_standard_function("getHours").is_some());
467        assert!(get_standard_function("getMinutes").is_some());
468    }
469}