Open clarkmcc opened 3 months ago
While not zero-allocation, have you considered integrating with the protobuf ecosystem? There is prost-reflect which provides a DynamicMessage
trait allowing field access via get_field
. Program
could then accept a DescriptorPool
to help with field and type resolution.
I like the idea of fundamentally changing Context so that it does not own any data, meaning that you do not need to clone your types to use them in CEL. Instead I'd like the Context to have references to that data.
This only works if you're not passing temporaries into Context
, otherwise end-user is forced to keep (moving) them around for as long as the Context
is used which is annoying and can be inefficient. I think simply using Cow
for values would be simplest and most versatile, while also removing any extra copies/clones.
EDIT 1:
Also, if Value
trait is added, and has add
function, an additional add_to
is required. In math, commutation is proven for numbers via induction and can't be assumed to hold true for every Value
.
So the default implementation should be:
/// Called when other [`Value`] is added to this type.
#[inline]
fn add(&self, second: Value) -> ResolveResult {
Err(ExecutionError::UnsupportedBinaryOperatorExternal(
"add", std::any::type_name::<Self>(),
))
}
/// Called when this type is added to other [`Value`].
///
/// Override if addition is non-commutative.
#[inline]
fn add_to(&self, first: Value) -> ResolveResult {
Self::add(self, first)
}
This issue is meant to be a scratchpad for ideas and feedback on improving how types and values are handled in the interpreter. There have been several different feature requests recently that could be solved by the a fundamental shift in how CEL values are managed.
Value
when only some fields in those types are actually referenced.serde_json::Value
.Today any value referenced in a CEL expression is owned by either the
Program
or theContext
. TheProgram
owns values that were created directly in the CEL expression, for example in the expression("foo" == "bar") == false
, there are three values owned by theProgram
, "foo", "bar", andfalse
. Values that are owned by theContext
are values that are dynamically provided at execution time to aProgram
as variables, likefoo == bar
, bothfoo
andbar
are values owned by the Context.Context
so that it does not own any data, meaning that you do not need to clone your types to use them in CEL. Instead I'd like theContext
to have references to that data.Questions:
Arc
/Rc
's anymore or could we get away with just this since we would assume the caller owned all the data. RIght now, anArc
is required for values owned byProgram
because aProgram
can be executed one or more times simultaneously.We can easily get references to, and represent primitive types in the interpreter, but what if an expression returned a property whose type was some other user-defined struct? How would we work with that? Perhaps instead of a
Value
enum, we have aValue
trait that exposes every behavior supported in a CEL expression, i.e.: