use core::{
borrow::{
Borrow,
BorrowMut,
},
ops::{
Deref,
DerefMut,
},
};
pub trait Tap: Sized {
fn tap<F, R>(self, func: F) -> Self
where
F: FnOnce(&Self) -> R,
R: Sized,
{
func(&self);
self
}
#[allow(unused_variables)]
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
fn tap_dbg<F, R>(self, func: F) -> Self
where
F: FnOnce(&Self) -> R,
R: Sized,
{
#[cfg(debug_assertions)]
return self.tap(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_mut<F, R>(mut self, func: F) -> Self
where
F: FnOnce(&mut Self) -> R,
R: Sized,
{
func(&mut self);
self
}
#[allow(unused_mut, unused_variables)]
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
fn tap_mut_dbg<F, R>(self, func: F) -> Self
where
F: FnOnce(&mut Self) -> R,
R: Sized,
{
#[cfg(debug_assertions)]
return self.tap_mut(func);
#[cfg(not(debug_assertions))]
return self;
}
}
impl<T: Sized> Tap for T {
}
pub trait TapBorrow<T: ?Sized>: Sized {
fn tap_borrow<F, R>(self, func: F) -> Self
where
Self: Borrow<T>,
F: FnOnce(&T) -> R,
R: Sized,
{
func(Borrow::<T>::borrow(&self));
self
}
#[allow(unused_variables)]
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
fn tap_borrow_dbg<F, R>(self, func: F) -> Self
where
Self: Borrow<T>,
F: FnOnce(&T) -> R,
R: Sized,
{
#[cfg(debug_assertions)]
return self.tap_borrow(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_borrow_mut<F, R>(mut self, func: F) -> Self
where
Self: BorrowMut<T>,
F: FnOnce(&mut T) -> R,
R: Sized,
{
func(BorrowMut::<T>::borrow_mut(&mut self));
self
}
#[allow(unused_mut, unused_variables)]
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
fn tap_borrow_mut_dbg<F, R>(self, func: F) -> Self
where
Self: BorrowMut<T>,
F: FnOnce(&mut T) -> R,
R: Sized,
{
#[cfg(debug_assertions)]
return self.tap_borrow_mut(func);
#[cfg(not(debug_assertions))]
return self;
}
}
impl<T: Sized, U: ?Sized> TapBorrow<U> for T {
}
pub trait TapAsRef<T: ?Sized>: Sized {
fn tap_ref<F, R>(self, func: F) -> Self
where
Self: AsRef<T>,
F: FnOnce(&T) -> R,
{
func(AsRef::<T>::as_ref(&self));
self
}
#[allow(unused_variables)]
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
fn tap_ref_dbg<F, R>(self, func: F) -> Self
where
Self: AsRef<T>,
F: FnOnce(&T) -> R,
{
#[cfg(debug_assertions)]
return self.tap_ref(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_ref_mut<F, R>(mut self, func: F) -> Self
where
Self: AsMut<T>,
F: FnOnce(&mut T) -> R,
{
func(AsMut::<T>::as_mut(&mut self));
self
}
#[allow(unused_mut, unused_variables)]
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
fn tap_ref_mut_dbg<F, R>(mut self, func: F) -> Self
where
Self: AsMut<T>,
F: FnOnce(&mut T) -> R,
{
#[cfg(debug_assertions)]
return self.tap_ref_mut(func);
#[cfg(not(debug_assertions))]
return self;
}
}
impl<T: Sized, U: ?Sized> TapAsRef<U> for T {
}
pub trait TapDeref: Sized {
fn tap_deref<F, R>(self, func: F) -> Self
where
Self: Deref,
F: FnOnce(&<Self as Deref>::Target) -> R,
{
func(Deref::deref(&self));
self
}
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
fn tap_deref_dbg<F, R>(self, func: F) -> Self
where
Self: Deref,
F: FnOnce(&<Self as Deref>::Target) -> R,
{
#[cfg(debug_assertions)]
return self.tap_deref(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_deref_mut<F, R>(mut self, func: F) -> Self
where
Self: DerefMut,
F: FnOnce(&mut <Self as Deref>::Target) -> R,
{
func(DerefMut::deref_mut(&mut self));
self
}
#[cfg_attr(not(debug_assertions), allow(unused_variables))]
fn tap_deref_mut_dbg<F, R>(self, func: F) -> Self
where
Self: DerefMut,
F: FnOnce(&mut <Self as Deref>::Target) -> R,
{
#[cfg(debug_assertions)]
return self.tap_deref_mut(func);
#[cfg(not(debug_assertions))]
return self;
}
}
impl<T: Sized> TapDeref for T {
}
pub trait TapOption<T: Sized>: Sized {
fn tap_some<F: FnOnce(&T) -> R, R>(self, func: F) -> Self;
#[allow(unused_variables)]
fn tap_some_dbg<F: FnOnce(&T) -> R, R>(self, func: F) -> Self {
#[cfg(debug_assertions)]
return self.tap_some(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_some_mut<F: FnOnce(&mut T) -> R, R>(self, func: F) -> Self;
#[allow(unused_variables)]
fn tap_some_mut_dbg<F: FnOnce(&mut T) -> R, R>(self, func: F) -> Self {
#[cfg(debug_assertions)]
return self.tap_some_mut(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_none<F: FnOnce() -> R, R>(self, func: F) -> Self;
#[allow(unused_variables)]
fn tap_none_dbg<F: FnOnce() -> R, R>(self, func: F) -> Self {
#[cfg(debug_assertions)]
return self.tap_none(func);
#[cfg(not(debug_assertions))]
return self;
}
}
impl<T> TapOption<T> for Option<T> {
fn tap_some<F: FnOnce(&T) -> R, R>(self, func: F) -> Self {
if let Some(val) = self.as_ref() {
func(val);
}
self
}
fn tap_some_mut<F: FnOnce(&mut T) -> R, R>(mut self, func: F) -> Self {
if let Some(val) = self.as_mut() {
func(val);
}
self
}
fn tap_none<F: FnOnce() -> R, R>(self, func: F) -> Self {
if self.is_none() {
func();
}
self
}
}
pub trait TapResult<T: Sized, E: Sized>: Sized {
fn tap_ok<F: FnOnce(&T) -> R, R>(self, func: F) -> Self;
#[allow(unused_variables)]
fn tap_ok_dbg<F: FnOnce(&T) -> R, R>(self, func: F) -> Self {
#[cfg(debug_assertions)]
return self.tap_ok(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_ok_mut<F: FnOnce(&mut T) -> R, R>(self, func: F) -> Self;
#[allow(unused_variables)]
fn tap_ok_mut_dbg<F: FnOnce(&mut T) -> R, R>(self, func: F) -> Self {
#[cfg(debug_assertions)]
return self.tap_ok_mut(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_err<F: FnOnce(&E) -> R, R>(self, func: F) -> Self;
#[allow(unused_variables)]
fn tap_err_dbg<F: FnOnce(&E) -> R, R>(self, func: F) -> Self {
#[cfg(debug_assertions)]
return self.tap_err(func);
#[cfg(not(debug_assertions))]
return self;
}
fn tap_err_mut<F: FnOnce(&mut E) -> R, R>(self, func: F) -> Self;
#[allow(unused_variables)]
fn tap_err_mut_dbg<F: FnOnce(&mut E) -> R, R>(self, func: F) -> Self {
#[cfg(debug_assertions)]
return self.tap_err_mut(func);
#[cfg(not(debug_assertions))]
return self;
}
}
impl<T, E> TapResult<T, E> for Result<T, E> {
fn tap_ok<F: FnOnce(&T) -> R, R>(self, func: F) -> Self {
if let Ok(val) = self.as_ref() {
func(val);
}
self
}
fn tap_ok_mut<F: FnOnce(&mut T) -> R, R>(mut self, func: F) -> Self {
if let Ok(val) = self.as_mut() {
func(val);
}
self
}
fn tap_err<F: FnOnce(&E) -> R, R>(self, func: F) -> Self {
if let Err(err) = self.as_ref() {
func(err);
}
self
}
fn tap_err_mut<F: FnOnce(&mut E) -> R, R>(mut self, func: F) -> Self {
if let Err(err) = self.as_mut() {
func(err);
}
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tap() {
let mut trap = 0;
assert_eq!(5.tap(|n| trap += *n), 5);
assert_eq!(5.tap_mut(|n| *n += trap), 10);
}
#[cfg(feature = "alloc")]
#[test]
fn tap_borrow() {
use alloc::rc::Rc;
let mut len = 0;
let _ = Rc::<str>::from("hello").tap_borrow(|s: &str| len = s.len());
assert_eq!(len, 5);
let v = alloc::vec![5i32, 1, 2, 4, 3]
.tap_borrow_mut(<[i32]>::sort)
.tap_borrow_mut(<[i32]>::reverse);
assert_eq!(v, &[5, 4, 3, 2, 1])
}
#[test]
fn tap_as_ref() {
struct Example {
a: [u8; 8],
b: [u16; 4],
}
impl AsRef<[u8]> for Example {
fn as_ref(&self) -> &[u8] {
&self.a
}
}
impl AsRef<[u16]> for Example {
fn as_ref(&self) -> &[u16] {
&self.b
}
}
impl AsMut<[u8]> for Example {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.a
}
}
impl AsMut<[u16]> for Example {
fn as_mut(&mut self) -> &mut [u16] {
&mut self.b
}
}
let mut sum_a = 0;
let mut sum_b = 0;
let e = Example {
a: [0, 1, 2, 3, 4, 5, 6, 7],
b: [8, 9, 10, 11],
}
.tap_ref(|a: &[u8]| sum_a = a.iter().sum())
.tap_ref(|b: &[u16]| sum_b = b.iter().sum())
.tap_ref_mut(|a: &mut [u8]| a.iter_mut().for_each(|e| *e *= 2))
.tap_ref_mut(|b: &mut [u16]| b.iter_mut().for_each(|e| *e *= 2));
assert_eq!(sum_a, 28);
assert_eq!(sum_b, 38);
assert_eq!(e.a, [0, 2, 4, 6, 8, 10, 12, 14]);
assert_eq!(e.b, [16, 18, 20, 22]);
}
#[cfg(feature = "alloc")]
#[test]
fn tap_deref() {
let mut len = 0;
let v = alloc::vec![5, 1, 4, 2, 3]
.tap_deref(|s| len = s.len())
.tap_deref_mut(<[i32]>::sort);
assert_eq!(len, 5);
assert_eq!(v, [1, 2, 3, 4, 5]);
}
#[test]
fn tap_option() {
let mut trap = 0;
None.tap_some(|x: &i32| trap += *x);
assert_eq!(trap, 0);
Some(5).tap_some(|x| trap += *x);
assert_eq!(trap, 5);
assert_eq!(Some(5).tap_some_mut(|x| *x += 5).unwrap(), 10);
assert!(Some(5).tap_mut(Option::take).is_none());
}
#[test]
fn tap_result() {
let mut trap = 0;
assert_eq!(Err(5).tap_ok(|x: &i32| trap += *x).unwrap_err(), 5);
assert_eq!(trap, 0);
assert_eq!(Err(5).tap_ok_mut(|x: &mut i32| *x += 5).unwrap_err(), 5);
assert_eq!(Ok::<_, i32>(5).tap_ok(|x: &i32| trap += *x).unwrap(), 5);
assert_eq!(trap, 5);
assert_eq!(Ok::<_, i32>(5).tap_ok_mut(|x| *x += 5).unwrap(), 10);
}
}