use std::sync::Arc;
use crate::engine::error::ECSResult;
use crate::engine::manager::ECSReference;
use crate::engine::systems::{AccessSets, System, SystemBackend};
use crate::engine::types::SystemID;
use super::store::Environment;
type EnvironmentSystemFn =
dyn Fn(Arc<Environment>, ECSReference<'_>) -> ECSResult<()> + Send + Sync;
pub struct EnvironmentSystem {
id: SystemID,
name: String,
access: AccessSets,
env: Arc<Environment>,
func: Box<EnvironmentSystemFn>,
}
impl EnvironmentSystem {
pub fn new<F>(
id: SystemID,
name: impl Into<String>,
access: AccessSets,
env: Arc<Environment>,
func: F,
) -> Self
where
F: Fn(Arc<Environment>, ECSReference<'_>) -> ECSResult<()> + Send + Sync + 'static,
{
Self {
id,
name: name.into(),
access,
env,
func: Box::new(func),
}
}
}
impl System for EnvironmentSystem {
#[inline]
fn id(&self) -> SystemID {
self.id
}
#[inline]
fn name(&self) -> &str {
&self.name
}
#[inline]
fn access(&self) -> &AccessSets {
&self.access
}
#[inline]
fn backend(&self) -> SystemBackend {
SystemBackend::CPU
}
fn run(&self, ecs: ECSReference<'_>) -> ECSResult<()> {
(self.func)(Arc::clone(&self.env), ecs)
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::engine::systems::{AccessSets, System};
use crate::environment::builder::EnvironmentBuilder;
use super::EnvironmentSystem;
#[test]
fn trait_accessors() {
let env = EnvironmentBuilder::new()
.register::<f32>("rate", 0.0f32)
.unwrap()
.build()
.unwrap();
let sys =
EnvironmentSystem::new(
7u16,
"TestSystem",
AccessSets::default(),
env,
|_, _| Ok(()),
);
assert_eq!(sys.id(), 7u16);
assert_eq!(sys.name(), "TestSystem");
assert!(matches!(
sys.backend(),
crate::engine::systems::SystemBackend::CPU
));
}
#[test]
fn system_captures_shared_env() {
let env = EnvironmentBuilder::new()
.register::<u32>("counter", 0u32)
.unwrap()
.build()
.unwrap();
let _sys = EnvironmentSystem::new(
0u16,
"IncrementCounter",
AccessSets::default(),
Arc::clone(&env),
move |_e, _ecs| Ok(()),
);
env.set::<u32>("counter", 5).unwrap();
assert_eq!(env.get::<u32>("counter").unwrap(), 5u32);
}
#[test]
fn shared_env_across_systems() {
let env = EnvironmentBuilder::new()
.register::<i32>("val", 10)
.unwrap()
.build()
.unwrap();
let env_a = Arc::clone(&env);
let env_b = Arc::clone(&env);
let _a = EnvironmentSystem::new(0u16, "A", AccessSets::default(), env_a, |_, _| Ok(()));
let _b = EnvironmentSystem::new(1u16, "B", AccessSets::default(), env_b, |_, _| Ok(()));
env.set::<i32>("val", 99).unwrap();
assert_eq!(env.get::<i32>("val").unwrap(), 99);
}
#[test]
fn duplicate_names_are_independent() {
let env = EnvironmentBuilder::new()
.register::<f32>("x", 0.0)
.unwrap()
.build()
.unwrap();
let a = EnvironmentSystem::new(
0u16,
"SharedName",
AccessSets::default(),
Arc::clone(&env),
|_, _| Ok(()),
);
let b = EnvironmentSystem::new(
1u16,
"SharedName",
AccessSets::default(),
Arc::clone(&env),
|_, _| Ok(()),
);
assert_eq!(a.name(), "SharedName");
assert_eq!(b.name(), "SharedName");
assert!(!std::ptr::eq(a.name().as_ptr(), b.name().as_ptr()));
}
}