Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructing rust types in cel #73

Open
obsoleszenz opened this issue Jul 22, 2024 · 9 comments
Open

Constructing rust types in cel #73

obsoleszenz opened this issue Jul 22, 2024 · 9 comments
Labels
enhancement New feature or request

Comments

@obsoleszenz
Copy link

obsoleszenz commented Jul 22, 2024

From the cle doc it seems like it's possible to construct strongly typed types inside cel and pass them back. Does cel-rust support this? Couldn't find documentation about this.

Example:

use cel_interpreter::{Context, Program};
use serde::Serialize;

// An example struct that derives Serialize
#[derive(Serialize)]
struct MyStruct {
    a: i32,
    b: i32,
}

fn main() {
    let program = Program::compile("MyStruct { a: 0, b: 0}").unwrap();
    let context = Context::default();

    let value = program.execute(&context).unwrap();
    assert_eq!(value, true.into());
    println!("{value:?}");
}

image

@clarkmcc
Copy link
Owner

This is not supported today. I believe the cel-go project supports this via protobufs. It's definitely something that we need to support to be spec-compliant.

@zeroexcuses
Copy link

Is there a easy way to hack this so that in addition to Json, we also support Ron ? That might be a solution to this.

Context: I am currently using Ron for my config files -- but I find what I really want is not merely Ron, but EXPRESSIONS over Ron -- which led me to finding Cel. And I'm now wondering if there is a easy hack to make Cel-rust also support Ron in addition to Json for the data notation.

@clarkmcc
Copy link
Owner

clarkmcc commented Aug 2, 2024

@zeroexcuses any type that implements Serialize (which a Rust ron rust would) can be added as a variable to the context. Not every rust data type is supported (tuples for example), so those wouldn't be available in your expressions, but the CEL-supported types should work fine.

Are you having issues doing the following? Or is your question about deserializing from CEL to Ron?

use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
struct MyStruct {
    boolean: bool,
    float: f32,
}

let x: MyStruct = ron::from_str("(boolean: true, float: 1.23)").unwrap();
let mut context = Context::default();
context.add_variable("x", x).unwrap();

@Jikstra
Copy link

Jikstra commented Aug 3, 2024

Is there a easy way to hack this so that in addition to Json, we also support Ron ? That might be a solution to this.

Context: I am currently using Ron for my config files -- but I find what I really want is not merely Ron, but EXPRESSIONS over Ron -- which led me to finding Cel. And I'm now wondering if there is a easy hack to make Cel-rust also support Ron in addition to Json for the data notation.

This is also what i want/need. I started hacking expressions into my rust types, which kinda works but also is hacky. I think fusing cel and the ron syntax for enums/structs would be quite neat. I could imagine that one could return strings from cel and then deserialize them on the rust side to get rust types. Maybe that's the hack you are looking for?

@clarkmcc
Copy link
Owner

clarkmcc commented Aug 3, 2024

Can you help me understand the idea behind coupling Ron and cel? Cel is format-agnostic. Anything that implements serialize can be referenced in a CEL expression already.

@Jikstra
Copy link

Jikstra commented Aug 4, 2024

Can you help me understand the idea behind coupling Ron and cel? Cel is format-agnostic. Anything that implements serialize can be referenced in a CEL expression already.

I'm more talking about deserializing. Being able to construct rust structs/enums from cel would be amazing and leveraging the ron syntax for this.

@Caellian
Copy link
Contributor

Caellian commented Nov 5, 2024

There's an important disambiguation to be made here. Ron is a config file format, while it looks like Rust, it doesn't actually define a schema.

A schema would allow you to define:

MyStruct {
  example: Either<String, f32>
}

while Ron operates on values so it can only do:

MyStruct {
  example: "I must be a discrete value, even though Either implements Serialize and Deserialize for both types"
}

So Ron support isn't the solution, and it's already supported for the most part as input for cel-rust, the only lacking part here is that Value has no Value::ron() function like it does for Value::json(), but you can serialize Value into Ron directly just fine.


Building types at runtime requires protobufs, and they will never be visible to the complier. Crates like prost can load a .proto file at build-time and generate structs that way, but not while the program is running.

rust-protobuf supports dynamic types, but check the linked example to see how you'd have to interact with those objects.

@obsoleszenz
Copy link
Author

@Caellian for me it's not about dynamic types. I think defining the schema in rust is the way to go, but allowing the cel side to construct those types. Personally I don't care if protobuf or serde or anything else is used under the hood.

@Caellian
Copy link
Contributor

Caellian commented Nov 6, 2024

Oh, I get it now.

For now you can get very close by using functions, but I see what you mean.

This suggestion then requires extending both the parser and interpreter. The parser is straightforward enough, the interpreter would need a new ConstructorFunction concept to handle this properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants