pub struct Program<'f, Fm: FnMarker = (), Rm: RuntimeMarker = ()> { /* private fields */ }
Expand description
Compiled CEL program ready for evaluation.
A Program
represents a compiled CEL expression that can be evaluated
multiple times with different variable bindings (activations). Programs
are created by compiling CEL expressions using an Env
.
§Type Parameters
'f
: Lifetime of functions registered in the environmentFm
: Function marker type indicating sync/async function supportRm
: Runtime marker type indicating the async runtime (if any)
§Examples
§Basic Usage
use cel_cxx::*;
let env = Env::builder()
.declare_variable::<String>("name")?
.build()?;
let program = env.compile("'Hello, ' + name")?;
let activation = Activation::new()
.bind_variable("name", "World")?;
let result = program.evaluate(activation)?;
§Type Information
use cel_cxx::*;
let env = Env::builder().build()?;
let program = env.compile("42")?;
// Check the return type
println!("Return type: {:?}", program.return_type());
Implementations§
Source§impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Program<'f, Fm, Rm>
impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Program<'f, Fm, Rm>
Sourcepub fn return_type(&self) -> &ValueType
pub fn return_type(&self) -> &ValueType
Returns the return type of this program.
This method returns the CEL type that this program will produce when evaluated. The type is determined during compilation based on the expression and the declared variables and functions.
§Returns
A reference to the ValueType
that this program returns.
§Examples
use cel_cxx::*;
let env = Env::builder().build()?;
let program = env.compile("42")?;
println!("Return type: {:?}", program.return_type());
// Output: Return type: Int
Examples found in repository?
654fn demo7_program_introspection() -> Result<(), Error> {
655 println!("📌 Demo 7: Program Introspection & Return Types");
656
657 // Test with numeric expression
658 {
659 let env = Env::builder()
660 .declare_variable::<i64>("a")?
661 .declare_variable::<i64>("b")?
662 .build()?;
663 let program = env.compile("a + b")?;
664 let return_type = program.return_type();
665 println!(" Expression: 'a + b'");
666 println!(" Return type: {}", return_type);
667
668 let activation = Activation::new()
669 .bind_variable("a", 10)?
670 .bind_variable("b", 20)?;
671 let result = program.evaluate(&activation)?;
672 println!(" Result: {}", result);
673 }
674
675 // Test with string expression
676 {
677 let env = Env::builder()
678 .declare_variable::<String>("a")?
679 .declare_variable::<String>("b")?
680 .build()?;
681 let program = env.compile("a + b")?;
682 let return_type = program.return_type();
683 println!(" Expression: 'a + b' (strings)");
684 println!(" Return type: {}", return_type);
685
686 let activation = Activation::new()
687 .bind_variable("a", "Hello ".to_string())?
688 .bind_variable("b", "World!".to_string())?;
689 let result = program.evaluate(&activation)?;
690 println!(" Result: {}", result);
691 }
692
693 // Test with boolean expression
694 {
695 let env = Env::builder().declare_variable::<i64>("age")?.build()?;
696 let program = env.compile("age >= 18")?;
697 let return_type = program.return_type();
698 println!(" Expression: 'age >= 18'");
699 println!(" Return type: {}", return_type);
700
701 let activation = Activation::new().bind_variable("age", 25i64)?;
702 let result = program.evaluate(&activation)?;
703 println!(" Result: {}", result);
704 }
705
706 println!();
707 Ok(())
708}
Sourcepub fn evaluate<'a, A, Afm>(
&self,
activation: A,
) -> <<Afm as FnMarkerAggr<Fm>>::Output as FnResult<'f, Result<Value, Error>>>::Outputwhere
A: ActivationInterface<'f, Afm> + 'a,
Afm: FnMarkerAggr<Fm>,
<Afm as FnMarkerAggr<Fm>>::Output: FnResult<'f, Result<Value, Error>>,
EvalDispatcher<<Afm as FnMarkerAggr<Fm>>::Output, Rm>: EvalDispatch<'f, A, Afm, Output = <<Afm as FnMarkerAggr<Fm>>::Output as FnResult<'f, Result<Value, Error>>>::Output>,
'f: 'a,
pub fn evaluate<'a, A, Afm>(
&self,
activation: A,
) -> <<Afm as FnMarkerAggr<Fm>>::Output as FnResult<'f, Result<Value, Error>>>::Outputwhere
A: ActivationInterface<'f, Afm> + 'a,
Afm: FnMarkerAggr<Fm>,
<Afm as FnMarkerAggr<Fm>>::Output: FnResult<'f, Result<Value, Error>>,
EvalDispatcher<<Afm as FnMarkerAggr<Fm>>::Output, Rm>: EvalDispatch<'f, A, Afm, Output = <<Afm as FnMarkerAggr<Fm>>::Output as FnResult<'f, Result<Value, Error>>>::Output>,
'f: 'a,
Evaluates the program with the given activation.
This method evaluates the compiled CEL expression using the variable and function bindings provided in the activation. The return type of this method depends on the program and activation markers:
- For synchronous programs: Returns
Result<Value, Error>
- For asynchronous programs: Returns
BoxFuture<Result<Value, Error>>
§Arguments
activation
- The activation containing variable and function bindings
§Type Parameters
A
- The activation typeAfm
- The activation’s function marker type
§Examples
§Synchronous Evaluation
use cel_cxx::*;
let env = Env::builder()
.declare_variable::<i64>("x")?
.build()?;
let program = env.compile("x * 2")?;
let activation = Activation::new()
.bind_variable("x", 21i64)?;
let result = program.evaluate(activation)?;
// result == Value::Int(42)
§With Empty Activation
use cel_cxx::*;
let env = Env::builder().build()?;
let program = env.compile("1 + 2 * 3")?;
let result = program.evaluate(())?;
// result == Value::Int(7)
Examples found in repository?
7fn main() -> Result<(), Error> {
8 println!("🚀 CEL-CXX Basic Example\n");
9
10 // Create an environment with variables and functions
11 let env = Env::builder()
12 .declare_variable::<String>("name")?
13 .declare_variable::<i64>("age")?
14 .register_global_function("greet", |name: &str| format!("Hello, {}!", name))?
15 .register_global_function("is_adult", |age: i64| age >= 18)?
16 .build()?;
17
18 // Compile and evaluate expressions
19 let expressions = vec![
20 "greet(name)",
21 "is_adult(age)",
22 "'Name: ' + name + ', Age: ' + string(age)",
23 "age >= 18 ? 'adult' : 'minor'",
24 ];
25
26 let activation = Activation::new()
27 .bind_variable("name", "Alice")?
28 .bind_variable("age", 25i64)?;
29
30 for expr in expressions {
31 let program = env.compile(expr)?;
32 let result = program.evaluate(&activation)?;
33 println!("{} = {}", expr, result);
34 }
35
36 println!("\n✅ Basic example completed!");
37 Ok(())
38}
More examples
146fn demo1_basic_operations() -> Result<(), Error> {
147 println!("📌 Demo 1: Basic Expressions & Zero-Annotation Functions");
148
149 let env = Env::builder()
150 .declare_variable::<String>("name")?
151 .declare_variable::<i64>("age")?
152 .declare_variable::<f64>("score")?
153 // ✨ Zero-annotation functions - types automatically inferred!
154 .register_global_function("greet", |name: &str| format!("Hello, {}!", name))?
155 .register_global_function("is_adult", |age: i64| age >= 18)?
156 .register_global_function("grade", |score: f64| -> String {
157 match score {
158 90.0..=100.0 => "A".to_string(),
159 80.0..=89.9 => "B".to_string(),
160 70.0..=79.9 => "C".to_string(),
161 60.0..=69.9 => "D".to_string(),
162 _ => "F".to_string(),
163 }
164 })?
165 .register_global_function("calculate_discount", |age: i64, score: f64| -> f64 {
166 let base_discount = if age >= 65 { 0.2 } else { 0.0 };
167 let score_bonus = if score >= 90.0 { 0.1 } else { 0.0 };
168 base_discount + score_bonus
169 })?
170 .build()?;
171
172 // Test basic expressions including simple arithmetic
173 let test_cases = vec![
174 ("1 + 1", "Alice", 25i64, 95.0, "Simple arithmetic"),
175 (
176 "greet(name)",
177 "Alice",
178 25i64,
179 95.0,
180 "Function with string parameter",
181 ),
182 ("is_adult(age)", "Bob", 16i64, 85.0, "Boolean function"),
183 (
184 "grade(score)",
185 "Charlie",
186 30i64,
187 78.5,
188 "String return function",
189 ),
190 (
191 "calculate_discount(age, score)",
192 "Diana",
193 67i64,
194 92.0,
195 "Multi-parameter function",
196 ),
197 ];
198
199 for (expr, name, age, score, description) in test_cases {
200 let program = env.compile(expr)?;
201 let activation = Activation::new()
202 .bind_variable("name", name)?
203 .bind_variable("age", age)?
204 .bind_variable("score", score)?;
205
206 let result = program.evaluate(&activation)?;
207 println!(" {} = {} ({})", expr, result, description);
208 }
209
210 println!();
211 Ok(())
212}
213
214/// Demo 2: Variable binding and providers
215fn demo2_variable_operations() -> Result<(), Error> {
216 println!("📌 Demo 2: Variable Binding & Providers");
217
218 let env = Env::builder()
219 .declare_variable::<i64>("a")?
220 .declare_variable::<i64>("b")?
221 .declare_global_function::<fn() -> i64>("get_const")?
222 .register_global_function("multiply", |x: i64, y: i64| x * y)?
223 .build()?;
224
225 // Test direct variable binding
226 {
227 println!(" Variable binding:");
228 let program = env.compile("a + b")?;
229 let activation = Activation::new()
230 .bind_variable("a", 10)?
231 .bind_variable("b", 20)?;
232 let result = program.evaluate(&activation)?;
233 println!(" a + b = {} (direct binding)", result);
234 }
235
236 // Test variable provider binding
237 {
238 println!(" Variable provider binding:");
239 let program = env.compile("a * b")?;
240 let activation = Activation::new()
241 .bind_variable("a", 5)?
242 .bind_variable_provider("b", || -> Result<i64, Error> {
243 println!(" Provider called for variable 'b'");
244 Ok(7)
245 })?;
246 let result = program.evaluate(&activation)?;
247 println!(" a * b = {} (provider binding)", result);
248 }
249
250 // Test function declaration and binding
251 {
252 println!(" Function declaration & binding:");
253 let program = env.compile("get_const() + multiply(a, 3)")?;
254 let activation = Activation::new()
255 .bind_variable("a", 4)?
256 .bind_global_function("get_const", || -> Result<i64, Error> { Ok(100) })?;
257 let result = program.evaluate(&activation)?;
258 println!(
259 " get_const() + multiply(a, 3) = {} (function binding)",
260 result
261 );
262 }
263
264 println!();
265 Ok(())
266}
267
268/// Demo 3: Opaque types with member functions
269fn demo3_opaque_member_functions() -> Result<(), Error> {
270 println!("📌 Demo 3: Opaque Types & Member Functions");
271
272 let env = Env::builder()
273 .declare_variable::<Student>("student")?
274 // ✨ Register struct methods directly using RustType::method_name syntax
275 .register_member_function("get_name", Student::get_name)?
276 .register_member_function("get_age", Student::get_age)?
277 .register_member_function("get_grade", Student::get_grade)?
278 .register_member_function("is_passing", Student::is_passing)?
279 .register_member_function("has_subject", Student::has_subject)?
280 .register_member_function("get_letter_grade", Student::get_letter_grade)?
281 .build()?;
282
283 let student = Student {
284 name: "John Doe".to_string(),
285 age: 18,
286 grade: 87.5,
287 subjects: vec!["Math".to_string(), "Physics".to_string()],
288 };
289
290 let activation = Activation::new().bind_variable("student", student)?;
291
292 let test_expressions = vec![
293 ("student.get_name()", "Get student name"),
294 ("student.get_age()", "Get student age"),
295 ("student.get_grade()", "Get numerical grade"),
296 ("student.get_letter_grade()", "Get letter grade"),
297 ("student.is_passing()", "Check if passing"),
298 ("student.has_subject('Math')", "Check if has Math subject"),
299 (
300 "student.has_subject('Chemistry')",
301 "Check if has Chemistry subject",
302 ),
303 ];
304
305 for (expr, description) in test_expressions {
306 let program = env.compile(expr)?;
307 let result = program.evaluate(&activation)?;
308 println!(" {} = {} ({})", expr, result, description);
309 }
310
311 println!();
312 Ok(())
313}
314
315/// Demo 4: Type conversions and standard Rust types
316fn demo4_type_conversions() -> Result<(), Error> {
317 println!("📌 Demo 4: Type Conversions & Standard Rust Types");
318
319 // Functions returning different types (both direct values and Results)
320 fn return_string_direct() -> String {
321 "hello world".to_string()
322 }
323 fn return_int_result() -> Result<i64, std::io::Error> {
324 Ok(42)
325 }
326 fn return_list() -> Vec<i64> {
327 vec![1, 2, 3, 4, 5]
328 }
329 fn return_map() -> HashMap<String, i64> {
330 let mut map = HashMap::new();
331 map.insert("key1".to_string(), 100);
332 map.insert("key2".to_string(), 200);
333 map
334 }
335 fn return_optional_some() -> Option<String> {
336 Some("optional value".to_string())
337 }
338 fn return_optional_none() -> Option<String> {
339 None
340 }
341
342 let env = Env::builder()
343 .register_global_function("return_string_direct", return_string_direct)?
344 .register_global_function("return_int_result", return_int_result)?
345 .register_global_function("return_list", return_list)?
346 .register_global_function("return_map", return_map)?
347 .register_global_function("return_optional_some", return_optional_some)?
348 .register_global_function("return_optional_none", return_optional_none)?
349 .build()?;
350
351 let test_cases = vec![
352 ("return_string_direct()", "String conversion"),
353 ("return_int_result()", "Result<i64> conversion"),
354 ("return_list()", "Vec<i64> conversion"),
355 ("return_map()", "HashMap conversion"),
356 ("return_optional_some()", "Option<String> Some conversion"),
357 ("return_optional_none()", "Option<String> None conversion"),
358 ];
359
360 for (expr, description) in test_cases {
361 let program = env.compile(expr)?;
362 let result = program.evaluate(())?;
363 println!(" {} = {} ({})", expr, result, description);
364
365 // Demonstrate type conversion back to Rust types
366 match expr {
367 "return_string_direct()" => {
368 let rust_string: String = result
369 .try_into()
370 .map_err(|_| Error::invalid_argument("string conversion failed".to_string()))?;
371 println!(" Converted back to Rust String: '{}'", rust_string);
372 }
373 "return_int_result()" => {
374 let rust_int: i64 = result
375 .try_into()
376 .map_err(|_| Error::invalid_argument("int conversion failed".to_string()))?;
377 println!(" Converted back to Rust i64: {}", rust_int);
378 }
379 "return_list()" => {
380 let rust_list: Vec<i64> = result
381 .try_into()
382 .map_err(|_| Error::invalid_argument("list conversion failed".to_string()))?;
383 println!(" Converted back to Rust Vec<i64>: {:?}", rust_list);
384 }
385 _ => {}
386 }
387 }
388
389 println!();
390 Ok(())
391}
392
393/// Demo 5: Generic functions and type annotations
394fn demo5_generic_functions() -> Result<(), Error> {
395 println!("📌 Demo 5: Generic Functions & Function Overloads");
396
397 // Generic function that counts items in any Vec<T>
398 fn count_items<T>(items: Vec<T>) -> i64 {
399 items.len() as i64
400 }
401
402 // Generic function that processes maps
403 fn get_map_size<K, V>(map: HashMap<K, V>) -> i64 {
404 map.len() as i64
405 }
406
407 // Function working with references in containers
408 fn join_strings(strings: Vec<&str>, separator: &str) -> String {
409 strings.join(separator)
410 }
411
412 let env = Env::builder()
413 .declare_variable::<Vec<String>>("string_list")?
414 .declare_variable::<Vec<i64>>("int_list")?
415 .declare_variable::<HashMap<String, i64>>("score_map")?
416 .declare_variable::<Vec<f64>>("floats")?
417 // Register generic functions with specific type annotations
418 .register_global_function("count_strings", count_items::<String>)?
419 .register_global_function("count_ints", count_items::<i64>)?
420 .register_global_function("get_string_map_size", get_map_size::<String, i64>)?
421 .register_global_function("join_strings", join_strings)?
422 // Multiple functions with same name, different signatures (overloads)
423 .register_global_function("process", |x: i64| x * 2)?
424 .register_global_function("process", |x: f64| (x * 2.0).round())?
425 .register_global_function("process", |x: String| x.to_uppercase())?
426 // Overloaded member functions for different container types
427 .register_member_function("sum", |numbers: Vec<i64>| numbers.iter().sum::<i64>())?
428 .register_member_function("sum", |floats: Vec<f64>| floats.iter().sum::<f64>())?
429 .build()?;
430
431 let test_cases = vec![
432 // Generic function tests
433 ("count_strings(string_list)", "Count strings in list"),
434 ("count_ints(int_list)", "Count integers in list"),
435 ("get_string_map_size(score_map)", "Get map size"),
436 ("join_strings(string_list, ' ')", "Join strings with space"),
437 // Function overload tests
438 ("process(42)", "Process integer (multiply by 2)"),
439 ("process(3.14)", "Process float (multiply by 2, round)"),
440 ("process('hello')", "Process string (uppercase)"),
441 ("int_list.sum()", "Sum integers"),
442 ("floats.sum()", "Sum floats"),
443 ];
444
445 let activation = Activation::new()
446 .bind_variable(
447 "string_list",
448 vec!["hello".to_string(), "world".to_string(), "rust".to_string()],
449 )?
450 .bind_variable("int_list", vec![1, 2, 3, 4, 5, 6])?
451 .bind_variable("floats", vec![1.5, 2.7, 3.143, 4.0])?
452 .bind_variable("score_map", {
453 let mut map = HashMap::new();
454 map.insert("alice".to_string(), 95);
455 map.insert("bob".to_string(), 87);
456 map.insert("charlie".to_string(), 92);
457 map
458 })?;
459
460 for (expr, description) in test_cases {
461 let program = env.compile(expr)?;
462 let result = program.evaluate(&activation)?;
463 println!(" {} = {} ({})", expr, result, description);
464 }
465
466 println!();
467 Ok(())
468}
469
470/// Demo 6: Error handling with different error types including Box<dyn std::error::Error>
471fn demo6_error_handling() -> Result<(), Error> {
472 println!("📌 Demo 6: Error Handling & Validation");
473
474 let env = Env::builder()
475 .declare_variable::<String>("input")?
476 .declare_variable::<i64>("divisor")?
477 .declare_variable::<String>("email")?
478 // Functions returning different error types using thiserror-derived types
479 .register_global_function("safe_parse", |s: &str| -> Result<i64, ValidationError> {
480 s.parse::<i64>()
481 .map_err(|e| ValidationError::ParseError(e.to_string()))
482 })?
483 .register_global_function(
484 "safe_divide",
485 |a: i64, b: i64| -> Result<f64, ValidationError> {
486 if b == 0 {
487 Err(ValidationError::DivisionByZero)
488 } else {
489 Ok(a as f64 / b as f64)
490 }
491 },
492 )?
493 // Additional validation functions with ValidationError
494 .register_global_function(
495 "validate_email",
496 |email: &str| -> Result<bool, ValidationError> {
497 if email.is_empty() {
498 return Err(ValidationError::EmailError(
499 "Email cannot be empty".to_string(),
500 ));
501 }
502 if !email.contains('@') {
503 return Err(ValidationError::EmailError(
504 "Email must contain @ symbol".to_string(),
505 ));
506 }
507 if !email.contains('.') {
508 return Err(ValidationError::EmailError(
509 "Email must contain . symbol".to_string(),
510 ));
511 }
512 let parts: Vec<&str> = email.split('@').collect();
513 if parts.len() != 2 {
514 return Err(ValidationError::EmailError(
515 "Email must contain exactly one @ symbol".to_string(),
516 ));
517 }
518 if parts[0].is_empty() || parts[1].is_empty() {
519 return Err(ValidationError::EmailError(
520 "Email local and domain parts cannot be empty".to_string(),
521 ));
522 }
523 Ok(true)
524 },
525 )?
526 .register_global_function(
527 "validate_age",
528 |age: i64| -> Result<String, ValidationError> {
529 match age {
530 0..=17 => Ok("minor".to_string()),
531 18..=64 => Ok("adult".to_string()),
532 65..=120 => Ok("senior".to_string()),
533 _ => Err(ValidationError::AgeError(format!("Invalid age: {}", age))),
534 }
535 },
536 )?
537 .register_global_function(
538 "validate_range",
539 |x: i64, min: i64, max: i64| -> Result<i64, ValidationError> {
540 if x < min || x > max {
541 Err(ValidationError::RangeError { value: x, min, max })
542 } else {
543 Ok(x)
544 }
545 },
546 )?
547 .build()?;
548
549 let test_cases = vec![
550 // Success cases
551 (
552 "safe_parse('42')",
553 "42",
554 2i64,
555 "valid@email.com",
556 true,
557 "Parse valid number",
558 ),
559 (
560 "safe_divide(10, divisor)",
561 "10",
562 2i64,
563 "test@example.com",
564 true,
565 "Safe division",
566 ),
567 (
568 "validate_email(email)",
569 "25",
570 1i64,
571 "user@domain.com",
572 true,
573 "Valid email",
574 ),
575 (
576 "validate_age(safe_parse(input))",
577 "25",
578 1i64,
579 "user@test.com",
580 true,
581 "Valid age",
582 ),
583 // Error cases
584 (
585 "safe_parse('invalid')",
586 "invalid",
587 2i64,
588 "test@test.com",
589 false,
590 "Parse invalid number",
591 ),
592 (
593 "safe_divide(10, divisor)",
594 "10",
595 0i64,
596 "test@test.com",
597 false,
598 "Division by zero",
599 ),
600 (
601 "validate_email(email)",
602 "10",
603 1i64,
604 "invalid-email",
605 false,
606 "Invalid email format",
607 ),
608 (
609 "validate_age(safe_parse(input))",
610 "150",
611 1i64,
612 "test@test.com",
613 false,
614 "Invalid age",
615 ),
616 (
617 "validate_range(safe_parse(input), 1, 100)",
618 "150",
619 2i64,
620 "test@test.com",
621 false,
622 "Value out of range",
623 ),
624 ];
625
626 for (expr, input, divisor, email, should_succeed, description) in test_cases {
627 let program = env.compile(expr)?;
628 let activation = Activation::new()
629 .bind_variable("input", input)?
630 .bind_variable("divisor", divisor)?
631 .bind_variable("email", email)?;
632
633 match program.evaluate(&activation) {
634 Ok(result) => {
635 println!(" {} = {} ✅ ({})", expr, result, description);
636 if !should_succeed {
637 println!(" ⚠️ Expected this to fail!");
638 }
639 }
640 Err(e) => {
641 println!(" {} -> ERROR: {} ❌ ({})", expr, e, description);
642 if should_succeed {
643 println!(" ⚠️ Expected this to succeed!");
644 }
645 }
646 }
647 }
648
649 println!();
650 Ok(())
651}
652
653/// Demo 7: Program introspection and return types
654fn demo7_program_introspection() -> Result<(), Error> {
655 println!("📌 Demo 7: Program Introspection & Return Types");
656
657 // Test with numeric expression
658 {
659 let env = Env::builder()
660 .declare_variable::<i64>("a")?
661 .declare_variable::<i64>("b")?
662 .build()?;
663 let program = env.compile("a + b")?;
664 let return_type = program.return_type();
665 println!(" Expression: 'a + b'");
666 println!(" Return type: {}", return_type);
667
668 let activation = Activation::new()
669 .bind_variable("a", 10)?
670 .bind_variable("b", 20)?;
671 let result = program.evaluate(&activation)?;
672 println!(" Result: {}", result);
673 }
674
675 // Test with string expression
676 {
677 let env = Env::builder()
678 .declare_variable::<String>("a")?
679 .declare_variable::<String>("b")?
680 .build()?;
681 let program = env.compile("a + b")?;
682 let return_type = program.return_type();
683 println!(" Expression: 'a + b' (strings)");
684 println!(" Return type: {}", return_type);
685
686 let activation = Activation::new()
687 .bind_variable("a", "Hello ".to_string())?
688 .bind_variable("b", "World!".to_string())?;
689 let result = program.evaluate(&activation)?;
690 println!(" Result: {}", result);
691 }
692
693 // Test with boolean expression
694 {
695 let env = Env::builder().declare_variable::<i64>("age")?.build()?;
696 let program = env.compile("age >= 18")?;
697 let return_type = program.return_type();
698 println!(" Expression: 'age >= 18'");
699 println!(" Return type: {}", return_type);
700
701 let activation = Activation::new().bind_variable("age", 25i64)?;
702 let result = program.evaluate(&activation)?;
703 println!(" Result: {}", result);
704 }
705
706 println!();
707 Ok(())
708}
709
710/// Demo 8: Advanced container operations and reference handling
711fn demo8_container_operations() -> Result<(), Error> {
712 println!("📌 Demo 8: Container Operations & Reference Handling");
713
714 let env = Env::builder()
715 .declare_variable::<Vec<&str>>("string_refs")?
716 .declare_variable::<HashMap<i64, &str>>("lookup_table")?
717 .declare_variable::<Option<&str>>("maybe_value")?
718 .declare_variable::<Vec<User>>("users")?
719 // Functions working with reference types
720 .register_global_function("longest_string", |strings: Vec<&str>| -> Option<String> {
721 strings
722 .iter()
723 .max_by_key(|s| s.len())
724 .map(|s| s.to_string())
725 })?
726 .register_global_function(
727 "lookup",
728 |table: HashMap<i64, &str>, key: i64| -> Option<String> {
729 table.get(&key).map(|s| s.to_string())
730 },
731 )?
732 .register_global_function("string_length", |s: Option<&str>| -> i64 {
733 s.map(|s| s.len() as i64).unwrap_or(0)
734 })?
735 // Advanced filtering and mapping
736 .register_global_function("filter_adults", |users: Vec<User>| -> Vec<User> {
737 users.into_iter().filter(|u| u.age >= 18).collect()
738 })?
739 .register_global_function(
740 "group_by_age_range",
741 |users: Vec<User>| -> HashMap<String, Vec<String>> {
742 let mut groups: HashMap<String, Vec<String>> = HashMap::new();
743 for user in users {
744 let range = match user.age {
745 0..=17 => "minor",
746 18..=64 => "adult",
747 _ => "senior",
748 };
749 groups.entry(range.to_string()).or_default().push(user.name);
750 }
751 groups
752 },
753 )?
754 .build()?;
755
756 // Prepare test data with proper lifetimes
757 let source_strings = [
758 "hello".to_string(),
759 "world".to_string(),
760 "rust".to_string(),
761 "programming".to_string(),
762 ];
763 let string_refs: Vec<&str> = source_strings.iter().map(|s| s.as_str()).collect();
764
765 let lookup_table: HashMap<i64, &str> = HashMap::from([(1, "one"), (2, "two"), (3, "three")]);
766
767 let maybe_value: Option<&str> = Some("test string");
768
769 let users = vec![
770 User {
771 id: 1,
772 name: "Alice".to_string(),
773 email: "alice@test.com".to_string(),
774 age: 25,
775 roles: vec![],
776 metadata: HashMap::new(),
777 },
778 User {
779 id: 2,
780 name: "Bob".to_string(),
781 email: "bob@test.com".to_string(),
782 age: 16,
783 roles: vec![],
784 metadata: HashMap::new(),
785 },
786 User {
787 id: 3,
788 name: "Carol".to_string(),
789 email: "carol@test.com".to_string(),
790 age: 67,
791 roles: vec![],
792 metadata: HashMap::new(),
793 },
794 ];
795
796 let test_expressions = vec![
797 ("longest_string(string_refs)", "Find longest string"),
798 ("lookup(lookup_table, 2)", "Lookup value by key"),
799 ("string_length(maybe_value)", "Get optional string length"),
800 ("filter_adults(users).size()", "Count adult users"),
801 (
802 "group_by_age_range(users).size()",
803 "Group users by age range",
804 ),
805 ];
806
807 let activation = Activation::new()
808 .bind_variable("string_refs", string_refs)?
809 .bind_variable("lookup_table", lookup_table)?
810 .bind_variable("maybe_value", maybe_value)?
811 .bind_variable("users", users)?;
812
813 for (expr, description) in test_expressions {
814 let program = env.compile(expr)?;
815 let result = program.evaluate(&activation)?;
816 println!(" {} = {} ({})", expr, result, description);
817 }
818
819 println!();
820 Ok(())
821}
Source§impl<'f, Rm: RuntimeMarker> Program<'f, (), Rm>
impl<'f, Rm: RuntimeMarker> Program<'f, (), Rm>
Sourcepub fn force_async(self) -> Program<'f, Async, Rm>
Available on crate feature async
only.
pub fn force_async(self) -> Program<'f, Async, Rm>
async
only.Forces conversion to an async program.
This method converts a synchronous program to an asynchronous one, allowing it to work with async functions and evaluation.
§Examples
use cel_cxx::*;
let sync_program = Env::builder().build()?.compile("42")?;
let async_program = sync_program.force_async();
Source§impl<'f, Fm: FnMarker> Program<'f, Fm, ()>
impl<'f, Fm: FnMarker> Program<'f, Fm, ()>
Sourcepub fn use_runtime<Rt: Runtime>(self) -> Program<'f, Fm, Rt>
Available on crate feature async
only.
pub fn use_runtime<Rt: Runtime>(self) -> Program<'f, Fm, Rt>
async
only.Configures this program to use a specific async runtime.
This method allows you to specify which async runtime should be used for evaluating this program when it contains async functions.
§Type Parameters
Rt
- The runtime type to use
§Examples
use cel_cxx::*;
use cel_cxx::r#async::Tokio;
let env = Env::builder().build()?;
let program = env.compile("42")?;
let async_program = program.use_runtime::<Tokio>();
Sourcepub fn use_tokio(self) -> Program<'f, Fm, Tokio>
Available on crate features async
and tokio
only.
pub fn use_tokio(self) -> Program<'f, Fm, Tokio>
async
and tokio
only.Configures this program to use the Tokio async runtime.
This is a convenience method equivalent to use_runtime::<Tokio>()
.
§Examples
use cel_cxx::*;
let env = Env::builder().build()?;
let program = env.compile("42")?;
let tokio_program = program.use_tokio();
Sourcepub fn use_async_std(self) -> Program<'f, Fm, AsyncStd>
Available on crate features async
and async-std
only.
pub fn use_async_std(self) -> Program<'f, Fm, AsyncStd>
async
and async-std
only.Configures this program to use the async-std runtime.
This is a convenience method equivalent to use_runtime::<AsyncStd>()
.
§Examples
use cel_cxx::*;
let env = Env::builder().build()?;
let program = env.compile("42")?;
let async_std_program = program.use_async_std();
Sourcepub fn use_smol(self) -> Program<'f, Fm, Smol>
Available on crate features async
and smol
only.
pub fn use_smol(self) -> Program<'f, Fm, Smol>
async
and smol
only.Configures this program to use the smol runtime.
This is a convenience method equivalent to use_runtime::<Smol>()
.
§Examples
use cel_cxx::*;
let env = Env::builder().build()?;
let program = env.compile("42")?;
let smol_program = program.use_smol();
Trait Implementations§
Auto Trait Implementations§
impl<'f, Fm, Rm> Freeze for Program<'f, Fm, Rm>
impl<'f, Fm = (), Rm = ()> !RefUnwindSafe for Program<'f, Fm, Rm>
impl<'f, Fm, Rm> Send for Program<'f, Fm, Rm>
impl<'f, Fm, Rm> Sync for Program<'f, Fm, Rm>
impl<'f, Fm, Rm> Unpin for Program<'f, Fm, Rm>
impl<'f, Fm = (), Rm = ()> !UnwindSafe for Program<'f, Fm, Rm>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more