Skip to main content

ruda_kernel/dsl/frontend/
runtime_option.rs

1use ruda_kernel_macros::derive_expand;
2
3use crate::dsl::prelude::*;
4
5#[derive_expand(RudaType, RudaTypeMut, IntoRuntime)]
6#[ruda(runtime_variants, no_constructors)]
7pub enum Option<T: RudaType> {
8    /// No value.
9    None,
10    /// Some value of type `T`.
11    Some(T),
12}
13
14fn discriminant(variant_name: &'static str) -> i32 {
15    OptionExpand::<u32>::discriminant_of(variant_name)
16}
17
18pub enum OptionArgs<T: LaunchArg, R: Runtime> {
19    Some(<T as LaunchArg>::RuntimeArg<R>),
20    None,
21}
22
23impl<T: LaunchArg, R: Runtime> From<Option<<T as LaunchArg>::RuntimeArg<R>>> for OptionArgs<T, R> {
24    fn from(value: Option<<T as LaunchArg>::RuntimeArg<R>>) -> Self {
25        match value {
26            Some(arg) => Self::Some(arg),
27            None => Self::None,
28        }
29    }
30}
31
32impl<T: LaunchArg + Default + IntoRuntime> LaunchArg for Option<T> {
33    type RuntimeArg<R: Runtime> = OptionArgs<T, R>;
34    type CompilationArg = OptionCompilationArg<T>;
35
36    fn register<R: Runtime>(
37        arg: Self::RuntimeArg<R>,
38        launcher: &mut KernelLauncher<R>,
39    ) -> Self::CompilationArg {
40        match arg {
41            OptionArgs::Some(arg) => OptionCompilationArg::Some(T::register(arg, launcher)),
42            OptionArgs::None => OptionCompilationArg::None,
43        }
44    }
45
46    fn expand(
47        arg: &Self::CompilationArg,
48        builder: &mut KernelBuilder,
49    ) -> <Self as RudaType>::ExpandType {
50        match arg {
51            OptionCompilationArg::Some(value) => {
52                let value = T::expand(value, builder);
53                OptionExpand {
54                    discriminant: discriminant("Some").into(),
55                    value,
56                }
57            }
58            OptionCompilationArg::None => OptionExpand {
59                discriminant: discriminant("None").into(),
60                value: T::default().__expand_runtime_method(&mut builder.scope),
61            },
62        }
63    }
64
65    fn expand_output(
66        arg: &Self::CompilationArg,
67        builder: &mut KernelBuilder,
68    ) -> <Self as RudaType>::ExpandType {
69        match arg {
70            OptionCompilationArg::Some(value) => {
71                let value = T::expand_output(value, builder);
72                OptionExpand {
73                    discriminant: discriminant("Some").into(),
74                    value,
75                }
76            }
77            OptionCompilationArg::None => OptionExpand {
78                discriminant: discriminant("None").into(),
79                value: T::default().__expand_runtime_method(&mut builder.scope),
80            },
81        }
82    }
83}
84
85pub enum OptionCompilationArg<T: LaunchArg> {
86    Some(T::CompilationArg),
87    None,
88}
89
90impl<T: LaunchArg> Clone for OptionCompilationArg<T> {
91    fn clone(&self) -> Self {
92        match self {
93            OptionCompilationArg::Some(value) => OptionCompilationArg::Some(value.clone()),
94            OptionCompilationArg::None => OptionCompilationArg::None,
95        }
96    }
97}
98
99impl<T: LaunchArg> PartialEq for OptionCompilationArg<T> {
100    fn eq(&self, other: &Self) -> bool {
101        match (self, other) {
102            (Self::Some(l0), Self::Some(r0)) => l0 == r0,
103            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
104        }
105    }
106}
107
108impl<T: LaunchArg> Eq for OptionCompilationArg<T> {}
109
110impl<T: LaunchArg> core::hash::Hash for OptionCompilationArg<T> {
111    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
112        core::mem::discriminant(self).hash(state);
113        match self {
114            OptionCompilationArg::Some(value) => value.hash(state),
115            OptionCompilationArg::None => {}
116        }
117    }
118}
119
120impl<T: LaunchArg> core::fmt::Debug for OptionCompilationArg<T> {
121    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
122        match self {
123            Self::Some(arg0) => f.debug_tuple("Some").field(arg0).finish(),
124            Self::None => write!(f, "None"),
125        }
126    }
127}
128
129/// Extensions for [`Option`]
130#[allow(non_snake_case)]
131pub trait RudaOption<T: RudaType> {
132    /// Create a new [`Option::Some`] in a kernel
133    fn new_Some(_0: T) -> Option<T> {
134        Option::Some(_0)
135    }
136    fn none_with_default(_0: T) -> Option<T> {
137        Option::None
138    }
139
140    #[doc(hidden)]
141    fn __expand_Some(scope: &mut Scope, value: T::ExpandType) -> OptionExpand<T> {
142        Self::__expand_new_Some(scope, value)
143    }
144    #[doc(hidden)]
145    fn __expand_new_Some(_scope: &mut Scope, value: T::ExpandType) -> OptionExpand<T> {
146        OptionExpand::<T> {
147            discriminant: discriminant("Some").into(),
148            value,
149        }
150    }
151    fn __expand_none_with_default(_scope: &mut Scope, value: T::ExpandType) -> OptionExpand<T> {
152        OptionExpand {
153            discriminant: discriminant("None").into(),
154            value,
155        }
156    }
157}
158
159/// Extensions for [`Option`] that require default
160#[allow(non_snake_case)]
161pub trait RudaOptionDefault<T: RudaType + Default + IntoRuntime>: RudaOption<T> {
162    /// Create a new [`Option::None`] in a kernel
163    fn new_None() -> Option<T> {
164        Option::None
165    }
166
167    #[doc(hidden)]
168    fn __expand_new_None(scope: &mut Scope) -> OptionExpand<T> {
169        let value = T::default().__expand_runtime_method(scope);
170        Self::__expand_none_with_default(scope, value)
171    }
172}
173
174impl<T: RudaType> RudaOption<T> for Option<T> {}
175impl<T: RudaType + Default + IntoRuntime> RudaOptionDefault<T> for Option<T> {}
176
177mod impls {
178    use core::ops::{Deref, DerefMut};
179
180    use super::*;
181
182    /////////////////////////////////////////////////////////////////////////////
183    // Type implementation
184    /////////////////////////////////////////////////////////////////////////////
185
186    #[doc(hidden)]
187    impl<T: RudaType> OptionExpand<T> {
188        pub fn __expand_is_some_and_method(
189            self,
190            scope: &mut Scope,
191            f: impl FnOnce(&mut Scope, T::ExpandType) -> NativeExpand<bool>,
192        ) -> NativeExpand<bool> {
193            match_expand_expr(scope, self, discriminant("None"), |_, _| false.into())
194                .case(scope, discriminant("Some"), |scope, value| f(scope, value))
195                .finish(scope)
196        }
197
198        pub fn __expand_is_none_or_method(
199            self,
200            scope: &mut Scope,
201            f: impl FnOnce(&mut Scope, T::ExpandType) -> NativeExpand<bool>,
202        ) -> NativeExpand<bool> {
203            match_expand_expr(scope, self, discriminant("None"), |_, _| true.into())
204                .case(scope, discriminant("Some"), |scope, value| f(scope, value))
205                .finish(scope)
206        }
207
208        pub fn __expand_as_ref_method(&self, _scope: &mut Scope) -> OptionExpand<T> {
209            self.clone()
210        }
211
212        pub fn __expand_as_mut_method(&mut self, _scope: &mut Scope) -> OptionExpand<T> {
213            self.clone()
214        }
215
216        pub fn __expand_expect_method(self, scope: &mut Scope, msg: &str) -> T::ExpandType
217        where
218            T::ExpandType: Assign,
219        {
220            // Replace with `trap` eventually to ensure execution doesn't continue to the next kernel
221            match_expand_expr(scope, self, discriminant("Some"), |_, value| value)
222                .case(scope, discriminant("None"), |scope, value| {
223                    printf_expand(scope, msg, alloc::vec![]);
224                    terminate!();
225                    value
226                })
227                .finish(scope)
228        }
229
230        pub fn __expand_unwrap_or_else_method<F>(self, scope: &mut Scope, f: F) -> T::ExpandType
231        where
232            F: FnOnce(&mut Scope) -> T::ExpandType,
233            T::ExpandType: Assign,
234        {
235            match_expand_expr(scope, self, discriminant("Some"), |_, value| value)
236                .case(scope, discriminant("None"), |scope, _| f(scope))
237                .finish(scope)
238        }
239
240        pub fn __expand_map_method<U, F>(self, scope: &mut Scope, f: F) -> OptionExpand<U>
241        where
242            F: FnOnce(&mut Scope, T::ExpandType) -> U::ExpandType,
243            U: RudaType + IntoRuntime + Default,
244            OptionExpand<U>: Assign,
245        {
246            match_expand_expr(scope, self, discriminant("Some"), |scope, value| {
247                let value = f(scope, value);
248                Option::__expand_new_Some(scope, value)
249            })
250            .case(scope, discriminant("None"), |scope, _| {
251                Option::__expand_new_None(scope)
252            })
253            .finish(scope)
254        }
255
256        pub fn __expand_inspect_method<F>(self, scope: &mut Scope, f: F) -> Self
257        where
258            F: FnOnce(&mut Scope, &T::ExpandType),
259        {
260            match_expand(scope, self.clone(), discriminant("Some"), |scope, value| {
261                f(scope, &value)
262            })
263            .case(scope, discriminant("None"), |_, _| {})
264            .finish(scope);
265            self
266        }
267
268        pub fn __expand_map_or_method<U, F>(
269            self,
270            scope: &mut Scope,
271            default: U::ExpandType,
272            f: F,
273        ) -> U::ExpandType
274        where
275            F: FnOnce(&mut Scope, T::ExpandType) -> U::ExpandType,
276            U: RudaType + Default + IntoRuntime,
277            U::ExpandType: Assign,
278        {
279            match_expand_expr(scope, self, discriminant("Some"), f)
280                .case(scope, discriminant("None"), |_, _| default)
281                .finish(scope)
282        }
283
284        pub fn __expand_map_or_else_method<U, D, F>(
285            self,
286            scope: &mut Scope,
287            default: D,
288            f: F,
289        ) -> U::ExpandType
290        where
291            D: FnOnce(&mut Scope) -> U::ExpandType,
292            F: FnOnce(&mut Scope, T::ExpandType) -> U::ExpandType,
293            U: RudaType + Default + IntoRuntime,
294            U::ExpandType: Assign,
295        {
296            match_expand_expr(scope, self, discriminant("Some"), f)
297                .case(scope, discriminant("None"), |scope, _| default(scope))
298                .finish(scope)
299        }
300
301        pub fn __expand_map_or_default_method<U, F>(self, scope: &mut Scope, f: F) -> U::ExpandType
302        where
303            U: RudaType + IntoRuntime + Default,
304            F: FnOnce(&mut Scope, T::ExpandType) -> U::ExpandType,
305            U::ExpandType: Assign,
306        {
307            match_expand_expr(scope, self, discriminant("Some"), f)
308                .case(scope, discriminant("None"), |scope, _| {
309                    U::default().__expand_runtime_method(scope)
310                })
311                .finish(scope)
312        }
313
314        pub fn __expand_as_deref_method(self, scope: &mut Scope) -> OptionExpand<T::Target>
315        where
316            T: Deref<Target: RudaType + Default + IntoRuntime>,
317            T::ExpandType: Deref<Target = <T::Target as RudaType>::ExpandType>,
318            <T::Target as RudaType>::ExpandType: Assign,
319        {
320            self.__expand_map_method(scope, |_, value| (*value).clone())
321        }
322
323        pub fn __expand_as_deref_mut_method(self, scope: &mut Scope) -> OptionExpand<T::Target>
324        where
325            T: DerefMut<Target: RudaType + Default + IntoRuntime>,
326            T::ExpandType: Deref<Target = <T::Target as RudaType>::ExpandType>,
327            <T::Target as RudaType>::ExpandType: Assign,
328        {
329            self.__expand_map_method(scope, |_, value| (*value).clone())
330        }
331
332        pub fn __expand_and_then_method<U, F>(self, scope: &mut Scope, f: F) -> OptionExpand<U>
333        where
334            F: FnOnce(&mut Scope, T::ExpandType) -> OptionExpand<U>,
335            U: RudaType + IntoRuntime + Default,
336            U::ExpandType: Assign,
337        {
338            match_expand_expr(scope, self, discriminant("Some"), f)
339                .case(scope, discriminant("None"), |scope, _| {
340                    Option::__expand_new_None(scope)
341                })
342                .finish(scope)
343        }
344
345        pub fn __expand_filter_method<P>(self, scope: &mut Scope, predicate: P) -> Self
346        where
347            P: FnOnce(&mut Scope, T::ExpandType) -> NativeExpand<bool>,
348            T: Default + IntoRuntime,
349            Self: Assign,
350        {
351            match_expand_expr(scope, self, discriminant("Some"), |scope, value| {
352                let cond = predicate(scope, value.clone());
353                if_else_expr_expand(scope, cond, |scope| Option::__expand_new_Some(scope, value))
354                    .or_else(scope, |scope| Option::__expand_new_None(scope))
355            })
356            .case(scope, discriminant("None"), |scope, _| {
357                Option::__expand_new_None(scope)
358            })
359            .finish(scope)
360        }
361
362        pub fn __expand_or_else_method<F>(self, scope: &mut Scope, f: F) -> OptionExpand<T>
363        where
364            F: FnOnce(&mut Scope) -> OptionExpand<T>,
365            OptionExpand<T>: Assign,
366        {
367            let is_some = self.clone().__expand_is_some_method(scope);
368            if_else_expr_expand(scope, is_some, |_| self).or_else(scope, |scope| f(scope))
369        }
370
371        pub fn __expand_zip_with_method<U, F, R>(
372            self,
373            scope: &mut Scope,
374            other: OptionExpand<U>,
375            f: F,
376        ) -> OptionExpand<R>
377        where
378            F: FnOnce(&mut Scope, T::ExpandType, U::ExpandType) -> R::ExpandType,
379            U: RudaType,
380            R: RudaType + IntoRuntime + Default,
381            OptionExpand<R>: Assign,
382        {
383            match_expand_expr(scope, self, discriminant("Some"), |scope, value| {
384                match_expand_expr(scope, other, discriminant("Some"), |scope, other| {
385                    let value = f(scope, value, other);
386                    Option::__expand_new_Some(scope, value)
387                })
388                .case(scope, discriminant("None"), |scope, _| {
389                    Option::__expand_new_None(scope)
390                })
391                .finish(scope)
392            })
393            .case(scope, discriminant("None"), |scope, _| {
394                Option::__expand_new_None(scope)
395            })
396            .finish(scope)
397        }
398
399        pub fn __expand_reduce_method<U, R, F>(
400            self,
401            scope: &mut Scope,
402            other: OptionExpand<U>,
403            f: F,
404        ) -> OptionExpand<R>
405        where
406            T::ExpandType: Into<R::ExpandType>,
407            U::ExpandType: Into<R::ExpandType>,
408            F: FnOnce(&mut Scope, T::ExpandType, U::ExpandType) -> R::ExpandType,
409            U: RudaType + IntoRuntime + Default,
410            R: RudaType + IntoRuntime + Default,
411            OptionExpand<R>: Assign,
412        {
413            match_expand_expr(scope, self, discriminant("Some"), {
414                let other = other.clone();
415                |scope, value| {
416                    match_expand_expr(scope, other, discriminant("Some"), {
417                        let value = value.clone();
418                        |scope, other| {
419                            let value = f(scope, value, other);
420                            Option::__expand_new_Some(scope, value)
421                        }
422                    })
423                    .case(scope, discriminant("None"), |scope, _| {
424                        Option::__expand_new_Some(scope, value.into())
425                    })
426                    .finish(scope)
427                }
428            })
429            .case(scope, discriminant("None"), |scope, _| {
430                match_expand_expr(scope, other, discriminant("Some"), |scope, other| {
431                    Option::__expand_new_Some(scope, other.into())
432                })
433                .case(scope, discriminant("None"), |scope, _| {
434                    Option::__expand_new_None(scope)
435                })
436                .finish(scope)
437            })
438            .finish(scope)
439        }
440
441        #[allow(clippy::missing_safety_doc)]
442        pub unsafe fn __expand_unwrap_unchecked_method(self, scope: &mut Scope) -> T::ExpandType
443        where
444            T::ExpandType: Assign,
445        {
446            match_expand_expr(scope, self, discriminant("Some"), |_, value| value).finish(scope)
447        }
448    }
449
450    #[ruda(expand_only)]
451    impl<T: RudaType> Option<T> {
452        /////////////////////////////////////////////////////////////////////////
453        // Querying the contained values
454        /////////////////////////////////////////////////////////////////////////
455
456        /// Returns `true` if the option is a [`Some`] value.
457        ///
458        /// # Examples
459        ///
460        /// ```
461        /// let x: Option<u32> = Some(2);
462        /// assert_eq!(x.is_some(), true);
463        ///
464        /// let x: Option<u32> = None;
465        /// assert_eq!(x.is_some(), false);
466        /// ```
467        pub fn is_some(&self) -> bool {
468            match self {
469                Option::Some(_) => true.runtime(),
470                Option::None => false.runtime(),
471            }
472        }
473
474        /// Returns `true` if the option is a [`None`] value.
475        ///
476        /// # Examples
477        ///
478        /// ```
479        /// let x: Option<u32> = Some(2);
480        /// assert_eq!(x.is_none(), false);
481        ///
482        /// let x: Option<u32> = None;
483        /// assert_eq!(x.is_none(), true);
484        /// ```
485        #[must_use = "if you intended to assert that this doesn't have a value, consider \
486                  wrapping this in an `assert!()` instead"]
487        pub fn is_none(&self) -> bool {
488            !self.is_some()
489        }
490
491        /////////////////////////////////////////////////////////////////////////
492        // Getting to contained values
493        /////////////////////////////////////////////////////////////////////////
494
495        /// Returns the contained [`Some`] value, consuming the `self` value.
496        ///
497        /// Because this function may panic, its use is generally discouraged.
498        /// Panics are meant for unrecoverable errors, and
499        /// [may abort the entire program][panic-abort].
500        ///
501        /// Instead, prefer to use pattern matching and handle the [`None`]
502        /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or
503        /// [`unwrap_or_default`]. In functions returning `Option`, you can use
504        /// [the `?` (try) operator][try-option].
505        ///
506        /// [panic-abort]: https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html
507        /// [try-option]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#where-the--operator-can-be-used
508        /// [`unwrap_or`]: Option::unwrap_or
509        /// [`unwrap_or_else`]: Option::unwrap_or_else
510        /// [`unwrap_or_default`]: Option::unwrap_or_default
511        ///
512        /// # Panics
513        ///
514        /// Panics if the self value equals [`None`].
515        ///
516        /// # Examples
517        ///
518        /// ```
519        /// let x = Some("air");
520        /// assert_eq!(x.unwrap(), "air");
521        /// ```
522        ///
523        /// ```should_panic
524        /// let x: Option<&str> = None;
525        /// assert_eq!(x.unwrap(), "air"); // fails
526        /// ```
527        pub fn unwrap(self) -> T
528        where
529            T::ExpandType: Assign,
530        {
531            self.expect("called `Option::unwrap()` on a `None` value")
532        }
533
534        /// Returns the contained [`Some`] value or a provided default.
535        ///
536        /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
537        /// the result of a function call, it is recommended to use [`unwrap_or_else`],
538        /// which is lazily evaluated.
539        ///
540        /// [`unwrap_or_else`]: Option::unwrap_or_else
541        ///
542        /// # Examples
543        ///
544        /// ```
545        /// assert_eq!(Some("car").unwrap_or("bike"), "car");
546        /// assert_eq!(None.unwrap_or("bike"), "bike");
547        /// ```
548        pub fn unwrap_or(self, default: T) -> T
549        where
550            T::ExpandType: Assign,
551        {
552            match self {
553                Some(x) => x,
554                None => default,
555            }
556        }
557
558        /// Returns the contained [`Some`] value or a default.
559        ///
560        /// Consumes the `self` argument then, if [`Some`], returns the contained
561        /// value, otherwise if [`None`], returns the [default value] for that
562        /// type.
563        ///
564        /// # Examples
565        ///
566        /// ```
567        /// let x: Option<u32> = None;
568        /// let y: Option<u32> = Some(12);
569        ///
570        /// assert_eq!(x.unwrap_or_default(), 0);
571        /// assert_eq!(y.unwrap_or_default(), 12);
572        /// ```
573        ///
574        /// [default value]: Default::default
575        /// [`parse`]: str::parse
576        /// [`FromStr`]: crate::dsl::str::FromStr
577        pub fn unwrap_or_default(self) -> T
578        where
579            T: Default + IntoRuntime,
580            T::ExpandType: Assign,
581        {
582            match self {
583                Some(x) => x,
584                None => comptime![T::default()].runtime(),
585            }
586        }
587
588        /////////////////////////////////////////////////////////////////////////
589        // Transforming contained values
590        /////////////////////////////////////////////////////////////////////////
591
592        /////////////////////////////////////////////////////////////////////////
593        // Boolean operations on the values, eager and lazy
594        /////////////////////////////////////////////////////////////////////////
595
596        /// Returns [`None`] if the option is [`None`], otherwise returns `optb`.
597        ///
598        /// Arguments passed to `and` are eagerly evaluated; if you are passing the
599        /// result of a function call, it is recommended to use [`and_then`], which is
600        /// lazily evaluated.
601        ///
602        /// [`and_then`]: Option::and_then
603        ///
604        /// # Examples
605        ///
606        /// ```
607        /// let x = Some(2);
608        /// let y: Option<&str> = None;
609        /// assert_eq!(x.and(y), None);
610        ///
611        /// let x: Option<u32> = None;
612        /// let y = Some("foo");
613        /// assert_eq!(x.and(y), None);
614        ///
615        /// let x = Some(2);
616        /// let y = Some("foo");
617        /// assert_eq!(x.and(y), Some("foo"));
618        ///
619        /// let x: Option<u32> = None;
620        /// let y: Option<&str> = None;
621        /// assert_eq!(x.and(y), None);
622        /// ```
623        pub fn and<U>(self, optb: Option<U>) -> Option<U>
624        where
625            U: RudaType + IntoRuntime + Default,
626            U::ExpandType: Assign,
627        {
628            match self {
629                Option::Some(_) => optb,
630                Option::None => Option::new_None(),
631            }
632        }
633
634        /// Returns the option if it contains a value, otherwise returns `optb`.
635        ///
636        /// Arguments passed to `or` are eagerly evaluated; if you are passing the
637        /// result of a function call, it is recommended to use [`or_else`], which is
638        /// lazily evaluated.
639        ///
640        /// [`or_else`]: Option::or_else
641        ///
642        /// # Examples
643        ///
644        /// ```
645        /// let x = Some(2);
646        /// let y = None;
647        /// assert_eq!(x.or(y), Some(2));
648        ///
649        /// let x = None;
650        /// let y = Some(100);
651        /// assert_eq!(x.or(y), Some(100));
652        ///
653        /// let x = Some(2);
654        /// let y = Some(100);
655        /// assert_eq!(x.or(y), Some(2));
656        ///
657        /// let x: Option<u32> = None;
658        /// let y = None;
659        /// assert_eq!(x.or(y), None);
660        /// ```
661        pub fn or(self, optb: Option<T>) -> Option<T>
662        where
663            T::ExpandType: Assign,
664        {
665            if self.is_some() { self } else { optb }
666        }
667
668        /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns [`None`].
669        ///
670        /// # Examples
671        ///
672        /// ```
673        /// let x = Some(2);
674        /// let y: Option<u32> = None;
675        /// assert_eq!(x.xor(y), Some(2));
676        ///
677        /// let x: Option<u32> = None;
678        /// let y = Some(2);
679        /// assert_eq!(x.xor(y), Some(2));
680        ///
681        /// let x = Some(2);
682        /// let y = Some(2);
683        /// assert_eq!(x.xor(y), None);
684        ///
685        /// let x: Option<u32> = None;
686        /// let y: Option<u32> = None;
687        /// assert_eq!(x.xor(y), None);
688        /// ```
689        pub fn xor(self, optb: Option<T>) -> Option<T>
690        where
691            T: Default + IntoRuntime,
692            T::ExpandType: Assign,
693        {
694            if self.is_some() && optb.is_none() {
695                self
696            } else if self.is_none() && optb.is_some() {
697                optb
698            } else {
699                Option::new_None()
700            }
701        }
702
703        /////////////////////////////////////////////////////////////////////////
704        // Misc
705        /////////////////////////////////////////////////////////////////////////
706
707        // TODO: `take`/`take_if`/`replace`
708
709        /// Zips `self` with another `Option`.
710        ///
711        /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`.
712        /// Otherwise, `None` is returned.
713        ///
714        /// # Examples
715        ///
716        /// ```
717        /// let x = Some(1);
718        /// let y = Some("hi");
719        /// let z = None::<u8>;
720        ///
721        /// assert_eq!(x.zip(y), Some((1, "hi")));
722        /// assert_eq!(x.zip(z), None);
723        /// ```
724        pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
725        where
726            U: RudaType,
727            (T, U): Default + IntoRuntime,
728            (T::ExpandType, U::ExpandType): Into<<(T, U) as RudaType>::ExpandType>,
729            OptionExpand<(T, U)>: Assign,
730        {
731            match self {
732                Some(a) => match other {
733                    Some(b) => Option::Some((a, b)),
734                    None => Option::new_None(),
735                },
736                None => Option::new_None(),
737            }
738        }
739    }
740
741    #[ruda(expand_only)]
742    impl<
743        T: RudaType<ExpandType: Assign> + IntoRuntime + Default,
744        U: RudaType<ExpandType: Assign> + IntoRuntime + Default,
745    > Option<(T, U)>
746    {
747        /// Unzips an option containing a tuple of two options.
748        ///
749        /// If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`.
750        /// Otherwise, `(None, None)` is returned.
751        ///
752        /// # Examples
753        ///
754        /// ```
755        /// let x = Some((1, "hi"));
756        /// let y = None::<(u8, u32)>;
757        ///
758        /// assert_eq!(x.unzip(), (Some(1), Some("hi")));
759        /// assert_eq!(y.unzip(), (None, None));
760        /// ```
761        #[inline]
762        pub fn unzip(self) -> (Option<T>, Option<U>) {
763            match self {
764                Option::Some(value) => (Option::Some(value.0), Option::Some(value.1)),
765                Option::None => (Option::new_None(), Option::new_None()),
766            }
767        }
768    }
769}