pub struct Program { /* private fields */ }Expand description
A compiled CEL program ready for evaluation.
The program holds a reference to the AST and a function registry, providing a convenient interface for evaluating the expression against different variable bindings.
Implementations§
Source§impl Program
impl Program
Sourcepub fn new(ast: Arc<Ast>, functions: Arc<FunctionRegistry>) -> Self
pub fn new(ast: Arc<Ast>, functions: Arc<FunctionRegistry>) -> Self
Create a new program from an AST and function registry.
Sourcepub fn with_proto_registry(
ast: Arc<Ast>,
functions: Arc<FunctionRegistry>,
proto_registry: Arc<dyn ProtoRegistry>,
) -> Self
pub fn with_proto_registry( ast: Arc<Ast>, functions: Arc<FunctionRegistry>, proto_registry: Arc<dyn ProtoRegistry>, ) -> Self
Create a new program with a type registry.
Sourcepub fn with_abbreviations(
ast: Arc<Ast>,
functions: Arc<FunctionRegistry>,
abbreviations: HashMap<String, String>,
) -> Self
pub fn with_abbreviations( ast: Arc<Ast>, functions: Arc<FunctionRegistry>, abbreviations: HashMap<String, String>, ) -> Self
Create a new program with abbreviations.
Sourcepub fn with_proto_registry_and_abbreviations(
ast: Arc<Ast>,
functions: Arc<FunctionRegistry>,
proto_registry: Arc<dyn ProtoRegistry>,
abbreviations: HashMap<String, String>,
) -> Self
pub fn with_proto_registry_and_abbreviations( ast: Arc<Ast>, functions: Arc<FunctionRegistry>, proto_registry: Arc<dyn ProtoRegistry>, abbreviations: HashMap<String, String>, ) -> Self
Create a new program with a type registry and abbreviations.
Sourcepub fn with_legacy_enums(self) -> Self
pub fn with_legacy_enums(self) -> Self
Use legacy (weak) enum mode where enum values are returned as plain integers.
Sourcepub fn eval(&self, activation: &dyn Activation) -> Value
pub fn eval(&self, activation: &dyn Activation) -> Value
Evaluate the program with the given variable bindings.
Examples found in repository?
7fn main() {
8 let env = Env::with_standard_library().with_variable("name", CelType::String);
9
10 let ast = env.compile(r#""Hello, " + name + "!""#).unwrap();
11 let program = env.program(&ast).unwrap();
12
13 let mut activation = MapActivation::new();
14 activation.insert("name", "World");
15
16 let result = program.eval(&activation);
17 println!("{}", result);
18}More examples
7fn main() {
8 // 1. Create an environment with the standard library and declare variables
9 let env = Env::with_standard_library()
10 .with_variable("user", CelType::String)
11 .with_variable("age", CelType::Int);
12
13 // 2. Compile the expression (parse + type-check)
14 let ast = env
15 .compile("age >= 21 && user.startsWith('admin')")
16 .unwrap();
17
18 // 3. Create a program from the compiled AST
19 let program = env.program(&ast).unwrap();
20
21 // 4. Set up variable bindings for evaluation
22 let mut activation = MapActivation::new();
23 activation.insert("user", "admin_alice"); // &str converts automatically
24 activation.insert("age", 25); // integers widen automatically
25
26 // 5. Evaluate the expression
27 let result = program.eval(&activation);
28 assert_eq!(result, Value::Bool(true));
29
30 println!("Expression: age >= 21 && user.startsWith('admin')");
31 println!("Result: {}", result);
32}7fn main() {
8 let env = Env::with_standard_library().with_variable("numbers", CelType::list(CelType::Int));
9
10 let mut activation = MapActivation::new();
11 activation.insert("numbers", Value::list([1, 5, 3, 8, 2]));
12
13 // Filter: keep only values > 3
14 let ast = env.compile("numbers.filter(x, x > 3)").unwrap();
15 let program = env.program(&ast).unwrap();
16 let result = program.eval(&activation);
17 println!("filter(x, x > 3): {}", result);
18
19 // Map: double each value
20 let ast = env.compile("numbers.map(x, x * 2)").unwrap();
21 let program = env.program(&ast).unwrap();
22 let result = program.eval(&activation);
23 println!("map(x, x * 2): {}", result);
24
25 // Exists: any value > 7?
26 let ast = env.compile("numbers.exists(x, x > 7)").unwrap();
27 let program = env.program(&ast).unwrap();
28 let result = program.eval(&activation);
29 println!("exists(x, x > 7): {}", result);
30
31 // All: all values > 0?
32 let ast = env.compile("numbers.all(x, x > 0)").unwrap();
33 let program = env.program(&ast).unwrap();
34 let result = program.eval(&activation);
35 println!("all(x, x > 0): {}", result);
36
37 // Size
38 let ast = env.compile("numbers.size()").unwrap();
39 let program = env.program(&ast).unwrap();
40 let result = program.eval(&activation);
41 println!("size(): {}", result);
42
43 // Contains (using 'in' operator)
44 let ast = env.compile("5 in numbers").unwrap();
45 let program = env.program(&ast).unwrap();
46 let result = program.eval(&activation);
47 println!("5 in numbers: {}", result);
48}7fn main() {
8 let env = Env::with_standard_library()
9 .with_variable("user", CelType::map(CelType::String, CelType::Dyn));
10
11 // Mixed value types require explicit Value::from()
12 let user = Value::map([
13 ("name", Value::from("Alice")),
14 ("age", Value::from(30)), // i32 automatically widens to i64
15 ("active", Value::from(true)),
16 ]);
17
18 let mut activation = MapActivation::new();
19 activation.insert("user", user);
20
21 // Field access
22 let ast = env.compile("user.name").unwrap();
23 let program = env.program(&ast).unwrap();
24 let result = program.eval(&activation);
25 println!("user.name: {}", result);
26
27 // Index access
28 let ast = env.compile(r#"user["age"]"#).unwrap();
29 let program = env.program(&ast).unwrap();
30 let result = program.eval(&activation);
31 println!(r#"user["age"]: {}"#, result);
32
33 // Check field existence with 'in'
34 let ast = env.compile(r#""name" in user"#).unwrap();
35 let program = env.program(&ast).unwrap();
36 let result = program.eval(&activation);
37 println!(r#""name" in user: {}"#, result);
38
39 // Check field existence with has()
40 let ast = env.compile("has(user.email)").unwrap();
41 let program = env.program(&ast).unwrap();
42 let result = program.eval(&activation);
43 println!("has(user.email): {}", result);
44
45 // Combine conditions
46 let ast = env.compile(r#"user.active && user.age >= 21"#).unwrap();
47 let program = env.program(&ast).unwrap();
48 let result = program.eval(&activation);
49 println!("active && age >= 21: {}", result);
50}7fn main() {
8 let env = Env::with_standard_library()
9 .with_variable("x", CelType::Int)
10 .with_variable("items", CelType::list(CelType::Int));
11
12 let mut activation = MapActivation::new();
13
14 // Division by zero returns an error value
15 println!("=== Division by zero ===");
16 activation.insert("x", 0);
17 let ast = env.compile("10 / x").unwrap();
18 let program = env.program(&ast).unwrap();
19 let result = program.eval(&activation);
20
21 match &result {
22 Value::Error(err) => println!("Error: {}", err),
23 other => println!("Result: {}", other),
24 }
25
26 // Index out of bounds
27 println!("\n=== Index out of bounds ===");
28 activation.insert("items", Value::list([1, 2, 3]));
29 let ast = env.compile("items[10]").unwrap();
30 let program = env.program(&ast).unwrap();
31 let result = program.eval(&activation);
32
33 match &result {
34 Value::Error(err) => println!("Error: {}", err),
35 other => println!("Result: {}", other),
36 }
37
38 // Key not found in map
39 println!("\n=== Key not found ===");
40 let env = Env::with_standard_library()
41 .with_variable("config", CelType::map(CelType::String, CelType::String));
42 let mut activation = MapActivation::new();
43 activation.insert("config", Value::map([("host", "localhost")]));
44
45 let ast = env.compile("config.missing_key").unwrap();
46 let program = env.program(&ast).unwrap();
47 let result = program.eval(&activation);
48
49 match &result {
50 Value::Error(err) => println!("Error: {}", err),
51 other => println!("Result: {}", other),
52 }
53
54 // Use has() to safely check field existence
55 println!("\n=== Safe field access with has() ===");
56 let ast = env
57 .compile("has(config.missing_key) ? config.missing_key : 'default'")
58 .unwrap();
59 let program = env.program(&ast).unwrap();
60 let result = program.eval(&activation);
61 println!("Result: {}", result);
62}7fn main() {
8 let env = Env::with_standard_library()
9 .with_variable("count", CelType::Int)
10 .with_variable("items", CelType::list(CelType::Int))
11 .with_variable("config", CelType::map(CelType::String, CelType::String));
12
13 let mut activation = MapActivation::new();
14 activation.insert("count", 42); // i32 automatically widens to i64
15 activation.insert("items", Value::list([1, 2, 3]));
16 activation.insert(
17 "config",
18 Value::map([("host", "localhost"), ("port", "8080")]),
19 );
20
21 // Extract i64
22 let ast = env.compile("count * 2").unwrap();
23 let program = env.program(&ast).unwrap();
24 let result = program.eval(&activation);
25
26 let value: i64 = (&result).try_into().expect("expected int");
27 println!("i64: {}", value);
28
29 // Extract bool
30 let ast = env.compile("count > 10").unwrap();
31 let program = env.program(&ast).unwrap();
32 let result = program.eval(&activation);
33
34 let value: bool = (&result).try_into().expect("expected bool");
35 println!("bool: {}", value);
36
37 // Extract &str
38 let ast = env.compile("config.host").unwrap();
39 let program = env.program(&ast).unwrap();
40 let result = program.eval(&activation);
41
42 let value: &str = (&result).try_into().expect("expected string");
43 println!("&str: {}", value);
44
45 // Extract &[Value] (list)
46 let ast = env.compile("items.filter(x, x > 1)").unwrap();
47 let program = env.program(&ast).unwrap();
48 let result = program.eval(&activation);
49
50 let list: &[Value] = (&result).try_into().expect("expected list");
51 println!("list length: {}", list.len());
52 for (i, v) in list.iter().enumerate() {
53 let n: i64 = v.try_into().expect("expected int");
54 println!(" [{}] = {}", i, n);
55 }
56
57 // Extract &ValueMap
58 let ast = env.compile("config").unwrap();
59 let program = env.program(&ast).unwrap();
60 let result = program.eval(&activation);
61
62 let map: &ValueMap = (&result).try_into().expect("expected map");
63 println!("map size: {}", map.len());
64 for (k, v) in map.iter() {
65 println!(" {:?} = {}", k, v);
66 }
67
68 // Handle errors gracefully
69 let result = Value::from("not an int");
70 let attempt: Result<i64, _> = (&result).try_into();
71 match attempt {
72 Ok(v) => println!("got: {}", v),
73 Err(e) => println!("conversion error: {}", e),
74 }
75
76 // Extract &OptionalValue
77 let opt_result = Value::optional_some(Value::from(99));
78 let opt: &OptionalValue = (&opt_result).try_into().expect("expected optional");
79 if opt.is_present() {
80 let inner: i64 = opt.as_value().unwrap().try_into().expect("expected int");
81 println!("optional value: {}", inner);
82 }
83}Sourcepub fn eval_with_container(
&self,
activation: &dyn Activation,
container: &str,
) -> Value
pub fn eval_with_container( &self, activation: &dyn Activation, container: &str, ) -> Value
Evaluate the program with the given variable bindings and container namespace.
The container is used for resolving unqualified type names following C++ namespace rules. For example, with container “cel.expr.conformance.proto3” and type name “TestAllTypes”, resolution tries:
- cel.expr.conformance.proto3.TestAllTypes
- cel.expr.conformance.TestAllTypes
- cel.expr.TestAllTypes
- cel.TestAllTypes
- TestAllTypes
Sourcepub fn eval_empty(&self) -> Value
pub fn eval_empty(&self) -> Value
Evaluate the program with no variable bindings.