use once_cell::unsync::OnceCell; use std::cell::Cell; use std::fmt::Debug; use std::ops::Deref; pub trait Eval { fn eval(self) -> Tgt; } /// A value which is initialized from a `Src` on the first access. pub struct Lazy { /// Exactly one of `src` of `tgt` must be set at a given time. /// Once `src` is unset and `tgt` is set, we never go back. src: Cell>, tgt: OnceCell, } impl Lazy where Src: Eval, { /// Creates a new lazy value with the given initializing value. pub fn new(src: Src) -> Self { Lazy { src: Cell::new(Some(src)), tgt: OnceCell::new(), } } /// Creates a new lazy value with the given already-initialized value. pub fn new_completed(tgt: Tgt) -> Self { let lazy = Lazy { src: Cell::new(None), tgt: OnceCell::new(), }; let _ = lazy.tgt.set(tgt); lazy } pub fn force(&self) -> &Tgt { self.tgt.get_or_init(|| { let src = self.src.take().unwrap(); src.eval() }) } pub fn get_mut(&mut self) -> &mut Tgt { self.force(); self.tgt.get_mut().unwrap() } pub fn into_inner(self) -> Tgt { self.force(); self.tgt.into_inner().unwrap() } } impl Deref for Lazy where Src: Eval, { type Target = Tgt; fn deref(&self) -> &Self::Target { self.force() } } /// This implementation evaluates before cloning, because we can't clone the contents of a `Cell`. impl Clone for Lazy where Src: Eval, Tgt: Clone, { fn clone(&self) -> Self { Self::new_completed(self.force().clone()) } } impl Debug for Lazy where Tgt: Debug, { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(tgt) = self.tgt.get() { fmt.debug_tuple("Lazy@Init").field(tgt).finish() } else { fmt.debug_tuple("Lazy@Uninit").finish() } } }