Gen7ScriptsRs/pkmn_lib_interface/src/handling/cached_value.rs

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()
}
)*
};
}