concinnity_core/ecs/system_entry.rs
1//! The system table a host hands [`World::start`](crate::ecs::World::start):
2//! one entry per system in run order, plus the load-time passes that bracket
3//! them.
4//!
5//! The table is a document. Table order is run order, and the `after` / `before`
6//! edges are checked against it rather than resolved into one, so a reader can
7//! take the file top to bottom as the tick. What builds the systems is a gate
8//! per entry: it inspects the world's content and returns the constructed
9//! system, or `None` to leave it out.
10
11use alloc::boxed::Box;
12
13use crate::ecs::{Access, EventStore, PipelineContext, System, World};
14use crate::result::CnResult;
15
16/// One row of the system table. Table order is run order.
17pub struct SystemEntry {
18 /// The entry name; the system's stable display name.
19 pub name: &'static str,
20 /// Human-readable gate condition, for docs and CLI reporting.
21 pub present_when: &'static str,
22 /// Constructs the system from world content when its gate holds. Runs from
23 /// `World::start` and from `World::system_manifest`, which discards the
24 /// value, so a system's constructor must stay cheap and side-effect-free.
25 pub gate: fn(&World) -> Option<Box<dyn System>>,
26 /// Systems (by entry name) that must run earlier in the tick than this one.
27 /// Validated against table order at schedule build: the table stays the one
28 /// execution order, and an edge that contradicts it is a startup panic, not
29 /// a silent reorder.
30 pub after: &'static [&'static str],
31 /// Systems this one must run before.
32 pub before: &'static [&'static str],
33}
34
35/// A host's completion pass: it runs over the world before the gates read it,
36/// and fails the start when the world cannot be completed.
37pub type CompleteWorld = fn(&mut PipelineContext) -> Result<(), CnResult>;
38
39/// A host's system table and the load-time passes only the host can supply.
40///
41/// The entries name the host's own system types, so the table is written where
42/// those types live; everything that runs it is here.
43pub struct SystemTable {
44 /// One entry per system, in run order.
45 pub entries: &'static [SystemEntry],
46 /// Runs over the world before the gates read it, so a component the pass
47 /// injects can still bring its system into the schedule. Absent leaves the
48 /// world exactly as it was loaded.
49 pub complete_world: Option<CompleteWorld>,
50 /// Runs over the world once its systems are built and before their `init`.
51 /// Absent leaves the loaded content exactly as it was added.
52 pub before_init: Option<fn(&mut PipelineContext)>,
53 /// Pre-creates the event queues a scheduled system's declared access can
54 /// touch, so its `events_mut` never grows the store's map mid-tick. Absent
55 /// leaves every queue to be created on first use.
56 pub prepare_events: Option<fn(&mut EventStore, Access)>,
57}
58
59impl SystemTable {
60 /// A table with no systems and no load-time passes: what a world runs when
61 /// its host contributes none.
62 pub const EMPTY: Self = Self {
63 entries: &[],
64 complete_world: None,
65 before_init: None,
66 prepare_events: None,
67 };
68}