viewport_lib/runtime/resources.rs
1//! Typed resource registry for sharing engine-owned state across runtime plugins.
2
3use std::any::{Any, TypeId};
4use std::collections::HashMap;
5
6/// Typed resource registry stored on [`super::ViewportRuntime`].
7///
8/// Accessible from [`super::context::RuntimeStepContext`] each frame. Resources
9/// persist across frames until explicitly removed or the runtime is dropped.
10///
11/// Each type `T` maps to at most one value. Inserting again overwrites the previous
12/// value of the same type.
13///
14/// # Ownership rules
15///
16/// Resources are engine-owned: they live for the lifetime of the `ViewportRuntime`
17/// they belong to. Use resources for state that two or more plugins need to share
18/// within the same runtime instance. Use plugin-local `struct` fields for state
19/// that belongs to only one plugin and does not need to be shared.
20///
21/// # Example
22///
23/// ```rust,ignore
24/// // Plugin A (ANIMATE phase) writes a shared value.
25/// fn step(&mut self, ctx: &mut RuntimeStepContext) {
26/// ctx.resources.insert(MySharedState { value: 42 });
27/// }
28///
29/// // Plugin B (POST_SIM phase) reads it.
30/// fn step(&mut self, ctx: &mut RuntimeStepContext) {
31/// if let Some(state) = ctx.resources.get::<MySharedState>() {
32/// println!("shared value: {}", state.value);
33/// }
34/// }
35/// ```
36#[derive(Default)]
37pub struct RuntimeResources {
38 map: HashMap<TypeId, Box<dyn Any + Send + 'static>>,
39}
40
41impl RuntimeResources {
42 /// Create an empty resource registry.
43 pub fn new() -> Self {
44 Self {
45 map: HashMap::new(),
46 }
47 }
48
49 /// Insert a resource, replacing any existing value of the same type.
50 pub fn insert<T: Send + 'static>(&mut self, value: T) {
51 self.map.insert(TypeId::of::<T>(), Box::new(value));
52 }
53
54 /// Get a shared reference to a resource. Returns `None` if not present.
55 pub fn get<T: Send + 'static>(&self) -> Option<&T> {
56 self.map
57 .get(&TypeId::of::<T>())
58 .and_then(|b| b.downcast_ref::<T>())
59 }
60
61 /// Get a mutable reference to a resource. Returns `None` if not present.
62 pub fn get_mut<T: Send + 'static>(&mut self) -> Option<&mut T> {
63 self.map
64 .get_mut(&TypeId::of::<T>())
65 .and_then(|b| b.downcast_mut::<T>())
66 }
67
68 /// Remove a resource and return it. Returns `None` if not present.
69 pub fn remove<T: Send + 'static>(&mut self) -> Option<T> {
70 self.map
71 .remove(&TypeId::of::<T>())
72 .and_then(|b| b.downcast::<T>().ok())
73 .map(|b| *b)
74 }
75
76 /// Returns `true` if a resource of this type is present.
77 pub fn contains<T: Send + 'static>(&self) -> bool {
78 self.map.contains_key(&TypeId::of::<T>())
79 }
80}