cel_core/eval/message.rs
1//! Trait abstraction for protobuf message values.
2//!
3//! `MessageValue` defines the interface for proto message values,
4//! decoupling cel-core from any specific protobuf implementation.
5
6use std::any::Any;
7use std::fmt;
8
9/// A trait representing a protobuf message value at runtime.
10///
11/// This abstraction allows cel-core to work with proto messages without
12/// depending on a specific protobuf library (e.g., prost-reflect).
13///
14/// # Object Safety
15///
16/// This trait is object-safe and can be used with `dyn MessageValue`.
17///
18/// # Downcasting
19///
20/// The `as_any()` method enables downcasting to concrete types. Note that
21/// downcasting only works with the exact concrete type - wrapped or newtype
22/// implementations will not match. Equality comparisons via `eq_message()`
23/// will return `false` for different concrete types even if they represent
24/// the same message content.
25///
26/// # Map Keys
27///
28/// `MessageValue` does not support hashing, so proto messages cannot be used
29/// as map keys in CEL. This matches the CEL specification.
30pub trait MessageValue: fmt::Debug + Send + Sync {
31 /// Get the fully qualified type name of this message.
32 fn type_name(&self) -> &str;
33
34 /// Check equality with another message value.
35 fn eq_message(&self, other: &dyn MessageValue) -> bool;
36
37 /// Downcast to a concrete type via `Any`.
38 fn as_any(&self) -> &dyn Any;
39
40 /// Clone this message value into a boxed trait object.
41 fn clone_boxed(&self) -> Box<dyn MessageValue>;
42
43 /// Returns true if this message is a "zero value" (all fields are default/unset).
44 ///
45 /// Used by optionals extension for `hasValue()` / `or()` semantics.
46 /// Returns `None` if the implementation cannot determine default status.
47 fn is_default(&self) -> Option<bool> {
48 None // Unknown - implementations should override
49 }
50}
51
52impl Clone for Box<dyn MessageValue> {
53 fn clone(&self) -> Self {
54 self.clone_boxed()
55 }
56}