cel_cxx/values/
traits.rs

1use super::*;
2use crate::IntoError;
3use std::hash::Hash;
4
5/// Trait for types that have a known CEL type.
6///
7/// This trait provides type information for values that can be used in CEL expressions.
8/// It is used in conjunction with [`IntoValue`] and [`FromValue`] to provide complete type
9/// information for value conversions.
10///
11/// # Implementation
12///
13/// **Important**: This trait should generally not be implemented manually. For most use cases:
14/// - **Built-in types**: Already have implementations (primitives, collections, etc.)
15/// - **Custom opaque types**: Use the `#[derive(Opaque)]` macro which automatically implements this trait
16/// - **Special cases**: Only implement manually if you have very specific requirements
17///
18/// # Examples
19///
20/// ## Using Built-in Types
21///
22/// ```rust
23/// use cel_cxx::{TypedValue, ValueType};
24///
25/// // Built-in types already implement TypedValue
26/// assert_eq!(i64::value_type(), ValueType::Int);
27/// assert_eq!(String::value_type(), ValueType::String);
28/// assert_eq!(bool::value_type(), ValueType::Bool);
29/// ```
30///
31/// ## Using Derive Macro for Custom Types
32///
33/// ```rust,no_run
34/// use cel_cxx::Opaque;
35///
36/// #[derive(Opaque, Debug, Clone, PartialEq)]
37/// #[cel_cxx(display)]
38/// struct CustomId(u64);
39///
40/// // TypedValue is automatically implemented by the derive macro
41/// ```
42pub trait TypedValue {
43    /// Returns the CEL type for this value type.
44    ///
45    /// This method provides the [`ValueType`] that corresponds to this Rust type
46    /// in the CEL type system. It is used for type checking, error messages,
47    /// and runtime type validation.
48    ///
49    /// # Returns
50    ///
51    /// The [`ValueType`] that represents this type in CEL expressions.
52    fn value_type() -> ValueType;
53}
54
55impl<T: TypedValue + ?Sized> TypedValue for &T {
56    fn value_type() -> ValueType {
57        T::value_type()
58    }
59}
60
61impl<T: TypedValue + ?Sized> TypedValue for &mut T {
62    fn value_type() -> ValueType {
63        T::value_type()
64    }
65}
66
67/// Trait for converting values into CEL values.
68///
69/// This trait enables automatic conversion from Rust types to CEL [`Value`] instances.
70/// It is typically used alongside [`TypedValue`] to provide complete value conversion
71/// functionality.
72///
73/// # Implementation
74///
75/// **Important**: This trait should generally not be implemented manually. For most use cases:
76/// - **Built-in types**: Already have implementations
77/// - **Custom opaque types**: Use the `#[derive(Opaque)]` macro
78/// - **Collection types**: Automatically implemented for compatible element types
79///
80/// # Examples
81///
82/// ## Using Built-in Conversions
83///
84/// ```rust
85/// use cel_cxx::{IntoValue, Value};
86///
87/// // Built-in types can be converted directly
88/// let string_val = "hello".into_value();
89/// let int_val = 42i64.into_value();
90/// let bool_val = true.into_value();
91///
92/// assert_eq!(string_val, Value::String("hello".to_string().into()));
93/// assert_eq!(int_val, Value::Int(42));
94/// assert_eq!(bool_val, Value::Bool(true));
95/// ```
96///
97/// ## Collection Conversions
98///
99/// ```rust
100/// use cel_cxx::{IntoValue, Value};
101///
102/// let list = vec![1i64, 2i64, 3i64].into_value();
103/// let map = std::collections::HashMap::from([
104///     ("key".to_string(), "value".to_string())
105/// ]).into_value();
106/// ```
107pub trait IntoValue: Sized {
108    /// Converts this value into a CEL [`Value`].
109    ///
110    /// This method performs the conversion from a Rust type to its corresponding
111    /// CEL value representation. The conversion should be lossless where possible.
112    ///
113    /// # Returns
114    ///
115    /// A [`Value`] that represents this Rust value in the CEL type system.
116    fn into_value(self) -> Value;
117}
118
119impl<T: IntoValue + Clone> IntoValue for &T {
120    fn into_value(self) -> Value {
121        T::into_value(Clone::clone(self))
122    }
123}
124
125impl<T: IntoValue + Clone> IntoValue for &mut T {
126    fn into_value(self) -> Value {
127        T::into_value(Clone::clone(self))
128    }
129}
130
131/// Trait for converting CEL values into Rust types.
132///
133/// This trait enables conversion from CEL [`Value`] instances back to Rust types,
134/// with support for both owned and borrowed data through Generic Associated Types (GATs).
135/// It is the inverse operation of [`IntoValue`].
136///
137/// # Generic Associated Types (GATs)
138///
139/// The `Output<'a>` associated type allows the trait to return either owned or borrowed
140/// data depending on the source value:
141/// - For `String`: `Output<'a> = String` (always owned)
142/// - For `&str`: `Output<'a> = &'a str` (borrowed from the source Value)
143/// - For primitives: `Output<'a> = Self` (copied)
144///
145/// # Implementation
146///
147/// **Important**: This trait should generally not be implemented manually. For most use cases:
148/// - **Built-in types**: Already have implementations with proper lifetime handling
149/// - **Custom opaque types**: Use the `#[derive(Opaque)]` macro
150/// - **Manual implementation**: Only for very specific requirements and advanced use cases
151///
152/// # Examples
153///
154/// ## Using Built-in Conversions
155///
156/// ```rust
157/// use cel_cxx::{FromValue, Value};
158///
159/// let cel_string = Value::String("hello".to_string().into());
160/// let rust_string = String::from_value(&cel_string)?;
161/// assert_eq!(rust_string, "hello");
162///
163/// let cel_int = Value::Int(42);
164/// let rust_int = i64::from_value(&cel_int)?;
165/// assert_eq!(rust_int, 42);
166/// # Ok::<(), cel_cxx::Error>(())
167/// ```
168///
169/// ## Zero-Copy String Conversion
170///
171/// ```rust
172/// use cel_cxx::{FromValue, Value};
173///
174/// let cel_string = Value::String("hello world".to_string().into());
175///
176/// // Convert to borrowed string slice (zero-copy)
177/// let borrowed_str = <&str>::from_value(&cel_string)?;
178/// assert_eq!(borrowed_str, "hello world");
179/// # Ok::<(), cel_cxx::Error>(())
180/// ```
181pub trait FromValue: Sized {
182    /// The output type for the `from_value` method.
183    ///
184    /// This type is parameterized by the lifetime of the value being converted.
185    /// The lifetime is used to indicate whether the value is borrowed or owned.
186    type Output<'a>;
187
188    /// Attempts to convert a CEL [`Value`] into this type.
189    ///
190    /// This method performs type checking and conversion from a CEL value to the
191    /// target Rust type. It returns an error if the conversion is not possible.
192    ///
193    /// # Arguments
194    ///
195    /// * `value` - The CEL value to convert
196    ///
197    /// # Returns
198    ///
199    /// A [`Result`] containing either the converted value or a [`FromValueError`]
200    /// if the conversion failed.
201    ///
202    /// # Errors
203    ///
204    /// Returns [`FromValueError`] if:
205    /// - The value type doesn't match the expected type
206    /// - The value format is invalid for the target type
207    /// - Type constraints are not satisfied
208    fn from_value<'a>(value: &'a Value) -> Result<Self::Output<'a>, FromValueError>;
209}
210
211/// Error type for failed value conversions.
212///
213/// This error is returned when attempting to convert a CEL [`Value`] to a Rust type
214/// using the [`FromValue`] trait, but the conversion fails due to type mismatch.
215///
216/// # Error Information
217///
218/// The error contains:
219/// - **Source value**: The original CEL value that could not be converted
220/// - **Target type**: String description of the intended conversion target
221/// - **Context**: Additional information about why the conversion failed
222///
223/// # Common Causes
224///
225/// - **Type mismatch**: Trying to convert `Value::String` to `i64`
226/// - **Invalid format**: Trying to convert malformed data
227/// - **Constraint violation**: Value doesn't meet type constraints
228///
229/// # Examples
230///
231/// ```rust
232/// use cel_cxx::{Value, FromValue, FromValueError};
233///
234/// let string_val = Value::String("not_a_number".to_string().into());
235/// let result = i64::from_value(&string_val);
236///
237/// match result {
238///     Ok(num) => println!("Converted: {}", num),
239///     Err(error) => {
240///         println!("Cannot convert value: {}", error);
241///     }
242/// }
243/// ```
244#[derive(thiserror::Error, Debug, Clone)]
245pub struct FromValueError {
246    value: Value,
247    to_type: String,
248}
249
250impl FromValueError {
251    /// Create a new conversion error with a custom target type description.
252    ///
253    /// # Arguments
254    ///
255    /// * `value` - The CEL value that could not be converted
256    /// * `to` - Description of the target type (will be converted to string)
257    ///
258    /// # Examples
259    ///
260    /// ```rust
261    /// use cel_cxx::{Value, FromValueError};
262    ///
263    /// let error = FromValueError::new(Value::String("text".to_string().into()), "integer");
264    /// // Error created successfully with custom type description
265    /// ```
266    pub fn new(value: Value, to: impl ToString) -> Self {
267        Self {
268            value,
269            to_type: to.to_string(),
270        }
271    }
272
273    /// Create a new conversion error with automatic type name detection.
274    ///
275    /// This method uses the [`TypedValue`] trait to automatically determine
276    /// the CEL type information of the target type, providing more consistent error messages.
277    ///
278    /// # Type Parameters
279    ///
280    /// * `T` - The target type that implements [`TypedValue`]
281    ///
282    /// # Arguments
283    ///
284    /// * `value` - The CEL value that could not be converted
285    ///
286    /// # Examples
287    ///
288    /// ```rust
289    /// use cel_cxx::{Value, FromValueError};
290    ///
291    /// let error = FromValueError::new_typed::<i64>(Value::String("text".to_string().into()));
292    /// // error contains type information for the target type
293    /// ```
294    pub fn new_typed<T: TypedValue>(value: Value) -> Self {
295        Self::new(value, T::value_type())
296    }
297}
298
299impl std::fmt::Display for FromValueError {
300    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301        write!(
302            f,
303            "cannot convert value {} to type {}",
304            self.value, self.to_type
305        )
306    }
307}
308
309impl From<FromValueError> for Error {
310    fn from(error: FromValueError) -> Self {
311        Error::invalid_argument(format!(
312            "cannot convert value {} to type {}",
313            error.value, error.to_type
314        ))
315    }
316}
317
318/// Trait for types that can be used as map keys and have a known CEL map key type.
319///
320/// `TypedMapKey` provides static type information for map key types.
321/// This trait is used alongside [`IntoMapKey`] for complete map key functionality.
322///
323/// # Examples
324///
325/// ```rust,no_run
326/// use cel_cxx::{TypedMapKey, MapKeyType};
327///
328/// // Built-in types implement this automatically
329/// assert_eq!(String::mapkey_type(), MapKeyType::String);
330/// assert_eq!(i64::mapkey_type(), MapKeyType::Int);
331/// ```
332pub trait TypedMapKey: TypedValue {
333    /// Returns the CEL map key type for this type.
334    fn mapkey_type() -> MapKeyType {
335        MapKeyType::try_from(Self::value_type()).expect("invalid map key type")
336    }
337}
338
339impl<T: TypedMapKey + ?Sized> TypedMapKey for &T {
340    fn mapkey_type() -> MapKeyType {
341        T::mapkey_type()
342    }
343}
344
345impl<T: TypedMapKey + ?Sized> TypedMapKey for &mut T {
346    fn mapkey_type() -> MapKeyType {
347        T::mapkey_type()
348    }
349}
350
351/// Trait for converting values into CEL map keys.
352///
353/// `IntoMapKey` provides conversion from Rust types to CEL [`MapKey`] instances.
354/// Only types that are valid CEL map key types can implement this trait.
355///
356/// # Examples
357///
358/// ```rust,no_run
359/// use cel_cxx::{IntoMapKey, MapKey};
360///
361/// // Convert various types to map keys
362/// let string_key = "key".into_mapkey();
363/// let int_key = 42i64.into_mapkey();
364/// let bool_key = true.into_mapkey();
365///
366/// assert_eq!(string_key, MapKey::String("key".to_string().into()));
367/// assert_eq!(int_key, MapKey::Int(42));
368/// assert_eq!(bool_key, MapKey::Bool(true));
369/// ```
370pub trait IntoMapKey: IntoValue + Eq + Hash + Ord {
371    /// Converts this value into a CEL [`MapKey`].
372    fn into_mapkey(self) -> MapKey {
373        <Self as IntoValue>::into_value(self)
374            .try_into()
375            .expect("invalid map key type")
376    }
377}
378
379impl<T: IntoMapKey + Clone> IntoMapKey for &T {
380    fn into_mapkey(self) -> MapKey {
381        T::into_mapkey(Clone::clone(self))
382    }
383}
384
385impl<T: IntoMapKey + Clone> IntoMapKey for &mut T {
386    fn into_mapkey(self) -> MapKey {
387        T::into_mapkey(Clone::clone(self))
388    }
389}
390
391/// Trait for converting CEL map keys into Rust types.
392///
393/// `FromMapKey` provides conversion from CEL [`MapKey`] instances to Rust types.
394/// This is the inverse operation of [`IntoMapKey`].
395///
396/// # Examples
397///
398/// ```rust,no_run
399/// use cel_cxx::{FromMapKey, MapKey};
400///
401/// // Convert map keys back to Rust types
402/// let cel_key = MapKey::String("hello".to_string().into());
403/// let rust_string = String::from_mapkey(&cel_key).unwrap();
404/// assert_eq!(rust_string, "hello");
405///
406/// let cel_key = MapKey::Int(42);
407/// let rust_int = i64::from_mapkey(&cel_key).unwrap();
408/// assert_eq!(rust_int, 42);
409/// ```
410pub trait FromMapKey: FromValue + Eq + Hash + Ord
411where
412    for<'a> Self::Output<'a>: Eq + Hash + Ord,
413{
414    /// Attempts to convert a CEL [`MapKey`] into this type.
415    ///
416    /// # Returns
417    ///
418    /// - `Ok(Self)`: Conversion successful
419    /// - `Err(MapKey)`: Conversion failed, returns original map key
420    fn from_mapkey<'a>(key: &'a MapKey) -> Result<Self::Output<'a>, FromMapKeyError>;
421}
422
423/// Error type for failed map key conversions.
424///
425/// This error is returned when attempting to convert a CEL [`MapKey`] to a Rust type
426/// using the [`FromMapKey`] trait, but the conversion fails due to type mismatch.
427///
428/// # Error Information
429///
430/// The error contains:
431/// - **Source key**: The original CEL map key that could not be converted
432/// - **Target type**: The intended map key type for the conversion
433///
434/// # Map Key Constraints
435///
436/// Only certain types can be used as CEL map keys:
437/// - `bool` - Boolean keys
438/// - `i64` - Signed integer keys  
439/// - `u64` - Unsigned integer keys
440/// - `String` - String keys
441///
442/// # Common Causes
443///
444/// - **Type mismatch**: Trying to convert `MapKey::String` to `i64`
445/// - **Invalid key type**: Attempting conversion to unsupported key type
446/// - **Format issues**: Key value doesn't meet target type constraints
447///
448/// # Examples
449///
450/// ```rust
451/// use cel_cxx::{MapKey, FromMapKey, FromMapKeyError};
452///
453/// let string_key = MapKey::String("not_a_number".to_string().into());
454/// let result = i64::from_mapkey(&string_key);
455///
456/// match result {
457///     Ok(num) => println!("Converted key: {}", num),
458///     Err(error) => {
459///         println!("Cannot convert key: {}", error);
460///     }
461/// }
462/// ```
463#[derive(thiserror::Error, Debug, Clone)]
464pub struct FromMapKeyError {
465    key: MapKey,
466    to_type: MapKeyType,
467}
468
469impl FromMapKeyError {
470    /// Create a new map key conversion error.
471    ///
472    /// # Arguments
473    ///
474    /// * `key` - The CEL map key that could not be converted
475    /// * `to` - The target map key type for the conversion
476    ///
477    /// # Examples
478    ///
479    /// ```rust
480    /// use cel_cxx::{MapKey, MapKeyType, FromMapKeyError};
481    ///
482    /// let error = FromMapKeyError::new(
483    ///     MapKey::String("text".to_string().into()),
484    ///     MapKeyType::Int
485    /// );
486    /// // Error created successfully
487    /// ```
488    pub fn new(key: MapKey, to: MapKeyType) -> Self {
489        Self { key, to_type: to }
490    }
491
492    /// Create a new map key conversion error with automatic type detection.
493    ///
494    /// This method uses the [`TypedMapKey`] trait to automatically determine
495    /// the CEL type information of the target type, providing more consistent error messages.
496    ///
497    /// # Type Parameters
498    ///
499    /// * `T` - The target map key type that implements [`TypedMapKey`]
500    ///
501    /// # Arguments
502    ///
503    /// * `key` - The CEL map key that could not be converted
504    ///
505    /// # Examples
506    ///
507    /// ```rust
508    /// use cel_cxx::{MapKey, FromMapKeyError};
509    ///
510    /// let error = FromMapKeyError::new_typed::<i64>(MapKey::String("text".to_string().into()));
511    /// // error contains type information for the target type
512    /// ```
513    pub fn new_typed<T: TypedMapKey>(key: MapKey) -> Self {
514        Self::new(key, T::mapkey_type())
515    }
516}
517
518impl std::fmt::Display for FromMapKeyError {
519    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
520        write!(
521            f,
522            "cannot convert map key {} to type {}",
523            self.key, self.to_type
524        )
525    }
526}
527
528impl From<FromMapKeyError> for FromValueError {
529    fn from(error: FromMapKeyError) -> Self {
530        FromValueError::new(error.key.into(), error.to_type)
531    }
532}
533
534impl From<FromMapKeyError> for Error {
535    fn from(error: FromMapKeyError) -> Self {
536        Error::invalid_argument(format!(
537            "cannot convert map key {} to type {}",
538            error.key, error.to_type
539        ))
540    }
541}
542
543/// Trait for types that can be converted into compile-time CEL constants.
544///
545/// This trait extends [`IntoValue`] and [`TypedValue`] to provide conversion
546/// to [`Constant`] values, which can be used for compile-time optimization
547/// and type inference in CEL expressions.
548///
549/// # Compile-Time vs Runtime Values
550///
551/// - **Constants**: Known at compile-time, can be folded and optimized
552/// - **Values**: Computed at runtime, require full evaluation
553///
554/// Constants enable the CEL compiler to:
555/// - Perform constant folding optimizations
556/// - Detect type errors earlier
557/// - Generate more efficient evaluation code
558/// - Support constant expression evaluation
559///
560/// # Automatic Implementation
561///
562/// This trait is automatically implemented for all types that implement
563/// both [`IntoValue`] and [`TypedValue`], providing a default conversion
564/// from value to constant.
565///
566/// # Examples
567///
568/// ## Basic Constant Creation
569///
570/// ```rust
571/// use cel_cxx::{IntoConstant, Constant};
572///
573/// // Primitive constants
574/// let null_const = ().into_constant();          // Constant::Null
575/// let bool_const = true.into_constant();        // Constant::Bool(true)
576/// let int_const = 42i64.into_constant();        // Constant::Int(42)
577/// let string_const = "hello".into_constant();   // Constant::String("hello".to_string())
578/// ```
579///
580/// ## Usage in Environment Building
581///
582/// ```rust,no_run
583/// use cel_cxx::{Env, IntoConstant};
584///
585/// let env = Env::builder()
586///     .define_constant("PI", 3.14159)?
587///     .define_constant("APP_NAME", "MyApp")?
588///     .define_constant("MAX_RETRIES", 5i64)?
589///     .build()?;
590///
591/// // These constants can be used in expressions:
592/// // "PI * radius * radius"
593/// // "APP_NAME + ' v1.0'"  
594/// // "retries < MAX_RETRIES"
595/// # Ok::<(), cel_cxx::Error>(())
596/// ```
597pub trait IntoConstant: IntoValue + TypedValue {
598    /// Convert this value into a compile-time CEL constant.
599    ///
600    /// This method creates a [`Constant`] from the value, which can be used
601    /// for compile-time optimizations and constant expression evaluation.
602    ///
603    /// # Returns
604    ///
605    /// A [`Constant`] representing this value that can be used at compile-time.
606    ///
607    /// # Implementation Note
608    ///
609    /// The default implementation converts the value using [`IntoValue::into_value`]
610    /// and then wraps it as a constant. Custom implementations can provide
611    /// more efficient constant creation if needed.
612    ///
613    /// # Examples
614    ///
615    /// ```rust
616    /// use cel_cxx::{IntoConstant, Constant};
617    ///
618    /// let const_val = 42i64.into_constant();
619    /// let const_str = "hello".into_constant();
620    /// // Constants created successfully
621    /// ```
622    fn into_constant(self) -> Constant {
623        <Self as IntoValue>::into_value(self)
624            .try_into()
625            .expect("invalid constant type")
626    }
627}
628
629impl<T: IntoConstant + Clone> IntoConstant for &T {
630    fn into_constant(self) -> Constant {
631        T::into_constant(Clone::clone(self))
632    }
633}
634
635impl<T: IntoConstant + Clone> IntoConstant for &mut T {
636    fn into_constant(self) -> Constant {
637        T::into_constant(Clone::clone(self))
638    }
639}
640
641/// Trait for converting return values to CEL results.
642///
643/// This trait provides automatic conversion for function return types,
644/// supporting both direct values and `Result` types for error handling.
645///
646/// # Note
647///
648/// This trait is sealed and cannot be implemented outside this crate.
649///
650/// # Implementations
651///
652/// - `T` where `T: IntoValue + TypedValue` - Direct value conversion
653/// - `Result<T, E>` where `T: IntoValue + TypedValue, E: IntoError` - Error handling
654pub trait IntoResult: private::Sealed {
655    /// Convert the value into a CEL result.
656    fn into_result(self) -> Result<Value, Error>;
657
658    /// Get the CEL type of the resulting value.
659    fn value_type() -> ValueType;
660}
661
662impl<T: IntoValue + TypedValue, E: IntoError> IntoResult for Result<T, E> {
663    fn into_result(self) -> Result<Value, Error> {
664        self.map(|v| v.into_value()).map_err(|e| e.into_error())
665    }
666
667    fn value_type() -> ValueType {
668        <T as TypedValue>::value_type()
669    }
670}
671
672impl<T: IntoValue + TypedValue> IntoResult for T {
673    fn into_result(self) -> Result<Value, Error> {
674        Ok(self.into_value())
675    }
676
677    fn value_type() -> ValueType {
678        <T as TypedValue>::value_type()
679    }
680}
681
682// Sealed implementations for IntoResult
683impl<T: IntoValue + TypedValue, E: IntoError> private::Sealed for Result<T, E> {}
684impl<T: IntoValue + TypedValue> private::Sealed for T {}
685
686mod private {
687    pub trait Sealed {}
688}