Skip to main content

ruda_kernel/dsl/frontend/
comptime_option.rs

1use crate::dsl::prelude::*;
2use ruda_kernel_macros::derive_expand;
3
4#[derive(Default, Clone, Copy)]
5pub enum ComptimeOption<T> {
6    #[default]
7    None,
8    Some(T),
9}
10
11// Separate implementation so we don't need `RudaType` for `ComptimeOption` itself.
12// This is important because `&T where T: RudaType` does not necessarily implement
13// `RudaType`, but we need to support it in `as_ref`/`as_mut`.
14#[derive_expand(RudaType)]
15pub enum ComptimeOption<T: RudaType> {
16    None,
17    Some(T),
18}
19
20#[allow(clippy::derivable_impls)]
21impl<T: RudaType> Default for ComptimeOptionExpand<T> {
22    fn default() -> Self {
23        Self::None
24    }
25}
26
27#[allow(non_snake_case)]
28impl<T: RudaType> ComptimeOption<T> {
29    pub fn __expand_Some(scope: &mut Scope, value: T::ExpandType) -> ComptimeOptionExpand<T> {
30        Self::__expand_new_Some(scope, value)
31    }
32}
33
34impl<T: RudaType> ComptimeOptionExpand<T> {
35    pub fn is_some(&self) -> bool {
36        match self {
37            ComptimeOptionExpand::Some(_) => true,
38            ComptimeOptionExpand::None => false,
39        }
40    }
41
42    pub fn unwrap(self) -> T::ExpandType {
43        match self {
44            Self::Some(val) => val,
45            Self::None => panic!("Unwrap on a None RudaOption"),
46        }
47    }
48
49    pub fn is_none(&self) -> bool {
50        !self.is_some()
51    }
52
53    pub fn unwrap_or(self, fallback: T::ExpandType) -> T::ExpandType {
54        match self {
55            ComptimeOptionExpand::Some(val) => val,
56            ComptimeOptionExpand::None => fallback,
57        }
58    }
59}
60
61pub enum ComptimeOptionArgs<T: LaunchArg, R: Runtime> {
62    Some(<T as LaunchArg>::RuntimeArg<R>),
63    None,
64}
65
66impl<T: LaunchArg, R: Runtime> From<Option<<T as LaunchArg>::RuntimeArg<R>>>
67    for ComptimeOptionArgs<T, R>
68{
69    fn from(value: Option<<T as LaunchArg>::RuntimeArg<R>>) -> Self {
70        match value {
71            Some(arg) => Self::Some(arg),
72            None => Self::None,
73        }
74    }
75}
76
77impl<T: LaunchArg> LaunchArg for ComptimeOption<T> {
78    type RuntimeArg<R: Runtime> = ComptimeOptionArgs<T, R>;
79    type CompilationArg = ComptimeOptionCompilationArg<T>;
80
81    fn register<R: Runtime>(
82        arg: Self::RuntimeArg<R>,
83        launcher: &mut KernelLauncher<R>,
84    ) -> Self::CompilationArg {
85        match arg {
86            ComptimeOptionArgs::Some(arg) => {
87                ComptimeOptionCompilationArg::Some(T::register(arg, launcher))
88            }
89            ComptimeOptionArgs::None => ComptimeOptionCompilationArg::None,
90        }
91    }
92
93    fn expand(
94        arg: &Self::CompilationArg,
95        builder: &mut KernelBuilder,
96    ) -> <Self as RudaType>::ExpandType {
97        match arg {
98            ComptimeOptionCompilationArg::Some(arg) => {
99                ComptimeOptionExpand::Some(T::expand(arg, builder))
100            }
101            ComptimeOptionCompilationArg::None => ComptimeOptionExpand::None,
102        }
103    }
104
105    fn expand_output(
106        arg: &Self::CompilationArg,
107        builder: &mut KernelBuilder,
108    ) -> <Self as RudaType>::ExpandType {
109        match arg {
110            ComptimeOptionCompilationArg::Some(arg) => {
111                ComptimeOptionExpand::Some(T::expand_output(arg, builder))
112            }
113            ComptimeOptionCompilationArg::None => ComptimeOptionExpand::None,
114        }
115    }
116}
117
118pub enum ComptimeOptionCompilationArg<T: LaunchArg> {
119    Some(<T as LaunchArg>::CompilationArg),
120    None,
121}
122
123impl<T: LaunchArg> Clone for ComptimeOptionCompilationArg<T> {
124    fn clone(&self) -> Self {
125        match self {
126            ComptimeOptionCompilationArg::Some(arg) => {
127                ComptimeOptionCompilationArg::Some(arg.clone())
128            }
129            ComptimeOptionCompilationArg::None => ComptimeOptionCompilationArg::None,
130        }
131    }
132}
133
134impl<T: LaunchArg> PartialEq for ComptimeOptionCompilationArg<T> {
135    fn eq(&self, other: &Self) -> bool {
136        match (self, other) {
137            (
138                ComptimeOptionCompilationArg::Some(arg_0),
139                ComptimeOptionCompilationArg::Some(arg_1),
140            ) => arg_0 == arg_1,
141            (ComptimeOptionCompilationArg::None, ComptimeOptionCompilationArg::None) => true,
142            _ => false,
143        }
144    }
145}
146
147impl<T: LaunchArg> Eq for ComptimeOptionCompilationArg<T> {}
148
149impl<T: LaunchArg> core::hash::Hash for ComptimeOptionCompilationArg<T> {
150    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
151        match self {
152            ComptimeOptionCompilationArg::Some(arg) => {
153                arg.hash(state);
154            }
155            ComptimeOptionCompilationArg::None => {}
156        };
157    }
158}
159
160impl<T: LaunchArg> core::fmt::Debug for ComptimeOptionCompilationArg<T> {
161    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
162        match self {
163            ComptimeOptionCompilationArg::Some(arg) => f.debug_tuple("Some").field(arg).finish(),
164            ComptimeOptionCompilationArg::None => write!(f, "None"),
165        }
166    }
167}
168
169mod impls {
170    use core::ops::{Deref, DerefMut};
171
172    use super::*;
173    use ComptimeOption::Some;
174    type Option<T> = ComptimeOption<T>;
175    type OptionExpand<T> = ComptimeOptionExpand<T>;
176
177    /////////////////////////////////////////////////////////////////////////////
178    // Type implementation
179    /////////////////////////////////////////////////////////////////////////////
180
181    mod base {
182        use super::*;
183        use ComptimeOption::{None, Some};
184
185        impl<T> ComptimeOption<T> {
186            /// Returns `true` if the option is a [`Some`] value.
187            ///
188            /// # Examples
189            ///
190            /// ```
191            /// let x: Option<u32> = Some(2);
192            /// assert_eq!(x.is_some(), true);
193            ///
194            /// let x: Option<u32> = None;
195            /// assert_eq!(x.is_some(), false);
196            /// ```
197            #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"]
198            pub fn is_some(&self) -> bool {
199                matches!(*self, Some(_))
200            }
201
202            /// Returns `true` if the option is a [`Some`] and the value inside of it matches a predicate.
203            ///
204            /// # Examples
205            ///
206            /// ```
207            /// let x: Option<u32> = Some(2);
208            /// assert_eq!(x.is_some_and(|x| x > 1), true);
209            ///
210            /// let x: Option<u32> = Some(0);
211            /// assert_eq!(x.is_some_and(|x| x > 1), false);
212            ///
213            /// let x: Option<u32> = None;
214            /// assert_eq!(x.is_some_and(|x| x > 1), false);
215            ///
216            /// let x: Option<String> = Some("ownership".to_string());
217            /// assert_eq!(x.as_ref().is_some_and(|x| x.len() > 1), true);
218            /// println!("still alive {:?}", x);
219            /// ```
220            #[must_use]
221            pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool {
222                match self {
223                    None => false,
224                    Some(x) => f(x),
225                }
226            }
227
228            /// Returns `true` if the option is a [`None`] or the value inside of it matches a predicate.
229            ///
230            /// # Examples
231            ///
232            /// ```
233            /// let x: Option<u32> = Some(2);
234            /// assert_eq!(x.is_none_or(|x| x > 1), true);
235            ///
236            /// let x: Option<u32> = Some(0);
237            /// assert_eq!(x.is_none_or(|x| x > 1), false);
238            ///
239            /// let x: Option<u32> = None;
240            /// assert_eq!(x.is_none_or(|x| x > 1), true);
241            ///
242            /// let x: Option<String> = Some("ownership".to_string());
243            /// assert_eq!(x.as_ref().is_none_or(|x| x.len() > 1), true);
244            /// println!("still alive {:?}", x);
245            /// ```
246            #[must_use]
247            pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
248                match self {
249                    None => true,
250                    Some(x) => f(x),
251                }
252            }
253
254            /// Converts from `&Option<T>` to `Option<&T>`.
255            ///
256            /// # Examples
257            ///
258            /// Calculates the length of an <code>Option<[String]></code> as an <code>Option<[usize]></code>
259            /// without moving the [`String`]. The [`map`] method takes the `self` argument by value,
260            /// consuming the original, so this technique uses `as_ref` to first take an `Option` to a
261            /// reference to the value inside the original.
262            ///
263            /// [`map`]: Option::map
264            /// [String]: ../../std/string/struct.String.html "String"
265            /// [`String`]: ../../std/string/struct.String.html "String"
266            ///
267            /// ```
268            /// let text: Option<String> = Some("Hello, world!".to_string());
269            /// // First, cast `Option<String>` to `Option<&String>` with `as_ref`,
270            /// // then consume *that* with `map`, leaving `text` on the stack.
271            /// let text_length: Option<usize> = text.as_ref().map(|s| s.len());
272            /// println!("still can print text: {text:?}");
273            /// ```
274            pub fn as_ref(&self) -> Option<&T> {
275                match *self {
276                    Some(ref x) => Some(x),
277                    None => None,
278                }
279            }
280
281            /// Converts from `&mut Option<T>` to `Option<&mut T>`.
282            ///
283            /// # Examples
284            ///
285            /// ```
286            /// let mut x = Some(2);
287            /// match x.as_mut() {
288            ///     Some(v) => *v = 42,
289            ///     None => {},
290            /// }
291            /// assert_eq!(x, Some(42));
292            /// ```
293            pub fn as_mut(&mut self) -> Option<&mut T> {
294                match *self {
295                    Some(ref mut x) => Some(x),
296                    None => None,
297                }
298            }
299
300            /// Returns the contained [`Some`] value, consuming the `self` value.
301            ///
302            /// # Panics
303            ///
304            /// Panics if the value is a [`None`] with a custom panic message provided by
305            /// `msg`.
306            ///
307            /// # Examples
308            ///
309            /// ```
310            /// let x = Some("value");
311            /// assert_eq!(x.expect("fruits are healthy"), "value");
312            /// ```
313            ///
314            /// ```should_panic
315            /// let x: Option<&str> = None;
316            /// x.expect("fruits are healthy"); // panics with `fruits are healthy`
317            /// ```
318            ///
319            /// # Recommended Message Style
320            ///
321            /// We recommend that `expect` messages are used to describe the reason you
322            /// _expect_ the `Option` should be `Some`.
323            ///
324            /// ```should_panic
325            /// # let slice: &[u8] = &[];
326            /// let item = slice.get(0)
327            ///     .expect("slice should not be empty");
328            /// ```
329            ///
330            /// **Hint**: If you're having trouble remembering how to phrase expect
331            /// error messages remember to focus on the word "should" as in "env
332            /// variable should be set by blah" or "the given binary should be available
333            /// and executable by the current user".
334            ///
335            /// For more detail on expect message styles and the reasoning behind our
336            /// recommendation please refer to the section on ["Common Message
337            /// Styles"](../../std/error/index.html#common-message-styles) in the [`std::error`](../../std/error/index.html) module docs.
338            #[track_caller]
339            pub fn expect(self, msg: &str) -> T {
340                match self {
341                    Some(val) => val,
342                    None => panic!("{msg}"),
343                }
344            }
345
346            /// Returns the contained [`Some`] value, consuming the `self` value.
347            ///
348            /// Because this function may panic, its use is generally discouraged.
349            /// Panics are meant for unrecoverable errors, and
350            /// [may abort the entire program][panic-abort].
351            ///
352            /// Instead, prefer to use pattern matching and handle the [`None`]
353            /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or
354            /// [`unwrap_or_default`]. In functions returning `Option`, you can use
355            /// [the `?` (try) operator][try-option].
356            ///
357            /// [panic-abort]: https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html
358            /// [try-option]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#where-the--operator-can-be-used
359            /// [`unwrap_or`]: Option::unwrap_or
360            /// [`unwrap_or_else`]: Option::unwrap_or_else
361            /// [`unwrap_or_default`]: Option::unwrap_or_default
362            ///
363            /// # Panics
364            ///
365            /// Panics if the self value equals [`None`].
366            ///
367            /// # Examples
368            ///
369            /// ```
370            /// let x = Some("air");
371            /// assert_eq!(x.unwrap(), "air");
372            /// ```
373            ///
374            /// ```should_panic
375            /// let x: Option<&str> = None;
376            /// assert_eq!(x.unwrap(), "air"); // fails
377            /// ```
378            pub fn unwrap(self) -> T {
379                match self {
380                    Some(val) => val,
381                    None => panic!("called `Option::unwrap()` on a `None` value"),
382                }
383            }
384
385            /// Returns the contained [`Some`] value or computes it from a closure.
386            ///
387            /// # Examples
388            ///
389            /// ```
390            /// let k = 10;
391            /// assert_eq!(Some(4).unwrap_or_else(|| 2 * k), 4);
392            /// assert_eq!(None.unwrap_or_else(|| 2 * k), 20);
393            /// ```
394            pub fn unwrap_or_else<F>(self, f: F) -> T
395            where
396                F: FnOnce() -> T,
397            {
398                match self {
399                    Some(x) => x,
400                    None => f(),
401                }
402            }
403
404            /// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value (if `Some`) or returns `None` (if `None`).
405            ///
406            /// # Examples
407            ///
408            /// Calculates the length of an <code>Option<[String]></code> as an
409            /// <code>Option<[usize]></code>, consuming the original:
410            ///
411            /// [String]: ../../std/string/struct.String.html "String"
412            /// ```
413            /// let maybe_some_string = Some(String::from("Hello, World!"));
414            /// // `Option::map` takes self *by value*, consuming `maybe_some_string`
415            /// let maybe_some_len = maybe_some_string.map(|s| s.len());
416            /// assert_eq!(maybe_some_len, Some(13));
417            ///
418            /// let x: Option<&str> = None;
419            /// assert_eq!(x.map(|s| s.len()), None);
420            /// ```
421            pub fn map<U, F>(self, f: F) -> Option<U>
422            where
423                F: FnOnce(T) -> U,
424            {
425                match self {
426                    Some(x) => Some(f(x)),
427                    None => None,
428                }
429            }
430
431            /// Calls a function with a reference to the contained value if [`Some`].
432            ///
433            /// Returns the original option.
434            ///
435            /// # Examples
436            ///
437            /// ```
438            /// let list = vec![1, 2, 3];
439            ///
440            /// // prints "got: 2"
441            /// let x = list
442            ///     .get(1)
443            ///     .inspect(|x| println!("got: {x}"))
444            ///     .expect("list should be long enough");
445            ///
446            /// // prints nothing
447            /// list.get(5).inspect(|x| println!("got: {x}"));
448            /// ```
449            pub fn inspect<F>(self, f: F) -> Self
450            where
451                F: FnOnce(&T),
452            {
453                if let Some(ref x) = self {
454                    f(x);
455                }
456
457                self
458            }
459
460            /// Returns the provided default result (if none),
461            /// or applies a function to the contained value (if any).
462            ///
463            /// Arguments passed to `map_or` are eagerly evaluated; if you are passing
464            /// the result of a function call, it is recommended to use [`map_or_else`],
465            /// which is lazily evaluated.
466            ///
467            /// [`map_or_else`]: Option::map_or_else
468            ///
469            /// # Examples
470            ///
471            /// ```
472            /// let x = Some("foo");
473            /// assert_eq!(x.map_or(42, |v| v.len()), 3);
474            ///
475            /// let x: Option<&str> = None;
476            /// assert_eq!(x.map_or(42, |v| v.len()), 42);
477            /// ```
478            pub fn map_or<U, F>(self, default: U, f: F) -> U
479            where
480                F: FnOnce(T) -> U,
481            {
482                match self {
483                    Some(t) => f(t),
484                    None => default,
485                }
486            }
487            /// Computes a default function result (if none), or
488            /// applies a different function to the contained value (if any).
489            ///
490            /// # Basic examples
491            ///
492            /// ```
493            /// let k = 21;
494            ///
495            /// let x = Some("foo");
496            /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
497            ///
498            /// let x: Option<&str> = None;
499            /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
500            /// ```
501            ///
502            /// # Handling a Result-based fallback
503            ///
504            /// A somewhat common occurrence when dealing with optional values
505            /// in combination with [`Result<T, E>`] is the case where one wants to invoke
506            /// a fallible fallback if the option is not present.  This example
507            /// parses a command line argument (if present), or the contents of a file to
508            /// an integer.  However, unlike accessing the command line argument, reading
509            /// the file is fallible, so it must be wrapped with `Ok`.
510            ///
511            /// ```no_run
512            /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
513            /// let v: u64 = std::env::args()
514            ///    .nth(1)
515            ///    .map_or_else(|| std::fs::read_to_string("/etc/someconfig.conf"), Ok)?
516            ///    .parse()?;
517            /// #   Ok(())
518            /// # }
519            /// ```
520            pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
521            where
522                D: FnOnce() -> U,
523                F: FnOnce(T) -> U,
524            {
525                match self {
526                    Some(t) => f(t),
527                    None => default(),
528                }
529            }
530
531            /// Maps an `Option<T>` to a `U` by applying function `f` to the contained
532            /// value if the option is [`Some`], otherwise if [`None`], returns the
533            /// [default value] for the type `U`.
534            ///
535            /// # Examples
536            ///
537            /// ```ignore
538            ///
539            /// let x: Option<&str> = Some("hi");
540            /// let y: Option<&str> = None;
541            ///
542            /// assert_eq!(x.map_or_default(|x| x.len()), 2);
543            /// assert_eq!(y.map_or_default(|y| y.len()), 0);
544            /// ```
545            ///
546            /// [default value]: Default::default
547            pub fn map_or_default<U, F>(self, f: F) -> U
548            where
549                U: Default,
550                F: FnOnce(T) -> U,
551            {
552                match self {
553                    Some(t) => f(t),
554                    None => U::default(),
555                }
556            }
557
558            /// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`.
559            ///
560            /// Leaves the original Option in-place, creating a new one with a reference
561            /// to the original one, additionally coercing the contents via [`Deref`].
562            ///
563            /// # Examples
564            ///
565            /// ```
566            /// let x: Option<String> = Some("hey".to_owned());
567            /// assert_eq!(x.as_deref(), Some("hey"));
568            ///
569            /// let x: Option<String> = None;
570            /// assert_eq!(x.as_deref(), None);
571            /// ```
572            pub fn as_deref<'a>(&'a self) -> Option<&'a T::Target>
573            where
574                T: Deref,
575                &'a T: RudaType,
576            {
577                self.as_ref().map(Deref::deref)
578            }
579
580            /// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`.
581            ///
582            /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to
583            /// the inner type's [`Deref::Target`] type.
584            ///
585            /// # Examples
586            ///
587            /// ```
588            /// let mut x: Option<String> = Some("hey".to_owned());
589            /// assert_eq!(x.as_deref_mut().map(|x| {
590            ///     x.make_ascii_uppercase();
591            ///     x
592            /// }), Some("HEY".to_owned().as_mut_str()));
593            /// ```
594            pub fn as_deref_mut<'a>(&'a mut self) -> Option<&'a mut T::Target>
595            where
596                T: DerefMut,
597                &'a mut T: RudaType,
598            {
599                self.as_mut().map(DerefMut::deref_mut)
600            }
601
602            /// Returns [`None`] if the option is [`None`], otherwise calls `f` with the
603            /// wrapped value and returns the result.
604            ///
605            /// Some languages call this operation flatmap.
606            ///
607            /// # Examples
608            ///
609            /// ```
610            /// fn sq_then_to_string(x: u32) -> Option<String> {
611            ///     x.checked_mul(x).map(|sq| sq.to_string())
612            /// }
613            ///
614            /// assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
615            /// assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
616            /// assert_eq!(None.and_then(sq_then_to_string), None);
617            /// ```
618            ///
619            /// Often used to chain fallible operations that may return [`None`].
620            ///
621            /// ```
622            /// let arr_2d = [["A0", "A1"], ["B0", "B1"]];
623            ///
624            /// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
625            /// assert_eq!(item_0_1, Some(&"A1"));
626            ///
627            /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
628            /// assert_eq!(item_2_0, None);
629            /// ```
630            pub fn and_then<U, F>(self, f: F) -> Option<U>
631            where
632                F: FnOnce(T) -> Option<U>,
633                U: RudaType,
634            {
635                match self {
636                    Some(x) => f(x),
637                    None => None,
638                }
639            }
640
641            /// Returns [`None`] if the option is [`None`], otherwise calls `predicate`
642            /// with the wrapped value and returns:
643            ///
644            /// - [`Some(t)`] if `predicate` returns `true` (where `t` is the wrapped
645            ///   value), and
646            /// - [`None`] if `predicate` returns `false`.
647            ///
648            /// This function works similar to [`Iterator::filter()`]. You can imagine
649            /// the `Option<T>` being an iterator over one or zero elements. `filter()`
650            /// lets you decide which elements to keep.
651            ///
652            /// # Examples
653            ///
654            /// ```rust
655            /// fn is_even(n: &i32) -> bool {
656            ///     n % 2 == 0
657            /// }
658            ///
659            /// assert_eq!(None.filter(is_even), None);
660            /// assert_eq!(Some(3).filter(is_even), None);
661            /// assert_eq!(Some(4).filter(is_even), Some(4));
662            /// ```
663            ///
664            /// [`Some(t)`]: Some
665            pub fn filter<P>(self, predicate: P) -> Self
666            where
667                P: FnOnce(&T) -> bool,
668            {
669                if let Some(x) = self
670                    && predicate(&x)
671                {
672                    return Some(x);
673                }
674                None
675            }
676
677            /// Returns the option if it contains a value, otherwise calls `f` and
678            /// returns the result.
679            ///
680            /// # Examples
681            ///
682            /// ```
683            /// fn nobody() -> Option<&'static str> { None }
684            /// fn vikings() -> Option<&'static str> { Some("vikings") }
685            ///
686            /// assert_eq!(Some("barbarians").or_else(vikings), Some("barbarians"));
687            /// assert_eq!(None.or_else(vikings), Some("vikings"));
688            /// assert_eq!(None.or_else(nobody), None);
689            /// ```
690            pub fn or_else<F>(self, f: F) -> Option<T>
691            where
692                F: FnOnce() -> Option<T>,
693            {
694                match self {
695                    x @ Some(_) => x,
696                    None => f(),
697                }
698            }
699
700            /// Zips `self` and another `Option` with function `f`.
701            ///
702            /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some(f(s, o))`.
703            /// Otherwise, `None` is returned.
704            ///
705            /// # Examples
706            ///
707            /// ```ignore
708            ///
709            /// #[derive(Debug, PartialEq)]
710            /// struct Point {
711            ///     x: f64,
712            ///     y: f64,
713            /// }
714            ///
715            /// impl Point {
716            ///     fn new(x: f64, y: f64) -> Self {
717            ///         Self { x, y }
718            ///     }
719            /// }
720            ///
721            /// let x = Some(17.5);
722            /// let y = Some(42.7);
723            ///
724            /// assert_eq!(x.zip_with(y, Point::new), Some(Point { x: 17.5, y: 42.7 }));
725            /// assert_eq!(x.zip_with(None, Point::new), None);
726            /// ```
727            pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
728            where
729                F: FnOnce(T, U) -> R,
730                U: RudaType,
731                R: RudaType,
732            {
733                match (self, other) {
734                    (Some(a), Some(b)) => Some(f(a, b)),
735                    _ => None,
736                }
737            }
738
739            /// Reduces two options into one, using the provided function if both are `Some`.
740            ///
741            /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some(f(s, o))`.
742            /// Otherwise, if only one of `self` and `other` is `Some`, that one is returned.
743            /// If both `self` and `other` are `None`, `None` is returned.
744            ///
745            /// # Examples
746            ///
747            /// ```ignore
748            ///
749            /// let s12 = Some(12);
750            /// let s17 = Some(17);
751            /// let n = None;
752            /// let f = |a, b| a + b;
753            ///
754            /// assert_eq!(s12.reduce(s17, f), Some(29));
755            /// assert_eq!(s12.reduce(n, f), Some(12));
756            /// assert_eq!(n.reduce(s17, f), Some(17));
757            /// assert_eq!(n.reduce(n, f), None);
758            /// ```
759            pub fn reduce<U, R, F>(self, other: Option<U>, f: F) -> Option<R>
760            where
761                T: Into<R>,
762                U: Into<R>,
763                F: FnOnce(T, U) -> R,
764            {
765                match (self, other) {
766                    (Some(a), Some(b)) => Some(f(a, b)),
767                    (Some(a), _) => Some(a.into()),
768                    (_, Some(b)) => Some(b.into()),
769                    _ => None,
770                }
771            }
772        }
773
774        impl<T> ComptimeOption<T> {
775            /////////////////////////////////////////////////////////////////////////
776            // Querying the contained values
777            /////////////////////////////////////////////////////////////////////////
778
779            /// Returns `true` if the option is a [`None`] value.
780            ///
781            /// # Examples
782            ///
783            /// ```
784            /// let x: Option<u32> = Some(2);
785            /// assert_eq!(x.is_none(), false);
786            ///
787            /// let x: Option<u32> = None;
788            /// assert_eq!(x.is_none(), true);
789            /// ```
790            #[must_use = "if you intended to assert that this doesn't have a value, consider \
791                  wrapping this in an `assert!()` instead"]
792            pub fn is_none(&self) -> bool {
793                !self.is_some()
794            }
795
796            /////////////////////////////////////////////////////////////////////////
797            // Getting to contained values
798            /////////////////////////////////////////////////////////////////////////
799
800            /// Returns the contained [`Some`] value or a provided default.
801            ///
802            /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
803            /// the result of a function call, it is recommended to use [`unwrap_or_else`],
804            /// which is lazily evaluated.
805            ///
806            /// [`unwrap_or_else`]: Option::unwrap_or_else
807            ///
808            /// # Examples
809            ///
810            /// ```
811            /// assert_eq!(Some("car").unwrap_or("bike"), "car");
812            /// assert_eq!(None.unwrap_or("bike"), "bike");
813            /// ```
814            pub fn unwrap_or(self, default: T) -> T {
815                match self {
816                    Some(x) => x,
817                    None => default,
818                }
819            }
820
821            /// Returns the contained [`Some`] value or a default.
822            ///
823            /// Consumes the `self` argument then, if [`Some`], returns the contained
824            /// value, otherwise if [`None`], returns the [default value] for that
825            /// type.
826            ///
827            /// # Examples
828            ///
829            /// ```
830            /// let x: Option<u32> = None;
831            /// let y: Option<u32> = Some(12);
832            ///
833            /// assert_eq!(x.unwrap_or_default(), 0);
834            /// assert_eq!(y.unwrap_or_default(), 12);
835            /// ```
836            ///
837            /// [default value]: Default::default
838            /// [`parse`]: str::parse
839            /// [`FromStr`]: crate::dsl::str::FromStr
840            pub fn unwrap_or_default(self) -> T
841            where
842                T: Default + IntoRuntime,
843            {
844                match self {
845                    Some(x) => x,
846                    None => comptime![T::default()].runtime(),
847                }
848            }
849
850            /// Returns the contained [`Some`] value, consuming the `self` value,
851            /// without checking that the value is not [`None`].
852            ///
853            /// # Safety
854            ///
855            /// Calling this method on [`None`] is *[undefined behavior]*.
856            ///
857            /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
858            ///
859            /// # Examples
860            ///
861            /// ```
862            /// let x = Some("air");
863            /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
864            /// ```
865            ///
866            /// ```no_run
867            /// let x: Option<&str> = None;
868            /// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior!
869            /// ```
870            pub unsafe fn unwrap_unchecked(self) -> T {
871                match self {
872                    Some(val) => val,
873                    // SAFETY: the safety contract must be upheld by the caller.
874                    None => comptime![unsafe { core::hint::unreachable_unchecked() }],
875                }
876            }
877
878            /////////////////////////////////////////////////////////////////////////
879            // Boolean operations on the values, eager and lazy
880            /////////////////////////////////////////////////////////////////////////
881
882            /// Returns [`None`] if the option is [`None`], otherwise returns `optb`.
883            ///
884            /// Arguments passed to `and` are eagerly evaluated; if you are passing the
885            /// result of a function call, it is recommended to use [`and_then`], which is
886            /// lazily evaluated.
887            ///
888            /// [`and_then`]: Option::and_then
889            ///
890            /// # Examples
891            ///
892            /// ```
893            /// let x = Some(2);
894            /// let y: Option<&str> = None;
895            /// assert_eq!(x.and(y), None);
896            ///
897            /// let x: Option<u32> = None;
898            /// let y = Some("foo");
899            /// assert_eq!(x.and(y), None);
900            ///
901            /// let x = Some(2);
902            /// let y = Some("foo");
903            /// assert_eq!(x.and(y), Some("foo"));
904            ///
905            /// let x: Option<u32> = None;
906            /// let y: Option<&str> = None;
907            /// assert_eq!(x.and(y), None);
908            /// ```
909            pub fn and<U>(self, optb: Option<U>) -> Option<U>
910            where
911                U: RudaType,
912            {
913                match self {
914                    Some(_) => optb,
915                    Option::None => Option::new_None(),
916                }
917            }
918
919            /// Returns the option if it contains a value, otherwise returns `optb`.
920            ///
921            /// Arguments passed to `or` are eagerly evaluated; if you are passing the
922            /// result of a function call, it is recommended to use [`or_else`], which is
923            /// lazily evaluated.
924            ///
925            /// [`or_else`]: Option::or_else
926            ///
927            /// # Examples
928            ///
929            /// ```
930            /// let x = Some(2);
931            /// let y = None;
932            /// assert_eq!(x.or(y), Some(2));
933            ///
934            /// let x = None;
935            /// let y = Some(100);
936            /// assert_eq!(x.or(y), Some(100));
937            ///
938            /// let x = Some(2);
939            /// let y = Some(100);
940            /// assert_eq!(x.or(y), Some(2));
941            ///
942            /// let x: Option<u32> = None;
943            /// let y = None;
944            /// assert_eq!(x.or(y), None);
945            /// ```
946            pub fn or(self, optb: Option<T>) -> Option<T> {
947                match self {
948                    x @ Some(_) => x,
949                    None => optb,
950                }
951            }
952
953            /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns [`None`].
954            ///
955            /// # Examples
956            ///
957            /// ```
958            /// let x = Some(2);
959            /// let y: Option<u32> = None;
960            /// assert_eq!(x.xor(y), Some(2));
961            ///
962            /// let x: Option<u32> = None;
963            /// let y = Some(2);
964            /// assert_eq!(x.xor(y), Some(2));
965            ///
966            /// let x = Some(2);
967            /// let y = Some(2);
968            /// assert_eq!(x.xor(y), None);
969            ///
970            /// let x: Option<u32> = None;
971            /// let y: Option<u32> = None;
972            /// assert_eq!(x.xor(y), None);
973            /// ```
974            pub fn xor(self, optb: Option<T>) -> Option<T> {
975                match (self, optb) {
976                    (a @ Some(_), None) => a,
977                    (None, b @ Some(_)) => b,
978                    _ => Option::None,
979                }
980            }
981
982            /////////////////////////////////////////////////////////////////////////
983            // Misc
984            /////////////////////////////////////////////////////////////////////////
985
986            /// Zips `self` with another `Option`.
987            ///
988            /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`.
989            /// Otherwise, `None` is returned.
990            ///
991            /// # Examples
992            ///
993            /// ```
994            /// let x = Some(1);
995            /// let y = Some("hi");
996            /// let z = None::<u8>;
997            ///
998            /// assert_eq!(x.zip(y), Some((1, "hi")));
999            /// assert_eq!(x.zip(z), None);
1000            /// ```
1001            pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
1002            where
1003                U: RudaType,
1004            {
1005                match (self, other) {
1006                    (Some(a), Some(b)) => Option::Some((a, b)),
1007                    _ => Option::None,
1008                }
1009            }
1010        }
1011    }
1012
1013    mod expand {
1014        use super::*;
1015        use ComptimeOptionExpand::{None, Some};
1016
1017        #[doc(hidden)]
1018        impl<T: RudaType> ComptimeOptionExpand<T> {
1019            pub fn __expand_is_some_method(&self, _scope: &mut Scope) -> bool {
1020                matches!(*self, Some(_))
1021            }
1022
1023            pub fn __expand_is_some_and_method(
1024                self,
1025                scope: &mut Scope,
1026                f: impl FnOnce(&mut Scope, T::ExpandType) -> bool,
1027            ) -> bool {
1028                match self {
1029                    None => false,
1030                    Some(x) => f(scope, x),
1031                }
1032            }
1033
1034            pub fn __expand_is_none_or_method(
1035                self,
1036                scope: &mut Scope,
1037                f: impl FnOnce(&mut Scope, T::ExpandType) -> bool,
1038            ) -> bool {
1039                match self {
1040                    None => true,
1041                    Some(x) => f(scope, x),
1042                }
1043            }
1044
1045            pub fn __expand_as_ref_method(self, _scope: &mut Scope) -> Self {
1046                self
1047            }
1048
1049            pub fn __expand_as_mut_method(self, _scope: &mut Scope) -> Self {
1050                self
1051            }
1052
1053            fn __expand_len_method(&self, _scope: &mut Scope) -> usize {
1054                match self {
1055                    Some(_) => 1,
1056                    None => 0,
1057                }
1058            }
1059
1060            pub fn __expand_expect_method(self, _scope: &mut Scope, msg: &str) -> T::ExpandType {
1061                match self {
1062                    Some(val) => val,
1063                    None => panic!("{msg}"),
1064                }
1065            }
1066
1067            #[allow(clippy::unnecessary_literal_unwrap)]
1068            pub fn __expand_unwrap_method(self, _scope: &mut Scope) -> T::ExpandType {
1069                match self {
1070                    Some(val) => val,
1071                    None => core::option::Option::None.unwrap(),
1072                }
1073            }
1074
1075            pub fn __expand_unwrap_or_else_method<F>(self, scope: &mut Scope, f: F) -> T::ExpandType
1076            where
1077                F: FnOnce(&mut Scope) -> T::ExpandType,
1078            {
1079                match self {
1080                    Some(x) => x,
1081                    None => f(scope),
1082                }
1083            }
1084
1085            pub fn __expand_map_method<U, F>(
1086                self,
1087                scope: &mut Scope,
1088                f: F,
1089            ) -> ComptimeOptionExpand<U>
1090            where
1091                U: RudaType,
1092                F: FnOnce(&mut Scope, T::ExpandType) -> U::ExpandType,
1093            {
1094                match self {
1095                    Some(x) => Some(f(scope, x)),
1096                    None => None,
1097                }
1098            }
1099
1100            pub fn __expand_inspect_method<F>(self, scope: &mut Scope, f: F) -> Self
1101            where
1102                F: FnOnce(&mut Scope, T::ExpandType),
1103            {
1104                if let Some(x) = self.clone() {
1105                    f(scope, x);
1106                }
1107
1108                self
1109            }
1110
1111            pub fn __expand_map_or_method<U, F>(
1112                self,
1113                scope: &mut Scope,
1114                default: U::ExpandType,
1115                f: F,
1116            ) -> U::ExpandType
1117            where
1118                F: FnOnce(&mut Scope, T::ExpandType) -> U::ExpandType,
1119                U: RudaType,
1120            {
1121                match self {
1122                    Some(t) => f(scope, t),
1123                    None => default,
1124                }
1125            }
1126
1127            pub fn __expand_map_or_else_method<U, D, F>(
1128                self,
1129                scope: &mut Scope,
1130                default: D,
1131                f: F,
1132            ) -> U::ExpandType
1133            where
1134                U: RudaType,
1135                D: FnOnce(&mut Scope) -> U::ExpandType,
1136                F: FnOnce(&mut Scope, T::ExpandType) -> U::ExpandType,
1137            {
1138                match self {
1139                    Some(t) => f(scope, t),
1140                    None => default(scope),
1141                }
1142            }
1143
1144            pub fn __expand_map_or_default_method<U, F>(
1145                self,
1146                scope: &mut Scope,
1147                f: F,
1148            ) -> U::ExpandType
1149            where
1150                U: RudaType + Default + Into<U::ExpandType>,
1151                F: FnOnce(&mut Scope, T::ExpandType) -> U::ExpandType,
1152            {
1153                match self {
1154                    Some(t) => f(scope, t),
1155                    None => U::default().into(),
1156                }
1157            }
1158
1159            pub fn __expand_as_deref_method(
1160                self,
1161                scope: &mut Scope,
1162            ) -> ComptimeOptionExpand<T::Target>
1163            where
1164                T: Deref<Target: RudaType + Sized>,
1165                T::ExpandType: Deref<Target = <T::Target as RudaType>::ExpandType>,
1166            {
1167                self.__expand_map_method(scope, |_, it| (*it).clone())
1168            }
1169
1170            pub fn __expand_as_deref_mut_method(
1171                self,
1172                scope: &mut Scope,
1173            ) -> ComptimeOptionExpand<T::Target>
1174            where
1175                T: DerefMut<Target: RudaType + Sized>,
1176                T::ExpandType: Deref<Target = <T::Target as RudaType>::ExpandType>,
1177            {
1178                self.__expand_map_method(scope, |_, it| (*it).clone())
1179            }
1180
1181            pub fn __expand_and_then_method<U, F>(
1182                self,
1183                scope: &mut Scope,
1184                f: F,
1185            ) -> ComptimeOptionExpand<U>
1186            where
1187                U: RudaType,
1188                F: FnOnce(&mut Scope, T::ExpandType) -> ComptimeOptionExpand<U>,
1189            {
1190                match self {
1191                    Some(x) => f(scope, x),
1192                    None => None,
1193                }
1194            }
1195
1196            pub fn __expand_filter_method<P>(self, scope: &mut Scope, predicate: P) -> Self
1197            where
1198                P: FnOnce(&mut Scope, T::ExpandType) -> bool,
1199            {
1200                if let Some(x) = self
1201                    && predicate(scope, x.clone())
1202                {
1203                    Some(x)
1204                } else {
1205                    None
1206                }
1207            }
1208
1209            pub fn __expand_or_else_method<F>(
1210                self,
1211                scope: &mut Scope,
1212                f: F,
1213            ) -> ComptimeOptionExpand<T>
1214            where
1215                F: FnOnce(&mut Scope) -> ComptimeOptionExpand<T>,
1216            {
1217                match self {
1218                    x @ Some(_) => x,
1219                    None => f(scope),
1220                }
1221            }
1222
1223            // Entry methods that return &mut T excluded for now
1224
1225            pub fn __expand_take_method(&mut self, _scope: &mut Scope) -> ComptimeOptionExpand<T> {
1226                core::mem::take(self)
1227            }
1228
1229            pub fn __expand_take_if_method<P>(
1230                &mut self,
1231                scope: &mut Scope,
1232                predicate: P,
1233            ) -> ComptimeOptionExpand<T>
1234            where
1235                P: FnOnce(&mut Scope, T::ExpandType) -> bool,
1236            {
1237                match self {
1238                    Some(value) if predicate(scope, value.clone()) => {
1239                        self.__expand_take_method(scope)
1240                    }
1241                    _ => None,
1242                }
1243            }
1244
1245            pub fn __expand_replace_method(
1246                &mut self,
1247                _scope: &mut Scope,
1248                value: T::ExpandType,
1249            ) -> ComptimeOptionExpand<T> {
1250                core::mem::replace(self, Some(value))
1251            }
1252
1253            pub fn __expand_zip_with_method<U, F, R>(
1254                self,
1255                scope: &mut Scope,
1256                other: ComptimeOptionExpand<U>,
1257                f: F,
1258            ) -> ComptimeOptionExpand<R>
1259            where
1260                F: FnOnce(&mut Scope, T::ExpandType, U::ExpandType) -> R::ExpandType,
1261                R: RudaType,
1262                U: RudaType,
1263            {
1264                match (self, other) {
1265                    (Some(a), Some(b)) => Some(f(scope, a, b)),
1266                    _ => None,
1267                }
1268            }
1269
1270            pub fn __expand_reduce_method<U, R, F>(
1271                self,
1272                scope: &mut Scope,
1273                other: ComptimeOptionExpand<U>,
1274                f: F,
1275            ) -> ComptimeOptionExpand<R>
1276            where
1277                U: RudaType,
1278                R: RudaType,
1279                T::ExpandType: Into<R::ExpandType>,
1280                U::ExpandType: Into<R::ExpandType>,
1281                F: FnOnce(&mut Scope, T::ExpandType, U::ExpandType) -> R::ExpandType,
1282            {
1283                match (self, other) {
1284                    (Some(a), Some(b)) => Some(f(scope, a, b)),
1285                    (Some(a), _) => Some(a.into()),
1286                    (_, Some(b)) => Some(b.into()),
1287                    _ => None,
1288                }
1289            }
1290        }
1291
1292        impl<T: RudaType> ComptimeOptionExpand<T> {
1293            pub fn __expand_is_none_method(self, scope: &mut crate::dsl::prelude::Scope) -> bool {
1294                !self.__expand_is_some_method(scope)
1295            }
1296            pub fn __expand_unwrap_or_method(
1297                self,
1298                _scope: &mut crate::dsl::prelude::Scope,
1299                default: <T as crate::dsl::prelude::RudaType>::ExpandType,
1300            ) -> <T as crate::dsl::prelude::RudaType>::ExpandType {
1301                {
1302                    match self.clone() {
1303                        OptionExpand::Some(x) => x,
1304                        OptionExpand::None => default,
1305                    }
1306                }
1307            }
1308            pub fn __expand_unwrap_or_default_method(
1309                self,
1310                scope: &mut crate::dsl::prelude::Scope,
1311            ) -> <T as crate::dsl::prelude::RudaType>::ExpandType
1312            where
1313                T: Default + IntoRuntime,
1314            {
1315                {
1316                    match self.clone() {
1317                        OptionExpand::Some(x) => x,
1318                        OptionExpand::None => { T::default() }.__expand_runtime_method(scope),
1319                    }
1320                }
1321            }
1322            pub fn __expand_unwrap_unchecked_method(
1323                self,
1324                _scope: &mut crate::dsl::prelude::Scope,
1325            ) -> <T as crate::dsl::prelude::RudaType>::ExpandType {
1326                {
1327                    match self.clone() {
1328                        OptionExpand::Some(val) => val,
1329                        OptionExpand::None => unsafe { core::hint::unreachable_unchecked() },
1330                    }
1331                }
1332            }
1333            pub fn __expand_and_method<U>(
1334                self,
1335                scope: &mut crate::dsl::prelude::Scope,
1336                optb: <Option<U> as crate::dsl::prelude::RudaType>::ExpandType,
1337            ) -> <Option<U> as crate::dsl::prelude::RudaType>::ExpandType
1338            where
1339                U: RudaType,
1340            {
1341                {
1342                    match self.clone() {
1343                        OptionExpand::Some(_) => optb,
1344                        OptionExpand::None => Option::__expand_new_None(scope),
1345                    }
1346                }
1347            }
1348            pub fn __expand_or_method(
1349                self,
1350                _scope: &mut crate::dsl::prelude::Scope,
1351                optb: <Option<T> as crate::dsl::prelude::RudaType>::ExpandType,
1352            ) -> <Option<T> as crate::dsl::prelude::RudaType>::ExpandType {
1353                {
1354                    match self.clone() {
1355                        x @ OptionExpand::Some(_) => x,
1356                        OptionExpand::None => optb,
1357                    }
1358                }
1359            }
1360            pub fn __expand_xor_method(
1361                self,
1362                scope: &mut crate::dsl::prelude::Scope,
1363                optb: <Option<T> as crate::dsl::prelude::RudaType>::ExpandType,
1364            ) -> <Option<T> as crate::dsl::prelude::RudaType>::ExpandType {
1365                {
1366                    match (self.clone(), optb.clone()) {
1367                        (a @ OptionExpand::Some(_), OptionExpand::None) => a,
1368                        (OptionExpand::None, b @ OptionExpand::Some(_)) => b,
1369                        _ => Option::__expand_new_None(scope),
1370                    }
1371                }
1372            }
1373            pub fn __expand_zip_method<U>(
1374                self,
1375                scope: &mut crate::dsl::prelude::Scope,
1376                other: <Option<U> as crate::dsl::prelude::RudaType>::ExpandType,
1377            ) -> <Option<(T, U)> as crate::dsl::prelude::RudaType>::ExpandType
1378            where
1379                U: RudaType,
1380            {
1381                {
1382                    match (self.clone(), other.clone()) {
1383                        (OptionExpand::Some(a), OptionExpand::Some(b)) => {
1384                            let _arg_0 = (a, b);
1385                            Option::__expand_Some(scope, _arg_0)
1386                        }
1387                        _ => Option::__expand_new_None(scope),
1388                    }
1389                }
1390            }
1391        }
1392    }
1393
1394    impl<T, U> ComptimeOption<(T, U)> {
1395        /// Unzips an option containing a tuple of two options.
1396        ///
1397        /// If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`.
1398        /// Otherwise, `(None, None)` is returned.
1399        ///
1400        /// # Examples
1401        ///
1402        /// ```
1403        /// let x = Some((1, "hi"));
1404        /// let y = None::<(u8, u32)>;
1405        ///
1406        /// assert_eq!(x.unzip(), (Some(1), Some("hi")));
1407        /// assert_eq!(y.unzip(), (None, None));
1408        /// ```
1409        pub fn unzip(self) -> (Option<T>, Option<U>) {
1410            match self {
1411                Some((a, b)) => (Option::Some(a), Option::Some(b)),
1412                Option::None => (Option::None, Option::None),
1413            }
1414        }
1415    }
1416
1417    impl<T: RudaType, U: RudaType> ComptimeOptionExpand<(T, U)> {
1418        pub fn __expand_unzip_method(
1419            self,
1420            scope: &mut crate::dsl::prelude::Scope,
1421        ) -> <(Option<T>, Option<U>) as crate::dsl::prelude::RudaType>::ExpandType {
1422            {
1423                match self.clone() {
1424                    OptionExpand::Some((a, b)) => (
1425                        {
1426                            let _arg_0 = a;
1427                            Option::__expand_Some(scope, _arg_0)
1428                        },
1429                        {
1430                            let _arg_0 = b;
1431                            Option::__expand_Some(scope, _arg_0)
1432                        },
1433                    ),
1434                    OptionExpand::None => ({ Option::__expand_new_None(scope) }, {
1435                        Option::__expand_new_None(scope)
1436                    }),
1437                }
1438            }
1439        }
1440    }
1441}