Skip to main content

try_v2_traits/
extract.rs

1use std::{
2    fmt::Debug,
3    ops::{ControlFlow, Try},
4};
5
6impl<T> Extract<T> for Option<T> {}
7impl<T, E> Extract<T> for Result<T, E> {}
8impl<B, C> Extract<C> for ControlFlow<B, C> {}
9
10/// Methods for extracting the wrapped value
11pub trait Extract<T>
12where
13    Self: Try<Output = T> + Sized,
14{
15    /// Extracts the contained value `v` returning `Some(v)`, or `None` in the case of a Residual
16    ///
17    /// Think of this as the non-panicking version of `unwrap()`
18    fn output(self) -> Option<T> {
19        match self.branch() {
20            ControlFlow::Continue(val) => Some(val),
21            ControlFlow::Break(_) => None,
22        }
23    }
24
25    /// Return the contained value or panic with a generic message.
26    ///
27    /// In general you should prefer `expect()` for panic situations or `output()` for non-panic
28    ///
29    /// # Note to implementors
30    /// - the provided implementation uses [`Extract::expect`]. Implementors should prefer
31    ///   customising `expect` to directly customising `unwrap`.
32    fn unwrap(self) -> T
33    where
34        Self::Residual: Debug,
35    {
36        self.expect("called `unwrap()` on a residual:")
37    }
38
39    /// Return the contained value or panic with a custom message.
40    ///
41    /// In general you should prefer `output()` or `?` which do not panic.
42    fn expect(self, msg: &str) -> T
43    where
44        Self::Residual: Debug,
45    {
46        match self.branch() {
47            ControlFlow::Continue(v) => v,
48            #[cfg(not(panic = "immediate-abort"))]
49            ControlFlow::Break(r) => panic!("{msg}: {r:?}"),
50            #[cfg(panic = "immediate-abort")]
51            ControlFlow::Break(_) => panic!(),
52        }
53    }
54
55    /// Return the contained value or the given default.
56    ///
57    /// Arguments passed to unwrap_or are eagerly evaluated; if you are passing the result of a
58    /// function call, it is recommended to use unwrap_or_else, which is lazily evaluated.
59    ///
60    /// # Note to implementors
61    /// - the provided implementation uses [`Extract::unwrap_or_else`]. Implementors should prefer
62    ///   customising `unwrap_or_else` to directly customising `unwrap_or`.
63    fn unwrap_or(self, default: T) -> T {
64        self.unwrap_or_else(|| default)
65    }
66
67    /// Return the contained value or a default. Requires `T` to implement `Default`
68    ///
69    /// # Note to implementors
70    /// - the provided implementation uses [`Extract::unwrap_or_else`]. Implementors should prefer
71    ///   customising `unwrap_or_else` to directly customising `unwrap_or_default`.
72    fn unwrap_or_default(self) -> T
73    where
74        T: Default,
75    {
76        self.unwrap_or_else(Default::default)
77    }
78
79    /// Return the contained value or a value computed from a closure.
80    fn unwrap_or_else<F>(self, f: F) -> T
81    where
82        F: FnOnce() -> T,
83    {
84        match self.branch() {
85            ControlFlow::Continue(v) => v,
86            ControlFlow::Break(_) => f(),
87        }
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    mod output {
96        use super::*;
97
98        #[test]
99        fn ok() {
100            let ok_5: Result<_, ()> = Ok(5);
101            let stdlib = ok_5.ok();
102            let custom = ok_5.output();
103            assert_eq!(stdlib, custom);
104        }
105    }
106}