1use core::fmt;
2use std::marker::PhantomData;
3
4pub trait __VarCheck {
5 type Target;
6
7 fn target(&self) -> &Self::Target;
8
9 #[inline]
10 fn impls_copy(&self) -> bool {
11 false
12 }
13
14 #[inline]
15 fn try_debug_fmt(&self) -> Option<String> {
16 None
17 }
18
19 #[inline]
20 fn try_lazy<F, S>(&self, should_exec: bool, f: F) -> __InstantExecute
21 where
22 F: FnOnce(&Self) -> Option<S>,
23 S: ToString,
24 {
25 __InstantExecute(
26 should_exec
27 .then(|| f(self).map(|s| s.to_string()))
28 .flatten(),
29 )
30 }
31}
32
33impl<T> __VarCheck for __VarWrapper<T> {
34 type Target = T;
35
36 #[inline]
37 fn target(&self) -> &Self::Target {
38 &self.0
39 }
40}
41
42#[derive(Debug, Clone, Copy)]
43pub struct __VarWrapper<T>(pub T);
44impl<T> __VarWrapper<T> {
45 #[inline]
46 pub fn into_inner(self) -> T {
47 self.0
48 }
49}
50impl<T: fmt::Debug> __VarWrapper<T> {
51 #[inline]
52 pub fn try_debug_fmt(&self) -> Option<String> {
53 Some(format!("{:?}", self.0))
54 }
55}
56impl<T: Copy> __VarWrapper<T> {
57 #[inline]
63 pub fn impls_copy(&self) -> bool {
64 true
65 }
66
67 #[inline]
68 pub fn try_lazy<F, S>(&self, should_exec: bool, f: F) -> __LazyExecute<Self, F, S>
69 where
70 F: FnOnce(Self) -> Option<S>,
71 S: ToString,
72 {
73 __LazyExecute(*self, should_exec.then_some(f), PhantomData)
74 }
75}
76
77#[derive(Debug, Clone)]
78pub struct __InstantExecute(Option<String>);
79impl __InstantExecute {
80 #[inline]
81 pub fn exec(self) -> Option<String> {
82 self.0
83 }
84}
85
86#[derive(Debug, Clone)]
87pub struct __LazyExecute<T, F, S>(T, Option<F>, PhantomData<S>);
88impl<T, F, S> __LazyExecute<T, F, S>
89where
90 F: FnOnce(T) -> Option<S>,
91 S: ToString,
92{
93 #[inline]
94 pub fn exec(self) -> Option<String> {
95 let Self(arg, f, _) = self;
96 f.map(|f| f(arg).map(|s| s.to_string())).flatten()
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use std::sync::atomic::{AtomicBool, Ordering};
104
105 pub struct NoDebug(String);
106
107 #[test]
108 fn test_debug_and_ref() {
109 let x = "hello world".to_owned();
110 let fn_called = AtomicBool::from(false);
111
112 let w = __VarWrapper(&x);
114 let w_fn = w.try_lazy(true, |val| {
115 fn_called.store(true, Ordering::Relaxed);
116
117 val.try_debug_fmt()
118 });
119
120 assert!(!fn_called.load(Ordering::Relaxed));
122 let w_val = w_fn.exec();
123 assert!(w_val.is_some());
125 assert!(fn_called.load(Ordering::Relaxed));
127
128 fn_called.store(false, Ordering::Relaxed);
130
131 let z = __VarWrapper(x);
133 let z_fn = z.try_lazy(true, |val| {
134 fn_called.store(true, Ordering::Relaxed);
135
136 val.try_debug_fmt()
137 });
138 assert!(fn_called.load(Ordering::Relaxed));
140 let z_val = z_fn.exec();
141 assert!(z_val.is_some());
143
144 let z = z.into_inner();
146
147 let y = __VarWrapper(NoDebug(z));
149 let y_fn = y.try_lazy(true, |val| val.try_debug_fmt());
150
151 assert!(y_fn.exec().is_none());
153 }
154
155 #[test]
156 fn test_generic_fn() {
157 fn generic_debug<T: fmt::Debug>(t: T) {
158 let bin = __VarWrapper(t);
159 let val = bin.try_lazy(true, |v| v.try_debug_fmt()).exec();
160
161 assert!(val.is_some());
162 }
163
164 fn generic_no_debug<T>(t: T) {
165 let bin = __VarWrapper(t);
166 let val = bin.try_lazy(true, |v| v.try_debug_fmt()).exec();
167
168 assert!(val.is_none());
169 }
170
171 generic_debug(5u64);
172 generic_debug(&5u64);
173 generic_no_debug(5u64);
174 generic_no_debug(&5u64);
175 }
176}