oofs/
var_check.rs

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]
58    // pub fn target(self) -> T {
59    //     self.0
60    // }
61
62    #[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        // we load a reference to the bin.
113        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        // before `exec()`, fn should not be called for ref value.
121        assert!(!fn_called.load(Ordering::Relaxed));
122        let w_val = w_fn.exec();
123        // Since `&String` implements `fmt::Debug`, it should output `Some(...)`.
124        assert!(w_val.is_some());
125        // after `exec()`, fn should have been executed.
126        assert!(fn_called.load(Ordering::Relaxed));
127
128        // reset `fn_called` to `false`.
129        fn_called.store(false, Ordering::Relaxed);
130
131        // we load an owned value to the bin.
132        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        // since fn is instantly called, `fn_called` should be set to `true`.
139        assert!(fn_called.load(Ordering::Relaxed));
140        let z_val = z_fn.exec();
141        // Since `String` implements `fmt::Debug`, it should output `Some(...)`.
142        assert!(z_val.is_some());
143
144        // unload should unwrap the `__VarWrapper` wrapper.
145        let z = z.into_inner();
146
147        // Load the struct that does not implement `fmt::Debug`.
148        let y = __VarWrapper(NoDebug(z));
149        let y_fn = y.try_lazy(true, |val| val.try_debug_fmt());
150
151        // since the value does not implement `fmt::Debug`, it should return `None`.
152        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}