cel_cxx/values/
optional.rs

1use std::ops::{Deref, DerefMut};
2
3/// CEL-compatible optional value type.
4///
5/// `Optional<T>` is similar to Rust's `Option<T>` but designed specifically for CEL's
6/// optional value semantics. It provides a comprehensive API for working with optional
7/// values in CEL expressions.
8///
9/// # Type Parameters
10///
11/// - `T`: The type of the optional value
12///
13/// # Examples
14///
15/// ```rust,no_run
16/// use cel_cxx::{Optional, Value};
17///
18/// // Create optional values
19/// let some_val = Optional::new("hello");
20/// let none_val: Optional<String> = Optional::none();
21///
22/// // Convert from/to Option
23/// let option = Some(42i64);
24/// let optional = Optional::from_option(option);
25/// let back_to_option = optional.into_option();
26///
27/// // Chain operations
28/// let result = Optional::new(10)
29///     .map(|x| x * 2)
30///     .filter(|&x| x > 15)
31///     .or(Optional::new(0));
32/// ```
33#[derive(Debug, Clone, PartialEq, Default)]
34pub struct Optional<T>(Box<Option<T>>);
35
36impl<T> Optional<T> {
37    /// Creates a new optional value containing the given value.
38    ///
39    /// # Examples
40    ///
41    /// ```rust,no_run
42    /// use cel_cxx::Optional;
43    ///
44    /// let opt = Optional::new(42);
45    /// assert!(opt.as_option().is_some());
46    /// ```
47    pub fn new(value: T) -> Self {
48        Self(Box::new(Some(value)))
49    }
50
51    /// Creates an empty optional value.
52    ///
53    /// # Examples
54    ///
55    /// ```rust,no_run
56    /// use cel_cxx::Optional;
57    ///
58    /// let opt: Optional<i32> = Optional::none();
59    /// assert!(opt.as_option().is_none());
60    /// ```
61    pub fn none() -> Self {
62        Self(Box::new(None))
63    }
64
65    /// Converts the optional into a standard `Option`.
66    ///
67    /// # Examples
68    ///
69    /// ```rust,no_run
70    /// use cel_cxx::Optional;
71    ///
72    /// let opt = Optional::new(42);
73    /// let option = opt.into_option();
74    /// assert_eq!(option, Some(42));
75    /// ```
76    pub fn into_option(self) -> Option<T> {
77        *self.0
78    }
79
80    /// Creates an optional from a standard `Option`.
81    ///
82    /// # Examples
83    ///
84    /// ```rust,no_run
85    /// use cel_cxx::Optional;
86    ///
87    /// let option = Some(42);
88    /// let opt = Optional::from_option(option);
89    /// assert_eq!(opt.into_option(), Some(42));
90    /// ```
91    pub fn from_option(opt: Option<T>) -> Self {
92        Self(Box::new(opt))
93    }
94
95    /// Returns a reference to the contained `Option`.
96    ///
97    /// # Examples
98    ///
99    /// ```rust,no_run
100    /// use cel_cxx::Optional;
101    ///
102    /// let opt = Optional::new(42);
103    /// assert_eq!(opt.as_option(), &Some(42));
104    /// ```
105    pub fn as_option(&self) -> &Option<T> {
106        &self.0
107    }
108
109    /// Returns a mutable reference to the contained `Option`.
110    ///
111    /// # Examples
112    ///
113    /// ```rust,no_run
114    /// use cel_cxx::Optional;
115    ///
116    /// let mut opt = Optional::new(42);
117    /// *opt.as_option_mut() = Some(100);
118    /// assert_eq!(opt.into_option(), Some(100));
119    /// ```
120    pub fn as_option_mut(&mut self) -> &mut Option<T> {
121        &mut self.0
122    }
123
124    /// Converts from `Optional<T>` to `Optional<&T>`.
125    ///
126    /// # Examples
127    ///
128    /// ```rust,no_run
129    /// use cel_cxx::Optional;
130    ///
131    /// let opt = Optional::new("hello".to_string());
132    /// let opt_ref = opt.as_ref();
133    /// assert_eq!(opt_ref.into_option(), Some(&"hello".to_string()));
134    /// ```
135    pub fn as_ref(&self) -> Optional<&T> {
136        Optional::from_option(self.as_option().as_ref())
137    }
138
139    /// Converts from `Optional<T>` to `Optional<&mut T>`.
140    ///
141    /// # Examples
142    ///
143    /// ```rust,no_run
144    /// use cel_cxx::Optional;
145    ///
146    /// let mut opt = Optional::new("hello".to_string());
147    /// let opt_mut = opt.as_mut();
148    /// // Can modify the contained value through opt_mut
149    /// ```
150    pub fn as_mut(&mut self) -> Optional<&mut T> {
151        Optional::from_option(self.as_option_mut().as_mut())
152    }
153
154    /// Maps an `Optional<T>` to `Optional<U>` by applying a function to the contained value.
155    ///
156    /// # Examples
157    ///
158    /// ```rust,no_run
159    /// use cel_cxx::Optional;
160    ///
161    /// let opt = Optional::new(5);
162    /// let doubled = opt.map(|x| x * 2);
163    /// assert_eq!(doubled.into_option(), Some(10));
164    /// ```
165    pub fn map<U, F>(self, f: F) -> Optional<U>
166    where
167        F: FnOnce(T) -> U,
168    {
169        Optional::from_option(self.into_option().map(f))
170    }
171
172    /// Calls the provided closure with the contained value (if any).
173    ///
174    /// # Examples
175    ///
176    /// ```rust,no_run
177    /// use cel_cxx::Optional;
178    ///
179    /// let opt = Optional::new(42);
180    /// let result = opt.inspect(|x| println!("Value: {}", x));
181    /// assert_eq!(result.into_option(), Some(42));
182    /// ```
183    pub fn inspect<F>(self, f: F) -> Self
184    where
185        F: FnOnce(&T),
186    {
187        Optional::from_option(self.into_option().inspect(f))
188    }
189
190    /// Returns the optional if it contains a value, otherwise returns an empty optional.
191    ///
192    /// # Examples
193    ///
194    /// ```rust,no_run
195    /// use cel_cxx::Optional;
196    ///
197    /// let opt = Optional::new(5);
198    /// let filtered = opt.filter(|&x| x > 3);
199    /// assert_eq!(filtered.into_option(), Some(5));
200    ///
201    /// let opt = Optional::new(2);
202    /// let filtered = opt.filter(|&x| x > 3);
203    /// assert_eq!(filtered.into_option(), None);
204    /// ```
205    pub fn filter<P>(self, predicate: P) -> Self
206    where
207        P: FnOnce(&T) -> bool,
208    {
209        Optional::from_option(self.0.filter(predicate))
210    }
211
212    /// Returns the optional if it contains a value, otherwise returns `other`.
213    ///
214    /// # Examples
215    ///
216    /// ```rust,no_run
217    /// use cel_cxx::Optional;
218    ///
219    /// let some = Optional::new(2);
220    /// let none: Optional<i32> = Optional::none();
221    /// let other = Optional::new(100);
222    ///
223    /// assert_eq!(some.or(other.clone()).into_option(), Some(2));
224    /// assert_eq!(none.or(other).into_option(), Some(100));
225    /// ```
226    pub fn or(self, other: Optional<T>) -> Optional<T> {
227        Optional::from_option(self.0.or(other.into_option()))
228    }
229
230    /// Returns the optional if it contains a value, otherwise calls `f` and returns the result.
231    ///
232    /// # Examples
233    ///
234    /// ```rust,no_run
235    /// use cel_cxx::Optional;
236    ///
237    /// let none: Optional<i32> = Optional::none();
238    /// let result = none.or_else(|| Optional::new(42));
239    /// assert_eq!(result.into_option(), Some(42));
240    /// ```
241    pub fn or_else<F>(self, f: F) -> Optional<T>
242    where
243        F: FnOnce() -> Optional<T>,
244    {
245        Optional::from_option(self.into_option().or_else(|| f().into_option()))
246    }
247
248    /// Returns `Some` if exactly one of `self`, `other` is `Some`, otherwise returns `None`.
249    ///
250    /// # Examples
251    ///
252    /// ```rust,no_run
253    /// use cel_cxx::Optional;
254    ///
255    /// let some = Optional::new(2);
256    /// let none: Optional<i32> = Optional::none();
257    ///
258    /// assert_eq!(some.clone().xor(none.clone()).into_option(), Some(2));
259    /// assert_eq!(none.xor(some).into_option(), Some(2));
260    /// ```
261    pub fn xor(self, other: Optional<T>) -> Optional<T> {
262        Optional::from_option(self.0.xor(other.into_option()))
263    }
264
265    /// Returns the optional if it contains a value, otherwise returns an empty optional of type `U`.
266    ///
267    /// # Examples
268    ///
269    /// ```rust,no_run
270    /// use cel_cxx::Optional;
271    ///
272    /// let some = Optional::new(2);
273    /// let other = Optional::new("hello");
274    /// let result = some.and(other);
275    /// assert_eq!(result.into_option(), Some("hello"));
276    /// ```
277    pub fn and<U>(self, other: Optional<U>) -> Optional<U> {
278        Optional::from_option(self.0.and(other.into_option()))
279    }
280
281    /// Returns an empty optional if the optional is empty, otherwise calls `f` with the wrapped value and returns the result.
282    ///
283    /// # Examples
284    ///
285    /// ```rust,no_run
286    /// use cel_cxx::Optional;
287    ///
288    /// let opt = Optional::new(5);
289    /// let result = opt.and_then(|x| {
290    ///     if x > 0 {
291    ///         Optional::new(x * 2)
292    ///     } else {
293    ///         Optional::none()
294    ///     }
295    /// });
296    /// assert_eq!(result.into_option(), Some(10));
297    /// ```
298    pub fn and_then<U, F>(self, f: F) -> Optional<U>
299    where
300        F: FnOnce(T) -> Optional<U>,
301    {
302        Optional::from_option(self.into_option().and_then(|t| f(t).into_option()))
303    }
304
305    /// Takes the value out of the optional, leaving an empty optional in its place.
306    ///
307    /// # Examples
308    ///
309    /// ```rust,no_run
310    /// use cel_cxx::Optional;
311    ///
312    /// let mut opt = Optional::new(42);
313    /// let taken = opt.take();
314    /// assert_eq!(taken.into_option(), Some(42));
315    /// assert_eq!(opt.into_option(), None);
316    /// ```
317    pub fn take(&mut self) -> Optional<T> {
318        Optional::from_option(self.0.take())
319    }
320
321    /// Takes the value out of the optional if the predicate returns `true`.
322    ///
323    /// # Examples
324    ///
325    /// ```rust,no_run
326    /// use cel_cxx::Optional;
327    ///
328    /// let mut opt = Optional::new(42);
329    /// let taken = opt.take_if(|x| *x > 40);
330    /// assert_eq!(taken.into_option(), Some(42));
331    /// ```
332    pub fn take_if<P>(&mut self, predicate: P) -> Optional<T>
333    where
334        P: FnOnce(&mut T) -> bool,
335    {
336        Optional::from_option(self.0.take_if(predicate))
337    }
338
339    /// Replaces the actual value in the optional with the value given in parameter, returning the old value if present.
340    ///
341    /// # Examples
342    ///
343    /// ```rust,no_run
344    /// use cel_cxx::Optional;
345    ///
346    /// let mut opt = Optional::new(42);
347    /// let old = opt.replace(100);
348    /// assert_eq!(old.into_option(), Some(42));
349    /// assert_eq!(opt.into_option(), Some(100));
350    /// ```
351    pub fn replace(&mut self, value: T) -> Optional<T> {
352        Self::from_option(self.0.replace(value))
353    }
354
355    /// Zips `self` with another optional.
356    ///
357    /// # Examples
358    ///
359    /// ```rust,no_run
360    /// use cel_cxx::Optional;
361    ///
362    /// let opt1 = Optional::new(1);
363    /// let opt2 = Optional::new("hello");
364    /// let zipped = opt1.zip(opt2);
365    /// assert_eq!(zipped.into_option(), Some((1, "hello")));
366    /// ```
367    pub fn zip<U>(self, other: Optional<U>) -> Optional<(T, U)> {
368        Optional::from_option(self.into_option().zip(other.into_option()))
369    }
370
371    /// Converts from `Optional<T>` (or `&Optional<T>`) to `Optional<&T::Target>`.
372    ///
373    /// # Examples
374    ///
375    /// ```rust,no_run
376    /// use cel_cxx::Optional;
377    ///
378    /// let opt = Optional::new("hello".to_string());
379    /// let deref_opt = opt.as_deref();
380    /// assert_eq!(deref_opt.into_option(), Some("hello"));
381    /// ```
382    pub fn as_deref(&self) -> Optional<&<T as Deref>::Target>
383    where
384        T: Deref,
385    {
386        Optional::from_option(self.0.as_deref())
387    }
388
389    /// Converts from `Optional<T>` (or `&mut Optional<T>`) to `Optional<&mut T::Target>`.
390    ///
391    /// # Examples
392    ///
393    /// ```rust,no_run
394    /// use cel_cxx::Optional;
395    ///
396    /// let mut opt = Optional::new("hello".to_string());
397    /// let deref_mut_opt = opt.as_deref_mut();
398    /// // Can modify the dereferenced value
399    /// ```
400    pub fn as_deref_mut(&mut self) -> Optional<&mut <T as Deref>::Target>
401    where
402        T: DerefMut,
403    {
404        Optional::from_option(self.0.as_deref_mut())
405    }
406}
407
408impl<T, U> Optional<(T, U)> {
409    /// Unzips an optional containing a tuple into a tuple of optionals.
410    ///
411    /// # Examples
412    ///
413    /// ```rust,no_run
414    /// use cel_cxx::Optional;
415    ///
416    /// let opt = Optional::new((1, "hello"));
417    /// let (opt1, opt2) = opt.unzip();
418    /// assert_eq!(opt1.into_option(), Some(1));
419    /// assert_eq!(opt2.into_option(), Some("hello"));
420    /// ```
421    pub fn unzip(self) -> (Optional<T>, Optional<U>) {
422        let (v, w) = self.into_option().unzip();
423        (Optional::from_option(v), Optional::from_option(w))
424    }
425}
426
427impl<T> Optional<&T> {
428    /// Maps an `Optional<&T>` to an `Optional<T>` by copying the contents of the optional.
429    ///
430    /// # Examples
431    ///
432    /// ```rust,no_run
433    /// use cel_cxx::Optional;
434    ///
435    /// let opt_ref = Optional::new(&42);
436    /// let opt_owned = opt_ref.copied();
437    /// assert_eq!(opt_owned.into_option(), Some(42));
438    /// ```
439    pub fn copied(self) -> Optional<T>
440    where
441        T: Copy,
442    {
443        Optional::from_option(self.0.copied())
444    }
445
446    /// Maps an `Optional<&T>` to an `Optional<T>` by cloning the contents of the optional.
447    ///
448    /// # Examples
449    ///
450    /// ```rust,no_run
451    /// use cel_cxx::Optional;
452    ///
453    /// let hello_string = "hello".to_string();
454    /// let opt_ref = Optional::new(&hello_string);
455    /// let opt_owned = opt_ref.cloned();
456    /// assert_eq!(opt_owned.into_option(), Some("hello".to_string()));
457    /// ```
458    pub fn cloned(self) -> Optional<T>
459    where
460        T: Clone,
461    {
462        Optional::from_option(self.0.cloned())
463    }
464}
465
466impl<T> Optional<&mut T> {
467    /// Maps an `Optional<&mut T>` to an `Optional<T>` by copying the contents of the optional.
468    pub fn copied(self) -> Optional<T>
469    where
470        T: Copy,
471    {
472        Optional::from_option(self.0.copied())
473    }
474
475    /// Maps an `Optional<&mut T>` to an `Optional<T>` by cloning the contents of the optional.
476    pub fn cloned(self) -> Optional<T>
477    where
478        T: Clone,
479    {
480        Optional::from_option(self.0.cloned())
481    }
482}
483
484impl<T, E> Optional<Result<T, E>> {
485    /// Transposes an `Optional` of a `Result` into a `Result` of an `Optional`.
486    ///
487    /// # Examples
488    ///
489    /// ```rust,no_run
490    /// use cel_cxx::Optional;
491    ///
492    /// let opt_result: Optional<Result<i32, &str>> = Optional::new(Ok(42));
493    /// let result_opt = opt_result.transpose();
494    /// assert_eq!(result_opt, Ok(Optional::new(42)));
495    /// ```
496    pub fn transpose(self) -> Result<Optional<T>, E> {
497        self.into_option()
498            .transpose()
499            .map(|option| Optional::from_option(option))
500    }
501}
502
503impl<T> Optional<Optional<T>> {
504    /// Flattens an `Optional<Optional<T>>` into an `Optional<T>`.
505    ///
506    /// # Examples
507    ///
508    /// ```rust,no_run
509    /// use cel_cxx::Optional;
510    ///
511    /// let nested = Optional::new(Optional::new(42));
512    /// let flattened = nested.flatten();
513    /// assert_eq!(flattened.into_option(), Some(42));
514    /// ```
515    pub fn flatten(self) -> Optional<T> {
516        match self.into_option() {
517            Some(inner) => inner,
518            None => Optional::none(),
519        }
520    }
521}
522
523impl<T> Deref for Optional<T> {
524    type Target = Option<T>;
525
526    fn deref(&self) -> &Self::Target {
527        &self.0
528    }
529}
530
531impl<T> DerefMut for Optional<T> {
532    fn deref_mut(&mut self) -> &mut Self::Target {
533        &mut self.0
534    }
535}
536
537// Implements conversion from Option<T>
538impl<T> From<Option<T>> for Optional<T> {
539    fn from(opt: Option<T>) -> Self {
540        Self::from_option(opt)
541    }
542}
543
544// Implements conversion to Option<T>
545impl<T> From<Optional<T>> for Option<T> {
546    fn from(opt: Optional<T>) -> Self {
547        opt.into_option()
548    }
549}
550
551impl<T: std::fmt::Display> std::fmt::Display for Optional<T> {
552    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
553        match self.as_option() {
554            Some(v) => write!(f, "optional({v})"),
555            None => write!(f, "optional.none()"),
556        }
557    }
558}