use core::fmt;
use std::marker::PhantomData;
pub trait __VarCheck {
type Target;
fn target(&self) -> &Self::Target;
#[inline]
fn impls_copy(&self) -> bool {
false
}
#[inline]
fn try_debug_fmt(&self) -> Option<String> {
None
}
#[inline]
fn try_lazy<F, S>(&self, should_exec: bool, f: F) -> __InstantExecute
where
F: FnOnce(&Self) -> Option<S>,
S: ToString,
{
__InstantExecute(
should_exec
.then(|| f(self).map(|s| s.to_string()))
.flatten(),
)
}
}
impl<T> __VarCheck for __VarWrapper<T> {
type Target = T;
#[inline]
fn target(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Clone, Copy)]
pub struct __VarWrapper<T>(pub T);
impl<T> __VarWrapper<T> {
#[inline]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T: fmt::Debug> __VarWrapper<T> {
#[inline]
pub fn try_debug_fmt(&self) -> Option<String> {
Some(format!("{:?}", self.0))
}
}
impl<T: Copy> __VarWrapper<T> {
#[inline]
pub fn impls_copy(&self) -> bool {
true
}
#[inline]
pub fn try_lazy<F, S>(&self, should_exec: bool, f: F) -> __LazyExecute<Self, F, S>
where
F: FnOnce(Self) -> Option<S>,
S: ToString,
{
__LazyExecute(*self, should_exec.then_some(f), PhantomData)
}
}
#[derive(Debug, Clone)]
pub struct __InstantExecute(Option<String>);
impl __InstantExecute {
#[inline]
pub fn exec(self) -> Option<String> {
self.0
}
}
#[derive(Debug, Clone)]
pub struct __LazyExecute<T, F, S>(T, Option<F>, PhantomData<S>);
impl<T, F, S> __LazyExecute<T, F, S>
where
F: FnOnce(T) -> Option<S>,
S: ToString,
{
#[inline]
pub fn exec(self) -> Option<String> {
let Self(arg, f, _) = self;
f.map(|f| f(arg).map(|s| s.to_string())).flatten()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicBool, Ordering};
pub struct NoDebug(String);
#[test]
fn test_debug_and_ref() {
let x = "hello world".to_owned();
let fn_called = AtomicBool::from(false);
let w = __VarWrapper(&x);
let w_fn = w.try_lazy(true, |val| {
fn_called.store(true, Ordering::Relaxed);
val.try_debug_fmt()
});
assert!(!fn_called.load(Ordering::Relaxed));
let w_val = w_fn.exec();
assert!(w_val.is_some());
assert!(fn_called.load(Ordering::Relaxed));
fn_called.store(false, Ordering::Relaxed);
let z = __VarWrapper(x);
let z_fn = z.try_lazy(true, |val| {
fn_called.store(true, Ordering::Relaxed);
val.try_debug_fmt()
});
assert!(fn_called.load(Ordering::Relaxed));
let z_val = z_fn.exec();
assert!(z_val.is_some());
let z = z.into_inner();
let y = __VarWrapper(NoDebug(z));
let y_fn = y.try_lazy(true, |val| val.try_debug_fmt());
assert!(y_fn.exec().is_none());
}
#[test]
fn test_generic_fn() {
fn generic_debug<T: fmt::Debug>(t: T) {
let bin = __VarWrapper(t);
let val = bin.try_lazy(true, |v| v.try_debug_fmt()).exec();
assert!(val.is_some());
}
fn generic_no_debug<T>(t: T) {
let bin = __VarWrapper(t);
let val = bin.try_lazy(true, |v| v.try_debug_fmt()).exec();
assert!(val.is_none());
}
generic_debug(5u64);
generic_debug(&5u64);
generic_no_debug(5u64);
generic_no_debug(&5u64);
}
}