another_option/
lib.rs

1//! # `another-option`
2//!
3//! This package provides `Opt<T>` as an alternative to `Option<T>`. Why would you want another
4//! option? `Opt` provides advantages when:
5//!
6//! 1. the generic type, `T`, is expensive to allocate, and
7//! 2. mutation between `None` and `Some(...)` is frequent.
8//!
9//! ## Examples
10//!
11//! Since Rust's built-in `Option<T>` is an enum, it will drop its `Some(...)` value when `None`
12//! is assigned.
13//!
14//! ```rust
15//! let mut option: Option<String> = Some(String::with_capacity(1024));
16//! option = None; // drops the string
17//! option = Some(String::with_capacity(1024)); // allocation
18//! ```
19//!
20//! Since `Opt<T>` always owns the value, even when empty, the value can be reused without drops
21//! or allocations:
22//!
23//! ```rust
24//! use crate::another_option::Opt;
25//! let mut opt: Opt<String> = Opt::some(String::with_capacity(1024));
26//! opt.map_in_place(|v| v.push_str("value"));
27//! opt.set_none(); // does *not* drop the string
28//! opt.set_some();
29//! assert_eq!(opt.unwrap(), String::from("value"));
30//! ```
31
32#[derive(Copy, Clone, PartialOrd, Eq, Ord, Debug, Hash)]
33pub struct Opt<T> {
34    empty: bool,
35    value: T,
36}
37
38impl<T> PartialEq for Opt<T>
39where
40    T: std::cmp::PartialEq,
41{
42    fn eq(&self, other: &Self) -> bool {
43        if self.empty && other.empty {
44            true
45        } else if !self.empty && !other.empty {
46            self.value == other.value
47        } else {
48            false
49        }
50    }
51}
52
53impl<T> Opt<T> {
54    /// Construct an option with no value.
55    ///
56    /// Note: perhaps unexpectedly, this function accepts a `value` argument. This is necessary
57    /// given the underlying data structure.
58    pub fn none(value: T) -> Opt<T> {
59        Opt { empty: true, value }
60    }
61
62    /// Construct an option with 'some' value.
63    pub fn some(value: T) -> Opt<T> {
64        Opt {
65            empty: false,
66            value,
67        }
68    }
69}
70
71impl<T> Opt<T> {
72    // ===== querying the contained value =====
73
74    pub fn is_none(&self) -> bool {
75        self.empty
76    }
77
78    pub fn is_some(&self) -> bool {
79        !self.empty
80    }
81
82    // ===== setters =====
83
84    pub fn set_none(&mut self) {
85        self.empty = true;
86    }
87
88    pub fn set_some(&mut self) {
89        self.empty = false;
90    }
91
92    pub fn set_some_value(&mut self, value: T) {
93        self.empty = false;
94        self.value = value;
95    }
96
97    // ===== working with references =====
98
99    /// Converts from `&Opt<T>` to `Opt<&T>`.
100    pub fn as_ref(&self) -> Opt<&T> {
101        Opt {
102            empty: self.empty,
103            value: &self.value,
104        }
105    }
106
107    /// Converts from `&mut Opt<T>` to `Opt<&mut T>`.
108    pub fn as_mut(&mut self) -> Opt<&mut T> {
109        Opt {
110            empty: self.empty,
111            value: &mut self.value,
112        }
113    }
114
115    // ===== convert to/from `Option<T>` =====
116
117    // TODO: Does this make sense?
118    //  - if yes, do it and test it.
119    //  - if no, explain why not.
120
121    // ===== accessing the contained value =====
122
123    pub fn expect(self, msg: &str) -> T {
124        if !self.empty {
125            self.value
126        } else {
127            panic!("{}", msg);
128        }
129    }
130
131    pub fn unwrap(self) -> T {
132        if !self.empty {
133            self.value
134        } else {
135            panic!("called `unwrap()` on an empty value")
136        }
137    }
138
139    pub fn unwrap_or(self, default: T) -> T {
140        if !self.empty {
141            self.value
142        } else {
143            default
144        }
145    }
146
147    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
148        if !self.empty {
149            self.value
150        } else {
151            f()
152        }
153    }
154
155    // ===== transforming the contained value =====
156
157    /// Applies the function `f` to the value; regardless if `Opt<T>` is empty or not. Does not
158    /// modify the 'emptiness' of the option. (Note: This behavior, though consistent, may seem
159    /// strange at first.)
160    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {
161        Opt {
162            empty: self.empty,
163            value: f(self.value),
164        }
165    }
166
167    pub fn map_in_place<F: FnOnce(&mut T)>(&mut self, f: F) {
168        f(&mut self.value);
169    }
170
171    pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
172        if !self.empty {
173            f(self.value)
174        } else {
175            default
176        }
177    }
178
179    pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
180        if !self.empty {
181            f(self.value)
182        } else {
183            default()
184        }
185    }
186
187    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
188        if !self.empty {
189            Ok(self.value)
190        } else {
191            Err(err)
192        }
193    }
194
195    pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
196        if !self.empty {
197            Ok(self.value)
198        } else {
199            Err(err())
200        }
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207
208    // ===== equality tests =====
209
210    #[test]
211    fn test_eq_none() {
212        let none_1: Opt<String> = Opt::none(String::with_capacity(22));
213        let none_2: Opt<String> = Opt::none(String::with_capacity(44));
214        assert_eq!(none_1, none_2);
215    }
216
217    #[test]
218    fn test_eq_some() {
219        let some_thing_1: Opt<String> = Opt::some(String::from("thing"));
220        let some_thing_2: Opt<String> = Opt::some(String::from("thing"));
221        assert_eq!(some_thing_1, some_thing_2);
222    }
223
224    #[test]
225    fn test_ne_some() {
226        let some_day: Opt<String> = Opt::some(String::from("day"));
227        let some_where: Opt<String> = Opt::some(String::from("where"));
228        assert_ne!(some_day, some_where);
229    }
230
231    #[test]
232    fn test_ne_some_none() {
233        let some: Opt<String> = Opt::some(String::from("future"));
234        let none: Opt<String> = Opt::none(String::with_capacity(22));
235        assert_ne!(some, none);
236    }
237
238    // ===== `is_some` and `is_none` tests =====
239
240    #[test]
241    fn test_is_some_some() {
242        let opt: Opt<i16> = Opt::some(42);
243        assert_eq!(opt.is_none(), false);
244        assert_eq!(opt.is_some(), true);
245    }
246
247    #[test]
248    fn test_is_none_none() {
249        let opt: Opt<i16> = Opt::none(13);
250        assert_eq!(opt.is_none(), true);
251        assert_eq!(opt.is_some(), false);
252    }
253
254    // ===== setter tests =====
255
256    #[test]
257    fn test_set_none_1() {
258        let mut opt: Opt<i16> = Opt::none(13);
259        opt.set_none();
260        assert_eq!(opt.is_none(), true);
261        assert_eq!(opt.is_some(), false);
262    }
263
264    #[test]
265    fn test_set_none_2() {
266        let mut opt: Opt<i16> = Opt::some(42);
267        opt.set_none();
268        assert_eq!(opt.is_none(), true);
269        assert_eq!(opt.is_some(), false);
270    }
271
272    #[test]
273    fn test_set_some_1() {
274        let mut opt: Opt<i16> = Opt::none(13);
275        opt.set_some();
276        assert_eq!(opt.is_none(), false);
277        assert_eq!(opt.is_some(), true);
278        assert_eq!(opt.unwrap(), 13);
279    }
280
281    #[test]
282    fn test_set_some_2() {
283        let mut opt: Opt<i16> = Opt::some(13);
284        opt.set_some();
285        assert_eq!(opt.is_none(), false);
286        assert_eq!(opt.is_some(), true);
287        assert_eq!(opt.unwrap(), 13);
288    }
289
290    #[test]
291    fn test_set_some_value_1() {
292        let mut opt: Opt<i16> = Opt::none(13);
293        opt.set_some_value(7);
294        assert_eq!(opt.is_none(), false);
295        assert_eq!(opt.is_some(), true);
296        assert_eq!(opt.unwrap(), 7);
297    }
298
299    #[test]
300    fn test_set_some_value_2() {
301        let mut opt: Opt<i16> = Opt::some(13);
302        opt.set_some_value(7);
303        assert_eq!(opt.is_none(), false);
304        assert_eq!(opt.is_some(), true);
305        assert_eq!(opt.unwrap(), 7);
306    }
307
308    // ===== `as_ref` tests =====
309
310    #[test]
311    fn test_as_ref_some() {
312        let opt: Opt<i16> = Opt::some(42);
313        assert_eq!(opt.as_ref(), Opt::some(&42));
314    }
315
316    #[test]
317    fn test_as_ref_none() {
318        let opt: Opt<i16> = Opt::none(53);
319        assert_eq!(opt.as_ref(), Opt::none(&7));
320    }
321
322    // ===== `as_mut` tests =====
323
324    #[test]
325    fn test_as_mut_some() {
326        let mut opt: Opt<i16> = Opt::some(42);
327        assert_eq!(opt.as_mut(), Opt::some(&mut 42));
328    }
329
330    #[test]
331    fn test_as_mut_none() {
332        let mut opt: Opt<i16> = Opt::none(53);
333        assert_eq!(opt.as_mut(), Opt::none(&mut 7));
334    }
335
336    // ===== `expect` tests =====
337
338    #[test]
339    fn test_expect_some() {
340        assert_eq!(Opt::some(42).expect("error"), 42);
341    }
342
343    #[test]
344    #[should_panic(expected = "Douglas Adams")]
345    fn test_expect_none() {
346        Opt::none(29).expect("Douglas Adams");
347    }
348
349    // ===== `unwrap` tests =====
350
351    #[test]
352    fn test_unwrap_some() {
353        assert_eq!(Opt::some(42).unwrap(), 42);
354    }
355
356    #[test]
357    #[should_panic]
358    fn test_unwrap_none() {
359        Opt::none(31).unwrap();
360    }
361
362    // ===== `unwrap_or` tests =====
363
364    #[test]
365    fn test_unwrap_or_some() {
366        assert_eq!(Opt::some(42).unwrap_or(99), 42);
367    }
368
369    #[test]
370    fn test_unwrap_or_none() {
371        assert_eq!(Opt::none(-97).unwrap_or(99), 99);
372    }
373
374    // ===== `unwrap_or_else` tests =====
375
376    #[test]
377    fn test_unwrap_or_else_some() {
378        assert_eq!(Opt::some(42).unwrap_or_else(|| -1), 42);
379    }
380
381    #[test]
382    fn test_unwrap_or_else_none() {
383        assert_eq!(Opt::none(-37).unwrap_or_else(|| -1), -1);
384    }
385
386    // ===== `map` tests =====
387
388    #[test]
389    fn test_map_some_1() {
390        assert_eq!(Opt::some(42).map(|x| x + 1), Opt::some(43));
391    }
392
393    #[test]
394    fn test_map_some_2() {
395        let opt_1: Opt<String> = Opt::some(String::from("A"));
396        let opt_2 = opt_1.map(|mut s| {
397            s.push_str("B");
398            s
399        });
400        assert_eq!(opt_2, Opt::some(String::from("AB")));
401    }
402
403    #[test]
404    fn test_map_none_1() {
405        assert_eq!(Opt::none(431).map(|x| x + 1), Opt::none(0));
406    }
407
408    #[test]
409    fn test_map_none_2() {
410        let opt_1: Opt<String> = Opt::none(String::from("A"));
411        let opt_2 = opt_1.map(|mut s| {
412            s.push_str("B");
413            s
414        });
415        assert_eq!(opt_2, Opt::none(String::from("AB")));
416    }
417
418    // ===== `map_in_place` tests =====
419
420    #[test]
421    fn test_map_in_place_some() {
422        let mut opt = Opt::some(String::from("A"));
423        opt.map_in_place(|s| s.push_str("B"));
424        assert_eq!(opt, Opt::some(String::from("AB")));
425    }
426
427    #[test]
428    fn test_map_in_place_none() {
429        let mut opt = Opt::none(String::from("A"));
430        opt.map_in_place(|s| s.push_str("B"));
431        assert_eq!(opt, Opt::none(String::from("AB")));
432    }
433}