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}