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 let None = self.as_ref() { 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);
}
}