From 2c32196bbc632411d4f6998a506ca262a805a666 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 27 Apr 2026 21:19:56 +0800 Subject: Add global resource system to Program --- mingling_core/src/asset/global_resource.rs | 116 +++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 mingling_core/src/asset/global_resource.rs (limited to 'mingling_core/src/asset/global_resource.rs') diff --git a/mingling_core/src/asset/global_resource.rs b/mingling_core/src/asset/global_resource.rs new file mode 100644 index 0000000..5667576 --- /dev/null +++ b/mingling_core/src/asset/global_resource.rs @@ -0,0 +1,116 @@ +use std::{ + any::{Any, TypeId}, + collections::HashMap, + sync::{Arc, Mutex}, +}; + +use crate::{ChainProcess, Program, ProgramCollect}; + +pub type GlobalResources = Arc>>>; + +impl Program +where + C: ProgramCollect, +{ + /// Insert a resource of the given type, cloning the provided value into the store + pub fn with_resource(&mut self, res: Res) { + if let Ok(mut guard) = self.resources.lock() { + guard.insert(TypeId::of::(), Box::new(Arc::new(res))); + } + } + + /// Modify a resource by type, applying a closure to the resource if present + pub fn modify_res(&self, f: impl FnOnce(&mut Res)) + where + Res: 'static + Default + ResourceMarker + Send + Sync, + { + let mut guard = match self.resources.lock() { + Ok(guard) => guard, + Err(_) => { + return; + } + }; + if let Some(arc_res) = guard + .get_mut(&TypeId::of::()) + .and_then(|a| a.downcast_mut::>()) + { + let mut new_res = match Arc::try_unwrap(std::mem::take(arc_res)) { + Ok(val) => val, + Err(arc) => (*arc).res_clone(), + }; + f(&mut new_res); + *arc_res = Arc::new(new_res); + } + } + + /// Get an resources by type, returning `Res` if present + pub fn res(&self) -> Option> { + let guard = self.resources.lock().ok()?; + let boxed_any = guard.get(&TypeId::of::())?; + let arc_res = boxed_any.as_ref().downcast_ref::>()?; + Some(GlobalResource::from(Arc::clone(arc_res))) + } + + /// Get a resource by type, returning `GlobalResource` if present + pub fn res_or_route( + &self, + route: ChainProcess, + ) -> Result, ChainProcess> { + match self.res() { + Some(r) => Ok(r), + None => Err(route), + } + } + + /// Get a resource by type, returning `GlobalResource` or inserting a default + pub fn res_or_default( + &self, + ) -> GlobalResource { + self.res() + .unwrap_or_else(|| GlobalResource::from(Arc::new(Res::res_default()))) + } +} + +/// Global assets for storing Program global state information +pub struct GlobalResource { + res_arc: Arc, +} + +impl GlobalResource { + /// Create a new `GlobalAsset` from an `AssetType` value. + pub fn new(res: ResType) -> Self { + Self { + res_arc: Arc::new(res), + } + } +} + +impl From> for GlobalResource { + fn from(arc: Arc) -> Self { + Self { res_arc: arc } + } +} + +impl std::ops::Deref for GlobalResource { + type Target = ResType; + + fn deref(&self) -> &Self::Target { + &self.res_arc + } +} + +/// Resource marker trait, types that implement the Clone and Default traits can be considered as resources +pub trait ResourceMarker { + fn res_clone(&self) -> Self; + fn res_default() -> Self; +} + +impl ResourceMarker for T { + fn res_clone(&self) -> Self { + Clone::clone(self) + } + + fn res_default() -> Self { + Default::default() + } +} -- cgit