nothing/
lib.rs

1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
2
3#![feature(try_trait_v2)]
4
5/// [Probably] is a better [Option]:
6/// - [Something] is like [Some]
7/// - [Nothing] is like [None]
8#[derive(is_macro::Is, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, Hash, Default)]
9pub enum Probably<T> {
10    /// No value.
11    #[default]
12    Nothing,
13    /// Some value of type `T`.
14    Something(T),
15}
16
17pub use Probably::{Nothing, Something};
18
19impl<T> std::process::Termination for Probably<T> {
20    fn report(self) -> std::process::ExitCode {
21        match self {
22            Nothing => std::process::ExitCode::FAILURE,
23            _ => std::process::ExitCode::SUCCESS,
24        }
25    }
26}
27
28impl<T> std::ops::FromResidual for Probably<T> {
29    fn from_residual(residual: Probably<std::convert::Infallible>) -> Self {
30        match residual {
31            Nothing => Nothing,
32            Something(_) => todo!(),
33        }
34    }
35}
36
37impl<T> std::ops::Try for Probably<T> {
38    type Output = T;
39    type Residual = Probably<std::convert::Infallible>;
40
41    fn from_output(output: Self::Output) -> Self {
42        Something(output)
43    }
44
45    fn branch(self) -> std::ops::ControlFlow<Self::Residual, Self::Output> {
46        match self {
47            Something(v) => std::ops::ControlFlow::Continue(v),
48            Nothing => std::ops::ControlFlow::Break(Nothing),
49        }
50    }
51}
52
53impl<T> From<T> for Probably<T> {
54    fn from(x: T) -> Self {
55        Something(x)
56    }
57}
58
59impl<T> From<Option<T>> for Probably<T> {
60    fn from(x: Option<T>) -> Self {
61        match x {
62            Some(v) => Something(v),
63            None => Nothing,
64        }
65    }
66}
67
68impl<T> Into<Option<T>> for Probably<T> {
69    fn into(self) -> Option<T> {
70        match self {
71            Something(x) => Some(x),
72            Nothing => None,
73        }
74    }
75}
76
77impl<T> Probably<Probably<T>> {
78    /// Converts from `Probably<Probably<T>>` to `Probably<T>`.
79    ///
80    /// # Examples
81    ///
82    /// Basic usage:
83    ///
84    /// ```
85    /// let x: Probably<Probably<u32>> = Something(Something(6));
86    /// assert_eq!(Something(6), x.flatten());
87    ///
88    /// let x: Probably<Probably<u32>> = Something(Nothing);
89    /// assert_eq!(Nothing, x.flatten());
90    ///
91    /// let x: Probably<Probably<u32>> = Nothing;
92    /// assert_eq!(Nothing, x.flatten());
93    /// ```
94    ///
95    ///
96    /// Flattening only removes one level of nesting at a time:
97    ///
98    /// ```
99    /// let x: Probably<Probably<Probably<u32>>> = Something(Something(Something(6)));
100    /// assert_eq!(Something(Something(6)), x.flatten());
101    /// assert_eq!(Something(6), x.flatten().flatten());
102    /// ```
103    pub fn flatten(self) -> Probably<T> {
104        match self {
105            Something(inner) => inner,
106            Nothing => Nothing,
107        }
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn it_works() {
117        let result = 2 + 2;
118        assert_eq!(result, 4);
119    }
120
121    #[test]
122    fn from_option_works() {
123        let some = Some(42u8);
124        let sth: Probably<u8> = some.into();
125        assert_eq!(sth, Something(42u8));
126    }
127
128    #[test]
129    fn from_unit_works() {
130        let unit = ();
131        let sth: Probably<()> = unit.into();
132        assert_eq!(sth, Something(()));
133    }
134
135    #[test]
136    fn from_some_works() {
137        let unit = Some(());
138        let sth: Probably<()> = unit.into();
139        assert_eq!(sth, Something(()));
140    }
141}