use std::{borrow::Cow, ptr::NonNull}; use crate::{ExclusiveSystem, ExclusiveSystemDescriptor, ParallelSystemDescriptor, System}; pub(super) trait SystemContainer { fn display_name(&self) -> Cow<'static, str>; fn dependencies(&self) -> &[usize]; fn set_dependencies(&mut self, dependencies: impl IntoIterator); fn system_set(&self) -> usize; fn label(&self) -> &Option>; fn before(&self) -> &[Cow<'static, str>]; fn after(&self) -> &[Cow<'static, str>]; fn is_compatible(&self, other: &Self) -> bool; } pub(super) struct ExclusiveSystemContainer { system: Box, dependencies: Vec, set: usize, label: Option>, before: Vec>, after: Vec>, } impl ExclusiveSystemContainer { pub fn from_descriptor(descriptor: ExclusiveSystemDescriptor, set: usize) -> Self { ExclusiveSystemContainer { system: descriptor.system, dependencies: Vec::new(), set, label: descriptor.label, before: descriptor.before, after: descriptor.after, } } pub fn system_mut(&mut self) -> &mut Box { &mut self.system } } impl SystemContainer for ExclusiveSystemContainer { fn display_name(&self) -> Cow<'static, str> { self.label .as_ref() .cloned() .unwrap_or_else(|| self.system.name()) } fn dependencies(&self) -> &[usize] { &self.dependencies } fn set_dependencies(&mut self, dependencies: impl IntoIterator) { self.dependencies.clear(); self.dependencies.extend(dependencies); } fn system_set(&self) -> usize { self.set } fn label(&self) -> &Option> { &self.label } fn before(&self) -> &[Cow<'static, str>] { &self.before } fn after(&self) -> &[Cow<'static, str>] { &self.after } fn is_compatible(&self, _: &Self) -> bool { false } } pub struct ParallelSystemContainer { system: NonNull>, pub(crate) should_run: bool, dependencies: Vec, set: usize, label: Option>, before: Vec>, after: Vec>, } impl SystemContainer for ParallelSystemContainer { fn display_name(&self) -> Cow<'static, str> { self.label .as_ref() .cloned() .unwrap_or_else(|| self.system().name()) } fn dependencies(&self) -> &[usize] { &self.dependencies } fn set_dependencies(&mut self, dependencies: impl IntoIterator) { self.dependencies.clear(); self.dependencies.extend(dependencies); } fn system_set(&self) -> usize { self.set } fn label(&self) -> &Option> { &self.label } fn before(&self) -> &[Cow<'static, str>] { &self.before } fn after(&self) -> &[Cow<'static, str>] { &self.after } fn is_compatible(&self, other: &Self) -> bool { self.system() .component_access() .is_compatible(other.system().component_access()) && self .system() .resource_access() .is_compatible(other.system().resource_access()) } } unsafe impl Send for ParallelSystemContainer {} unsafe impl Sync for ParallelSystemContainer {} impl ParallelSystemContainer { pub(crate) fn from_descriptor(descriptor: ParallelSystemDescriptor, set: usize) -> Self { ParallelSystemContainer { system: unsafe { NonNull::new_unchecked(Box::into_raw(descriptor.system)) }, should_run: false, set, dependencies: Vec::new(), label: descriptor.label, before: descriptor.before, after: descriptor.after, } } pub fn display_name(&self) -> Cow<'static, str> { SystemContainer::display_name(self) } pub fn system(&self) -> &dyn System { // SAFE: statically enforced shared access. unsafe { self.system.as_ref() } } pub fn system_mut(&mut self) -> &mut dyn System { // SAFE: statically enforced exclusive access. unsafe { self.system.as_mut() } } /// # Safety /// Ensure no other borrows exist along with this one. #[allow(clippy::mut_from_ref)] pub unsafe fn system_mut_unsafe(&self) -> &mut dyn System { &mut *self.system.as_ptr() } pub fn should_run(&self) -> bool { self.should_run } pub fn dependencies(&self) -> &[usize] { &self.dependencies } }