option_utils/
lib.rs

1//! A collection of utilities for working with Rust's Option type.
2//!
3//! ## Example
4//!
5//! ```
6//! use option_utils::OptionUtils;
7//!
8//! let mut x = Some("Hello world".to_owned());
9//! x.inner_mut(|s| s.push('!'));
10//! assert_eq!(x, Some("Hello world!".to_owned()));
11//!
12//! let path = Some("dir");
13//! let path: Option<std::path::PathBuf> = path.map_into();
14//! assert_eq!(path, Some(std::path::Path::new("dir").to_owned()));
15//!
16//! let num = Some(10_u64);
17//! let num: Option<u8> = num.try_map_into().unwrap();
18//! assert_eq!(num, Some(10_u8));
19//! ```
20//!
21//! ## License
22//!
23//! This project is licensed under the Apache-2.0 license.
24//!
25
26/// A collection of utilities for working with Rust's Option type.
27pub trait OptionUtils<T> {
28    /// Run a function on the inner value of an Option.
29    fn inner_mut<F>(&mut self, f: F)
30    where
31        F: FnOnce(&mut T);
32
33    /// Map an Option into another type.
34    fn map_into<R>(self) -> Option<R>
35    where
36        Self: Sized,
37        T: Into<R>;
38
39    /// Map an Option into another type, returning an error if the conversion fails.
40    fn try_map_into<R, E>(self) -> Result<Option<R>, E>
41    where
42        Self: Sized,
43        T: TryInto<R, Error = E>;
44}
45
46impl<T> OptionUtils<T> for Option<T> {
47    fn inner_mut<F>(&mut self, f: F)
48    where
49        F: FnOnce(&mut T),
50    {
51        if let Some(inner) = self.as_mut() {
52            f(inner);
53        }
54    }
55
56    fn try_map_into<R, E>(self) -> Result<Option<R>, E>
57    where
58        Self: Sized,
59        T: TryInto<R, Error = E>,
60    {
61        self.map(TryInto::try_into).transpose()
62    }
63
64    fn map_into<R>(self) -> Option<R>
65    where
66        Self: Sized,
67        T: Into<R>,
68    {
69        self.map(Into::into)
70    }
71}
72
73#[cfg(test)]
74mod test {
75    use std::path::{Path, PathBuf};
76
77    use super::*;
78    use anyhow::Result;
79
80    #[test]
81    fn test_inner_mut() -> Result<()> {
82        let mut x = Some("Hello world".to_owned());
83        x.inner_mut(|s| s.push('!'));
84        assert_eq!(x, Some("Hello world!".to_owned()));
85        Ok(())
86    }
87
88    #[test]
89    fn test_map_into() -> Result<()> {
90        let path = Some("hey");
91        let path: Option<PathBuf> = path.map_into();
92        assert_eq!(path, Some(Path::new("hey").to_owned()));
93        Ok(())
94    }
95
96    #[test]
97    fn test_map_try_into() -> Result<()> {
98        let num = Some(10_u64);
99        let num: Option<u8> = num.try_map_into()?;
100        assert_eq!(num, Some(10_u8));
101        Ok(())
102    }
103}