use std::cell::RefCell;
use std::rc::Rc;
pub struct Lazy<T: Clone> {
factory: Rc<dyn Fn() -> T>,
cached: RefCell<Option<T>>,
}
impl<T: Clone> Lazy<T> {
pub fn new(factory: impl Fn() -> T + 'static) -> Self {
Lazy {
factory: Rc::new(factory),
cached: RefCell::new(None),
}
}
pub fn get(&self) -> T {
if self.cached.borrow().is_none() {
let value = (self.factory)();
*self.cached.borrow_mut() = Some(value);
}
self.cached.borrow().as_ref().unwrap().clone()
}
}
pub fn lazy_schema<T, F>(factory: F) -> impl Fn() -> T + 'static
where
T: Clone + 'static,
F: Fn() -> T + 'static,
{
let lazy = Rc::new(RefCell::new(None));
let factory = Rc::new(factory);
move || {
if lazy.borrow().is_none() {
let value = factory();
*lazy.borrow_mut() = Some(value);
}
lazy.borrow().as_ref().unwrap().clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lazy_schema() {
let mut call_count = 0;
let factory = lazy_schema(|| {
call_count += 1;
"computed"
});
assert_eq!(factory(), "computed");
assert_eq!(factory(), "computed");
assert_eq!(call_count, 1);
}
}