take_if/
lib.rs

1//! Conditionally take a value out of an option.
2//!
3//! This crate adds a `take_if` extension method to [`Option`] which conditionally
4//! takes the value out of an option, leaving `None` in its place if the value was
5//! taken. The predicate function is only called if the option is `Some`, and
6//! receives a reference to the option's contents.
7//!
8//! If you don't need to take the value conditionally, i.e. you always need to take
9//! the value, use [`Option::take`] instead.
10//!
11//! # Examples
12//!
13//! ```
14//! use take_if::TakeIf;
15//!
16//! let mut maybe_greeting = Some("Hello, World!");
17//!
18//! if let Some(greeting) = maybe_greeting.take_if(|greeting| greeting.starts_with("Hello")) {
19//!     println!(r#"Greeting {:?} starts with "Hello""#, greeting);
20//! } else {
21//!     println!(r#"There was no greeting, or it didn't start with "Hello""#);
22//! }
23//! ```
24//!
25//! [`Option`]: https://doc.rust-lang.org/std/option/enum.Option.html
26//! [`Option::take`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.take
27
28/// Extension trait for `Option<T>` that adds the `take_if` method.
29///
30/// See the [crate-level documentation](./index.html) for more information.
31pub trait TakeIf {
32    /// The type contained in the `Option`.
33    type Inner;
34
35    /// Takes value out of the `Option` if `predicate` returns `true`.
36    ///
37    /// See the [crate-level documentation](./index.html) for more information.
38    fn take_if<F: FnOnce(&Self::Inner) -> bool>(&mut self, predicate: F) -> Option<Self::Inner>;
39}
40
41impl<T> TakeIf for Option<T> {
42    type Inner = T;
43
44    fn take_if<F: FnOnce(&Self::Inner) -> bool>(&mut self, predicate: F) -> Option<Self::Inner> {
45        if self.as_ref().map(predicate).unwrap_or(false) {
46            self.take()
47        } else {
48            None
49        }
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use crate::TakeIf;
56
57    #[test]
58    fn conditional_take() {
59        let mut option = Some(5);
60        assert_eq!(None, option.take_if(|_| false));
61        assert_eq!(Some(5), option.take_if(|_| true));
62        assert_eq!(None, option.take_if(|_| true));
63    }
64}