From 9725bbc5a41e00a2b952cdfe4a04d472765c9e41 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sun, 7 Jun 2026 19:42:02 +0800 Subject: Add LazyRes for lazy resource initialization --- mingling_core/src/asset/lazy_resource.rs | 141 +++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 mingling_core/src/asset/lazy_resource.rs (limited to 'mingling_core/src/asset') diff --git a/mingling_core/src/asset/lazy_resource.rs b/mingling_core/src/asset/lazy_resource.rs new file mode 100644 index 0000000..41f8a34 --- /dev/null +++ b/mingling_core/src/asset/lazy_resource.rs @@ -0,0 +1,141 @@ +use crate::{ProgramCollect, ResourceMarker, this}; + +/// A lazily initialized resource that only creates its value on first access via a given initializer function. +/// +/// `LazyRes` wraps an `Option` and an initializer function, supporting thread-safe lazy loading. +/// Initialization is triggered by calls to `get_ref()`, `get_mut()`, or `get_clone()`. +pub struct LazyRes { + /// The initializer function, called on first access to produce the inner value. + init_fn: Box T + Send + Sync>, + /// Stores the initialized value; `None` means not yet initialized. + inner: Option, +} + +impl Default for LazyRes { + /// Creates an uninitialized `LazyRes` whose initializer returns `T::default()`. + fn default() -> Self { + Self { + inner: None, + init_fn: Box::new(|| T::default()), + } + } +} + +impl LazyRes { + /// Creates a new lazily initialized resource with a custom initializer function. + /// + /// # Parameters + /// - `f`: The initializer function called on first access, returning a value of type `T`. + /// + /// # Returns + /// Returns an uninitialized `LazyRes`. + #[must_use] + pub fn new(f: impl FnMut() -> T + Send + Sync + 'static) -> Self { + Self { + inner: None, + init_fn: Box::new(f), + } + } + + /// Returns an immutable reference to the inner value, calling the initializer if necessary. + /// + /// # Returns + /// An immutable reference to the inner value `T`. + pub fn get_ref(&mut self) -> &T { + if self.inner.is_none() { + self.inner = Some((self.init_fn)()); + } + self.inner.as_ref().unwrap() + } + + /// Returns a mutable reference to the inner value, calling the initializer if necessary. + /// + /// # Returns + /// A mutable reference to the inner value `T`. + pub fn get_mut(&mut self) -> &mut T { + if self.inner.is_none() { + self.inner = Some((self.init_fn)()); + } + self.inner.as_mut().unwrap() + } + + /// Resets the lazy resource by taking and returning the inner value; on next access, re-initialization occurs. + /// + /// # Returns + /// Returns the previously initialized value if any, otherwise `None`. + pub fn reset(&mut self) -> Option { + self.inner.take() + } + + /// Returns a clone of the inner value, calling the initializer if necessary. + /// + /// # Returns + /// A clone of type `T`. + pub fn get_clone(&mut self) -> T { + self.get_ref().clone() + } +} + +impl From for LazyRes { + /// Creates a `LazyRes` from an existing value (already initialized), with the initializer set to `T::default()`. + fn from(value: T) -> Self { + Self { + inner: Some(value), + init_fn: Box::new(|| T::default()), + } + } +} + +impl LazyRes { + /// Creates a lazily initialized resource using `T::default()` as the initializer. + pub fn lazy_default() -> Self { + Self::default() + } + + /// Creates a lazily initialized resource with a custom initializer function. + /// + /// Same as `LazyRes::new`. + pub fn lazy_init(f: impl FnMut() -> T + Send + Sync + 'static) -> Self { + Self::new(f) + } +} + +/// Provides convenience methods for types implementing `Default + Send + Sync + Clone + 'static`, +/// allowing them to easily create a corresponding `LazyRes`. +pub trait LazyInit: Default + Send + Sync + Clone + 'static { + /// Creates a lazily initialized resource for this type using `Default` as the initializer. + fn lazy_default() -> LazyRes { + LazyRes::default() + } + + /// Creates a lazily initialized resource for this type with a custom initializer function. + fn lazy_init(f: impl FnMut() -> Self + Send + Sync + 'static) -> LazyRes { + LazyRes::new(f) + } +} + +impl LazyInit for T {} + +impl ResourceMarker for LazyRes { + /// Clones the lazy resource. The cloned resource retains any initialized value, but the initializer is reset to `T::default()`. + fn res_clone(&self) -> Self { + Self { + inner: self.inner.clone(), + // The original initializer is not preserved on clone + init_fn: Box::new(|| T::default()), + } + } + + /// Returns a default lazy resource (uninitialized, using `T::default()` as the initializer). + fn res_default() -> Self { + Self::default() + } + + /// Modifies the current lazy resource via the `this` context provided by `C`. + fn modify(f: impl FnOnce(&mut Self)) + where + C: ProgramCollect + 'static, + { + this::().modify_res(f); + } +} -- cgit