Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::thread;
- trait System {}
- struct SystemEntry {
- /// The system to execute
- system: Box<dyn System>
- /// The max value for the gate
- gate_max: usize
- /// The gate blocking a system's execution till it completes
- gate: usize,
- }
- impl SystemEntry {
- /// Decrement the gate toward zero
- #[inline]
- pub fn decrement(&mut self) {
- self.gate.saturating_sub(1);
- }
- /// Reset the gate for another pass
- #[inline]
- pub fn reset(&mut self) {
- self.gate = self.gate_max;
- }
- /// Whether the system entry is ready for execution
- #[inline]
- pub fn can_execute(&self) -> bool {
- self.gate == 0
- }
- }
- /// A node in the system graph
- ///
- /// ### Safety
- /// This struct is highly unsafe and only intended for use inside `SystemGraph`
- struct Node {
- /// Pointer to the system this node owns
- system: *mut SystemEntry,
- /// A pointer to the list of child pointers for this node. Set to null if the node has no children
- child_ptr: *mut Node,
- /// The number of child pointers in this node. Set to 0 if the node has no children
- child_len: usize
- }
- impl Node {
- /// Execute the system this entry points to
- ///
- /// ### Safety
- /// Assumes that the underlying pointer is valid
- #[inline]
- pub unsafe fn execute(&self){
- (*self.system).system.execute();
- }
- /// Get the child pointers of this node
- ///
- /// ### Safety
- /// Assumes that `child_ptr` is valid and that there are
- /// at least `child_len - 1` pointers in memory after it
- pub unsafe fn children(&self) -> &[*mut Node] {
- slice::from_raw_parts(
- self.child_ptr as *const Node,
- self.child_len
- )
- }
- }
- /// A DAG describing how systems in the ecs relate and their execution order.
- ///
- /// ### Remarks
- /// This is a special system that lives outside the usual ecs execution order
- struct SystemGraph {
- /// The list of systems in this graph
- systems: Vec<SystemEntry>,
- /// The nodes describing the graph
- nodes: Vec<Node>
- /// The child pointers for the nodes of this graph
- child_ptrs: Vec<*mut Node>,
- }
- impl SystemGraph {
- /// Get the root node of the graph. The first node is always an empty logical node
- /// that points to all the children in the graph
- ///
- /// ### Safety
- /// The node pointer in this node is NOT valid and should not be dereferenced
- pub fn root(&self) -> &Node {
- &self.nodes[0]
- }
- }
- struct ActiveJob {
- /// The node this job belongs to
- node: *mut Node,
- /// The completion handle for this job
- completion_handle: JobHandle
- }
- impl ActiveJob {
- /// Create a new active job entry for a given node and handle
- ///
- /// ### Safety
- /// Assumes that the node is a valid pointer and will remain valid till the job
- /// is completed
- pub fn new(node: *mut Node, handle: JobHandle) -> Self {
- Self {
- node: node,
- completion_handle: handle
- }
- }
- /// Check if the job has completed, if so
- #[inline]
- pub fn completed(&self) -> bool {
- self.completion_handle.is_complete()
- }
- }
- /// The executor that handles executing all ECS systems as jobs
- struct EcsExecutor {
- /// The dag describing the system execution order
- dag: SystemGraph,
- /// The list of entries pending execution
- pending: Vec<*mut SystemEntry>,
- /// The jobs currently in flight
- in_flight: Vec<ActiveJob>,
- }
- impl EcsExecutor {
- fn execute(&mut self) {
- unsafe {
- // Queue up the root tasks and begin execution
- let root = self.dag.root();
- for child in root.children() {
- // TODO: Execute the child
- let handle = execute_child();
- self.in_flight.push(ActiveJob::(child, handle));
- }
- // Continue to dispatch tasks till the entire dag has been traversed
- while !self.in_flight.is_empty() {
- // Check if any in flight jobs have completed
- for job in self.in_flight.iter() {
- if !job.completed() {
- continue;
- }
- let children = (*job.node).children();
- for child in children.iter() {
- (*child).gate.saturating_sub(1);
- // The last prerequisite for the child has completed
- // begin executing the child
- if (*child).gate == 0 {
- // TODO: Execute the child
- let handle = execute_child();
- self.in_flight.push(ActiveJob::(child, handle));
- }
- }
- self.in_flight.remove(job);
- }
- // Yield while the job threads process the active work
- thread::yield_now();
- }
- // At this point `in_flight` should be empty and all systems have finished executing
- // TODO: Join on the remaining tasks
- }
- }
- }
- fn main() {
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement