1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#![forbid(unsafe_code)]
//! A crate exposing the `Tap` trait, which makes method chaining easier.
//!
//! Check out [`Tap`] for a more detailed documentation.
//!
//! # Examples
//!
//! ```
//! use tapir::Tap;
//!
//! fn smallest_factor(x: u32) -> u32 {
//!     for i in 2..x {
//!         if x % i == 0 {
//!             return i;
//!         }
//!     }
//!
//!     x
//! }
//!
//! let smallest_factors: Vec<u32> = (2..25).map(smallest_factor).collect();
//!
//! let unique_primes = smallest_factors.tap(|v| v.sort()).tap(Vec::dedup);
//! assert_eq!(unique_primes, [2, 3, 5, 7, 11, 13, 17, 19, 23]);
//! ```
//!
//! [`Tap`]: ./trait.Tap.html

/// An interface to enable the `tap` operation which is implemented for all `Sized` types.
///
/// The tap operation takes full ownership of a variable, calls the given function with a mutable
/// reference to the given variable and then returns full ownership of it.
/// This allows for easy mutation without having to declare the variable as mutable.
///
/// Tapping can be used to reduce the amount of local mutable variables,
/// which can make the code easier to read and may prevent accidental mutation.
///
/// # Examples
///
/// ```rust
/// fn get_unsorted_values() -> Vec<u32> {
///     vec![42, 7, 1337, 69]
/// }
///
/// fn use_sorted_values(values: &[u32]) {
///     assert_eq!(&[7, 42, 69, 1337], values);
/// }
///
/// // without tap one often needs mutable variables.
/// let mut old = get_unsorted_values();
/// old.sort();
/// use_sorted_values(&old);
///
/// // using tap, this can be simplified.
/// use tapir::Tap;
///
/// let tapped = get_unsorted_values().tap(|v| v.sort());
/// use_sorted_values(&tapped);
/// ```

pub trait Tap {
    /// Executes a closure on an object, returning it afterwards.
    ///
    /// # Examples
    ///
    /// ```
    /// use tapir::Tap;
    ///
    /// let mut max = 0;
    /// let data: [u32; 5] = [2, 8, 3, 4, 0];
    /// assert_eq!(
    ///     data.tap(|x| x.sort()).tap(|x| max += x.last().unwrap()),
    ///     [0, 2, 3, 4, 8]
    /// );
    /// assert_eq!(max, 8);
    /// ```
    fn tap<F: FnOnce(&mut Self)>(self, f: F) -> Self;
}

impl<T> Tap for T {
    #[inline]
    fn tap<F: FnOnce(&mut Self)>(mut self, f: F) -> Self {
        f(&mut self);
        self
    }
}