Skip to main content

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}