pub struct Activation<'f, Fm: FnMarker = ()> { /* private fields */ }
Expand description
Activation context for CEL expression evaluation.
An Activation
provides variable and function bindings that are used
during the evaluation of a CEL expression. It allows you to bind runtime
values to variables and functions that were declared in the environment.
§Type Parameters
'f
- Lifetime of the functions in the activationFm
- Function marker type indicating sync/async function support
§Examples
§Basic Variable Binding
use cel_cxx::*;
let activation = Activation::new()
.bind_variable("name", "Alice")
.unwrap()
.bind_variable("age", 30i64)
.unwrap();
§Function Binding
use cel_cxx::*;
let activation = Activation::new()
.bind_global_function("custom_fn", |x: i64| -> i64 { x * 2 })
.unwrap();
§Empty Activation
For expressions that don’t need any bindings, you can use ()
:
use cel_cxx::*;
let env = Env::builder().build().unwrap();
let program = env.compile("1 + 2").unwrap();
let result = program.evaluate(()).unwrap();
Implementations§
Source§impl<'f> Activation<'f, ()>
impl<'f> Activation<'f, ()>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new empty activation.
This creates an activation with no variable or function bindings. You can then use the builder methods to add bindings.
§Examples
use cel_cxx::*;
let activation = Activation::new();
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}
Sourcepub fn force_async(self) -> Activation<'f, Async>
Available on crate feature async
only.
pub fn force_async(self) -> Activation<'f, Async>
async
only.Force the activation to be async.
This method is only available when the async
feature is enabled.
It converts the activation to an AsyncActivation
.
§Examples
use cel_cxx::*;
let activation = Activation::new().force_async();
Source§impl<'f> Activation<'f, Async>
impl<'f> Activation<'f, Async>
Sourcepub fn new_async() -> Self
Available on crate feature async
only.
pub fn new_async() -> Self
async
only.Creates a new empty activation with async support.
This creates an activation with no variable or function bindings. You can then use the builder methods to add bindings.
§Examples
use cel_cxx::*;
let activation = Activation::new_async();
Source§impl<'f, Fm: FnMarker> Activation<'f, Fm>
impl<'f, Fm: FnMarker> Activation<'f, Fm>
Sourcepub fn bind_variable<S, T>(self, name: S, value: T) -> Result<Self, Error>
pub fn bind_variable<S, T>(self, name: S, value: T) -> Result<Self, Error>
Binds a variable to a value.
This method adds a variable binding to the activation. The variable name must match a variable declared in the environment, and the value must be compatible with the declared type.
§Arguments
name
- The name of the variable to bindvalue
- The value to bind to the variable
§Type Parameters
S
- The type of the variable name (must convert toString
)T
- The type of the value (must implementIntoValue
andTypedValue
)
§Returns
Returns a Result
containing the updated activation or an error if
the binding failed.
§Examples
use cel_cxx::*;
let activation = Activation::new()
.bind_variable("name", "World")
.unwrap()
.bind_variable("count", 42i64)
.unwrap();
§Errors
Returns an error if:
- The variable name is not declared in the environment
- The value type doesn’t match the declared variable type
- The value cannot be converted to a CEL value
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}
Sourcepub fn bind_variable_provider<S, F, Ffm>(
self,
name: S,
provider: F,
) -> Result<Activation<'f, <Ffm as FnMarkerAggr<Fm>>::Output>, Error>
pub fn bind_variable_provider<S, F, Ffm>( self, name: S, provider: F, ) -> Result<Activation<'f, <Ffm as FnMarkerAggr<Fm>>::Output>, Error>
Binds a variable to a value provider.
This method allows you to bind a variable to a provider function that will be called to get the value when the variable is accessed during evaluation. This can be useful for lazy evaluation or for variables whose values are expensive to compute.
§Arguments
name
- The name of the variable to bindprovider
- The provider function that will supply the value
§Type Parameters
S
- The type of the variable name (must convert toString
)F
- The provider function type (must implementIntoFunction
)Ffm
- The function marker type (sync/async)
§Returns
Returns a Result
containing the updated activation with the appropriate
function marker type, or an error if the binding failed.
§Examples
use cel_cxx::*;
let activation = Activation::new()
.bind_variable_provider("timestamp", || -> i64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs() as i64
})
.unwrap();
Examples found in repository?
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}
Sourcepub fn bind_function<S, F, Ffm, Args>(
self,
name: S,
member: bool,
f: F,
) -> Result<Activation<'f, <Ffm as FnMarkerAggr<Fm>>::Output>, Error>
pub fn bind_function<S, F, Ffm, Args>( self, name: S, member: bool, f: F, ) -> Result<Activation<'f, <Ffm as FnMarkerAggr<Fm>>::Output>, Error>
Binds a function (either global or member).
This method allows you to bind a function implementation that can be called during expression evaluation. The function can be either a global function or a member function.
§Arguments
name
- The name of the function to bindmember
- Whether this is a member function (true
) or global function (false
)f
- The function implementation
§Type Parameters
S
- The type of the function name (must convert toString
)F
- The function implementation type (must implementIntoFunction
)Ffm
- The function marker type (sync/async)
§Returns
Returns a Result
containing the updated activation with the appropriate
function marker type, or an error if the binding failed.
§Examples
use cel_cxx::*;
// Bind a global function
let activation = Activation::new()
.bind_function("double", false, |x: i64| -> i64 { x * 2 })
.unwrap();
// Bind a member function
let activation = Activation::new()
.bind_function("to_upper", true, |s: String| -> String { s.to_uppercase() })
.unwrap();
Sourcepub fn bind_member_function<S, F, Ffm, Args>(
self,
name: S,
f: F,
) -> Result<Activation<'f, <Ffm as FnMarkerAggr<Fm>>::Output>, Error>
pub fn bind_member_function<S, F, Ffm, Args>( self, name: S, f: F, ) -> Result<Activation<'f, <Ffm as FnMarkerAggr<Fm>>::Output>, Error>
Binds a member function.
This is a convenience method for binding member functions (functions that
are called as methods on values, like value.method()
).
§Arguments
name
- The name of the function to bindf
- The function implementation
§Type Parameters
S
- The type of the function name (must convert toString
)F
- The function implementation type (must implementIntoFunction
)Ffm
- The function marker type (sync/async)
§Returns
Returns a Result
containing the updated activation with the appropriate
function marker type, or an error if the binding failed.
§Examples
use cel_cxx::*;
let activation = Activation::new()
.bind_member_function("to_upper", |s: String| -> String { s.to_uppercase() })
.unwrap();
Sourcepub fn bind_global_function<S, F, Ffm, Args>(
self,
name: S,
f: F,
) -> Result<Activation<'f, <Ffm as FnMarkerAggr<Fm>>::Output>, Error>
pub fn bind_global_function<S, F, Ffm, Args>( self, name: S, f: F, ) -> Result<Activation<'f, <Ffm as FnMarkerAggr<Fm>>::Output>, Error>
Binds a global function.
This is a convenience method for binding global functions (functions that can be called from any context).
§Arguments
name
- The name of the function to bindf
- The function implementation
§Type Parameters
S
- The type of the function name (must convert toString
)F
- The function implementation type (must implementIntoFunction
)Ffm
- The function marker type (sync/async)
§Returns
Returns a Result
containing the updated activation with the appropriate
function marker type, or an error if the binding failed.
§Examples
use cel_cxx::*;
let activation = Activation::new()
.bind_global_function("double", |x: i64| -> i64 { x * 2 })
.unwrap();
Examples found in repository?
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}
Trait Implementations§
Source§impl<'f, Fm: FnMarker> ActivationInterface<'f, Fm> for &Activation<'f, Fm>
impl<'f, Fm: FnMarker> ActivationInterface<'f, Fm> for &Activation<'f, Fm>
Source§fn variables(&self) -> &VariableBindings<'f>
fn variables(&self) -> &VariableBindings<'f>
Source§fn functions(&self) -> &FunctionBindings<'f>
fn functions(&self) -> &FunctionBindings<'f>
Source§impl<'f, Fm: FnMarker> ActivationInterface<'f, Fm> for Activation<'f, Fm>
impl<'f, Fm: FnMarker> ActivationInterface<'f, Fm> for Activation<'f, Fm>
Source§fn variables(&self) -> &VariableBindings<'f>
fn variables(&self) -> &VariableBindings<'f>
Source§fn functions(&self) -> &FunctionBindings<'f>
fn functions(&self) -> &FunctionBindings<'f>
Source§impl<'f, Fm: FnMarker> ActivationInterface<'f, Fm> for Box<Activation<'f, Fm>>
impl<'f, Fm: FnMarker> ActivationInterface<'f, Fm> for Box<Activation<'f, Fm>>
Source§fn variables(&self) -> &VariableBindings<'f>
fn variables(&self) -> &VariableBindings<'f>
Source§fn functions(&self) -> &FunctionBindings<'f>
fn functions(&self) -> &FunctionBindings<'f>
Source§impl<'f, Fm: FnMarker> Debug for Activation<'f, Fm>
impl<'f, Fm: FnMarker> Debug for Activation<'f, Fm>
Auto Trait Implementations§
impl<'f, Fm> Freeze for Activation<'f, Fm>
impl<'f, Fm = ()> !RefUnwindSafe for Activation<'f, Fm>
impl<'f, Fm> Send for Activation<'f, Fm>where
Fm: Send,
impl<'f, Fm> Sync for Activation<'f, Fm>where
Fm: Sync,
impl<'f, Fm> Unpin for Activation<'f, Fm>where
Fm: Unpin,
impl<'f, Fm = ()> !UnwindSafe for Activation<'f, Fm>
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> 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