Skip to content

A Rust library for Common Expression Language (CEL), built on top of cel-cpp with zero-cost FFI bindings via cxx.

License

Notifications You must be signed in to change notification settings

xjasonli/cel-cxx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

github crates-io docs-rs deepwiki

CEL-CXX

A type-safe Rust library for Common Expression Language (CEL), built on top of cel-cpp with zero-cost FFI bindings via cxx.

Documentation

For detailed guides on architecture, function registration, type system, and advanced features, see the documentation directory.

Quick Start

Installation

Add to your Cargo.toml:

[dependencies]
cel-cxx = "0.2.3"

# Optional features
cel-cxx = { version = "0.2.3", features = ["tokio"] }

Basic Expression Evaluation

use cel_cxx::*;

// 1. Build environment with variables and functions
let env = Env::builder()
    .declare_variable::<String>("name")?
    .declare_variable::<i64>("age")?
    .register_global_function("adult", |age: i64| age >= 18)?
    .build()?;

// 2. Compile expression
let program = env.compile("'Hello ' + name + '! You are ' + (adult(age) ? 'an adult' : 'a minor')")?;

// 3. Create activation with variable bindings
let activation = Activation::new()
    .bind_variable("name", "Alice")?
    .bind_variable("age", 25i64)?;

// 4. Evaluate
let result = program.evaluate(&activation)?;
println!("{}", result); // "Hello Alice! You are an adult"
# Ok::<(), cel_cxx::Error>(())

Custom Types with Derive Macros

use cel_cxx::*;

#[derive(Opaque, Debug, Clone, PartialEq)]
// Specify type name in CEL type system.
#[cel_cxx(type = "myapp.User")]
// Generates `std::fmt::Display` impl for User` with `Debug` trait.
#[cel_cxx(display)]
// or you can specify a custom format.
// Generates `std::fmt::Display` impl with custom format.
#[cel_cxx(display = write!(fmt, "User(name={name})", name = &self.name))]
struct User {
    name: String,
    age: i32,
    roles: Vec<String>,
}

impl User {
    // Struct methods can be registered directly as CEL member functions
    fn has_role(&self, role: &str) -> bool {
        self.roles.contains(&role.to_string())
    }
    
    fn is_adult(&self) -> bool {
        self.age >= 18
    }
    
    fn get_role_count(&self) -> i64 {
        self.roles.len() as i64
    }
}

let env = Env::builder()
    .declare_variable::<User>("user")?
    // ✨ Register struct methods directly - &self becomes CEL receiver
    .register_member_function("has_role", User::has_role)?
    .register_member_function("is_adult", User::is_adult)?
    .register_member_function("get_role_count", User::get_role_count)?
    .build()?;

let program = env.compile("user.has_role('admin') && user.is_adult()")?;
# Ok::<(), cel_cxx::Error>(())

Platform Support

Platform Target Triple Status Notes
Linux x86_64-unknown-linux-gnu Tested
aarch64-unknown-linux-gnu Tested
armv7-unknown-linux-gnueabi Tested via cross-rs
i686-unknown-linux-gnu Tested via cross-rs
Windows x86_64-pc-windows-msvc Tested (Visual Studio 2022+)
macOS x86_64-apple-darwin Tested
aarch64-apple-darwin Tested
arm64e-apple-darwin Tested
Android aarch64-linux-android 🟡 Should work, use cargo-ndk
armv7-linux-androideabi 🟡 Should work, use cargo-ndk
x86_64-linux-android 🟡 Should work, use cargo-ndk
i686-linux-android 🟡 Should work, use cargo-ndk
iOS aarch64-apple-ios 🟡 Should work, untested
aarch64-apple-ios-sim 🟡 Should work, untested
x86_64-apple-ios 🟡 Should work, untested
arm64e-apple-ios 🟡 Should work, untested
tvOS aarch64-apple-tvos 🟡 Should work, untested
aarch64-apple-tvos-sim 🟡 Should work, untested
x86_64-apple-tvos 🟡 Should work, untested
watchOS aarch64-apple-watchos 🟡 Should work, untested
aarch64-apple-watchos-sim 🟡 Should work, untested
x86_64-apple-watchos-sim 🟡 Should work, untested
arm64_32-apple-watchos 🟡 Should work, untested
armv7k-apple-watchos 🟡 Should work, untested
visionOS aarch64-apple-visionos 🟡 Should work, untested
aarch64-apple-visionos-sim 🟡 Should work, untested
WebAssembly wasm32-unknown-emscripten Tested via cross-rs

