pub trait Tap: Sized {
fn tap<F, R>(self, func: F) -> Self
where
F: FnOnce(&Self) -> R,
R: Sized,
{ ... }
fn tap_dbg<F, R>(self, func: F) -> Self
where
F: FnOnce(&Self) -> R,
R: Sized,
{ ... }
fn tap_mut<F, R>(self, func: F) -> Self
where
F: FnOnce(&mut Self) -> R,
R: Sized,
{ ... }
fn tap_mut_dbg<F, R>(self, func: F) -> Self
where
F: FnOnce(&mut Self) -> R,
R: Sized,
{ ... }
}
Expand description
Value Tap
This trait allows any function that takes a borrowed value to be run on a value directly, without downgrading the binding.
Examples
Sorting a vector is a quintessential example of operations that break the flow
of handling a value. It cannot be done in the middle of an operation, because it
has the signature &mut self -> ()
.
use wyz::tap::Tap;
let v = vec![5, 1, 4, 2, 3]
.tap_mut(|v| v.sort())
.tap_mut(|v| v.reverse())
.tap_mut(|v| v.iter_mut().for_each(|elt| *elt *= 2));
assert_eq!(&v, &[10, 8, 6, 4, 2]);
Note that because sort
and reverse
are actually methods on [T: Ord]
, not
on Vec<T: Ord>
, they cannot be listed by name in the tap_mut
call. Their
signature is &mut [T: Ord] -> ()
, but tap_mut
provides a &mut Vec<T: Ord>
,
and deref-coercion does not apply to named functions. The TapDeref
trait
allows this to work.
Provided methods
Provides immutable access for inspection.
This is most useful for inserting passive inspection points into an expression, such as for logging or counting.
Examples
This demonstrates the use of tap
to inspect a value and log it as it
is transformed.
use wyz::tap::Tap;
fn make_value() -> i32 { 5 }
fn alter_value(n: i32) -> i32 { n * 3 }
let mut init_flag = false;
let mut fini_flag = false;
let finished = make_value()
.tap(|n| init_flag = *n == 5)
.tap_mut(|n| *n = alter_value(*n))
.tap(|n| fini_flag = *n == 15);
assert!(init_flag);
assert!(fini_flag);
assert_eq!(finished, 15);
This example is somewhat contrived, since tap
is most useful for
logging values with eprintln!
or the log
crate and those are hard to
nicely demonstrate in tests.
Calls tap
in debug builds, and does nothing in release builds.
Provides mutable access for modification.
This is most useful for transforming mutator methods of the kind
&mut self -> ()
and making them fit in value chains of self -> Self
.
Examples
Append to a string without a let mut
statement.
use wyz::tap::Tap;
let full: String = "Hello".to_owned()
.tap_mut(|s| s.push_str(", reader!"));
assert_eq!(full, "Hello, reader!");
fn tap_mut_dbg<F, R>(self, func: F) -> Self where
F: FnOnce(&mut Self) -> R,
R: Sized,
fn tap_mut_dbg<F, R>(self, func: F) -> Self where
F: FnOnce(&mut Self) -> R,
R: Sized,
Calls tap_mut
in debug builds, and does nothing in release builds.