98 lines
1.9 KiB
Rust
Executable File
98 lines
1.9 KiB
Rust
Executable File
use alloc::boxed::Box;
|
|
|
|
#[cfg(not(feature = "mock_data"))]
|
|
pub struct CachedValue<T> {
|
|
init_fn: Box<dyn Fn() -> T>,
|
|
value: Option<T>,
|
|
}
|
|
|
|
#[cfg(not(feature = "mock_data"))]
|
|
impl<T> CachedValue<T> {
|
|
pub fn new(init_fn: Box<dyn Fn() -> T>) -> Self {
|
|
Self {
|
|
init_fn,
|
|
value: None,
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn init_if_empty(&self) {
|
|
if self.value.is_none() {
|
|
unsafe {
|
|
let s = self as *const Self as *mut Self;
|
|
s.as_mut().unwrap().value.replace((self.init_fn)());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub fn value(&self) -> T
|
|
where
|
|
T: Clone,
|
|
{
|
|
self.init_if_empty();
|
|
self.value.as_ref().unwrap().clone()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn value_ref(&self) -> &T {
|
|
self.init_if_empty();
|
|
self.value.as_ref().unwrap()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "mock_data")]
|
|
pub struct CachedValue<T: Clone> {
|
|
value: T,
|
|
}
|
|
#[cfg(feature = "mock_data")]
|
|
impl<T: Clone> CachedValue<T> {
|
|
pub fn new(value: T) -> Self {
|
|
Self { value }
|
|
}
|
|
|
|
#[inline]
|
|
pub fn value(&self) -> T
|
|
where
|
|
T: Clone,
|
|
{
|
|
self.value.clone()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn value_ref(&self) -> &T {
|
|
&self.value
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "mock_data")]
|
|
impl<T: Clone> From<T> for CachedValue<T> {
|
|
fn from(value: T) -> Self {
|
|
Self::new(value)
|
|
}
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! cached_value {
|
|
($init: block) => {
|
|
CachedValue::new(alloc::boxed::Box::new(move || unsafe { $init }))
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! cached_value_getters {
|
|
(
|
|
$(
|
|
$(#[$attr:meta])*
|
|
$v:vis fn $name:ident(&self) -> $type:ty;
|
|
)*
|
|
) => {
|
|
$(
|
|
$(#[$attr])*
|
|
$v fn $name(&self) -> $type {
|
|
self.inner.$name.value()
|
|
}
|
|
)*
|
|
};
|
|
}
|