Legend:

  • Tested: Confirmed working with automated tests
  • 🟡 Should work: Build configuration exists but not tested in CI

Cross-Compilation Support

cel-cxx includes built-in support for cross-compilation via cross-rs. The build system automatically detects cross-compilation environments and configures the appropriate toolchains.

Usage with cross-rs:

# Install cross-rs
cargo install cross --git https://github.com/cross-rs/cross

# Build for aarch64
cross build --target aarch64-unknown-linux-gnu

Note: Not all cross-rs targets are supported due to CEL-CPP's build requirements. musl targets and some embedded targets may not work due to missing C++ standard library support or incompatible toolchains.

Android Build Instructions

Android builds require additional setup beyond the standard Rust toolchain:

Prerequisites:

  1. Install Android NDK and set ANDROID_NDK_HOME
  2. Install cargo-ndk for simplified Android builds
# Install cargo-ndk
cargo install cargo-ndk

# Add Android targets
rustup target add aarch64-linux-android
rustup target add armv7-linux-androideabi
rustup target add x86_64-linux-android
rustup target add i686-linux-android

Building for Android:

# Build for ARM64 (recommended)
cargo ndk --target aarch64-linux-android build

# Build for ARMv7
cargo ndk --target armv7-linux-androideabi build

# Build for x86_64 (emulator)
cargo ndk --target x86_64-linux-android build

# Build for i686 (emulator)
cargo ndk --target i686-linux-android build

Why cargo-ndk is required:

  • ANDROID_NDK_HOME configures Bazel for CEL-CPP compilation
  • cargo-ndk automatically sets up CC_{target} and AR_{target} environment variables needed for the Rust FFI layer
  • This ensures both the C++ (CEL-CPP) and Rust (cel-cxx-ffi) components use compatible toolchains

CEL Feature Support

Core Language Features

Feature Status Description
Basic Types null, bool, int, uint, double, string, bytes
Collections list<T>, map<K,V> with full indexing and comprehensions
Time Types duration, timestamp with full arithmetic support
Operators Arithmetic, logical, comparison, and membership operators
Variables Variable binding and scoping
Conditionals Ternary operator and logical short-circuiting
Comprehensions List and map comprehensions with filtering
Custom Types Opaque types via #[derive(Opaque)]
Protobuf Message Type 🚧 Planned Direct support for protobuf messages and enums as native CEL types with field access (e.g., p.x). See issue #1
Macros CEL macro expansion support
Function Overloads Multiple function signatures with automatic resolution
Type Checking Compile-time type validation

Standard Library

Feature Status Description
Built-in Functions Core CEL functions: size(), type(), has(), etc.
String Functions contains(), startsWith(), endsWith(), matches()
List Functions all(), exists(), exists_one(), filter(), map()
Map Functions Key/value iteration and manipulation
Type Conversion int(), double(), string(), bytes(), duration(), timestamp()
Math Functions Basic arithmetic and comparison operations

Optional Value Support

Feature Status Description
Optional Types optional<T> with safe navigation and null handling
Safe Navigation ?. operator for safe member access
Optional Chaining Chain optional operations without explicit null checks
Value Extraction value() and hasValue() functions for optional handling
Optional Macros optional.of(), optional.ofNonZeroValue() macros

Extension Libraries

Extension Status Description
Strings Extension Advanced string operations: split(), join(), replace(), format()
Math Extension Mathematical functions: math.greatest(), math.least(), math.abs(), math.sqrt(), bitwise ops
Lists Extension Enhanced list operations: flatten(), reverse(), slice(), unique()
Sets Extension Set operations: sets.contains(), sets.equivalent(), sets.intersects()
Regex Extension Regular expression support: matches(), findAll(), split()
Encoders Extension Encoding/decoding: base64.encode(), base64.decode(), URL encoding
Bindings Extension Variable binding and scoping enhancements

Runtime Features

Feature Status Description
Custom Functions Register custom Rust functions with automatic type conversion
Async Support Async function calls and evaluation with Tokio integration
Custom Extensions Build and register custom CEL extensions
Performance Optimization Optimized evaluation with caching and short-circuiting

License

Licensed under the Apache License 2.0. See LICENSE for details.

Acknowledgements

  • google/cel-cpp - The foundational C++ CEL implementation
  • dtolnay/cxx - Safe and efficient Rust-C++ interop
  • rmanoka/async-scoped - Scoped async execution for safe lifetime management
  • The CEL community and other Rust CEL implementations for inspiration and ecosystem growth

About

A Rust library for Common Expression Language (CEL), built on top of cel-cpp with zero-cost FFI bindings via cxx.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published