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}