1use std::fmt;
2
3use crate::bridge::{Drag, DragError, DragRelease};
4use crate::command::{CommandResult, Commands};
5use crate::domain::{ChartPoint, DomainError, Domains};
6use crate::input::Input;
7use crate::session::{Manipulation, PreparedGeometry};
8use crate::stores::Stores;
9use crate::view::{Pick, Views};
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
13pub enum Phase {
14 Dispatch,
15 Simulation,
16 Publication,
17}
18
19impl Phase {
20 pub const ALL: [Phase; 3] = [Phase::Dispatch, Phase::Simulation, Phase::Publication];
21
22 fn index(self) -> usize {
23 self as usize
24 }
25}
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28pub enum Order {
29 Before(&'static str),
30 After(&'static str),
31}
32
33#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
34pub struct Tick(pub u64);
35
36#[derive(Clone, Copy, Debug, PartialEq)]
37pub struct Step {
38 pub tick: Tick,
39 pub dt: f32,
40}
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43pub struct PhaseError {
44 pub phase: Phase,
45 pub system: Option<&'static str>,
46 pub cause: DomainError,
47}
48
49impl PhaseError {
50 pub(crate) fn system(phase: Phase, system: &'static str, cause: DomainError) -> Self {
51 Self {
52 phase,
53 system: Some(system),
54 cause,
55 }
56 }
57
58 pub(crate) fn unnamed(phase: Phase, cause: DomainError) -> Self {
59 Self {
60 phase,
61 system: None,
62 cause,
63 }
64 }
65}
66
67impl fmt::Display for PhaseError {
68 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
69 match self.system {
70 Some(system) => write!(
71 formatter,
72 "system `{system}` failed in {:?}: {}",
73 self.phase, self.cause
74 ),
75 None => write!(formatter, "{:?} phase failed: {}", self.phase, self.cause),
76 }
77 }
78}
79
80impl std::error::Error for PhaseError {}
81
82pub struct Ctx<'a, A> {
83 pub app: &'a mut A,
84 pub domains: &'a mut Domains,
85 pub views: &'a mut Views,
86 pub commands: &'a mut Commands<A>,
87 pub results: &'a [CommandResult],
88 pub input: &'a Input,
89 pub prepared: &'a [PreparedGeometry],
90 pub step: Step,
91 pub(crate) manipulation: &'a mut Manipulation,
92}
93
94impl<A: Stores> Ctx<'_, A> {
95 pub fn pick(&self, ndc: [f32; 2]) -> Option<Pick> {
96 self.domains.pick(self.views, self.prepared, ndc)
97 }
98
99 pub fn dragging(&self) -> Option<Drag> {
100 self.manipulation.dragging()
101 }
102
103 pub fn grab(&mut self, ndc: [f32; 2], time: f64) -> Result<Pick, DragError> {
104 self.manipulation.grab(
105 self.domains,
106 self.views,
107 self.prepared,
108 self.commands,
109 ndc,
110 time,
111 )
112 }
113
114 pub fn drag(&mut self, ndc: [f32; 2], time: f64) -> Result<ChartPoint, DragError> {
115 self.manipulation
116 .drag(self.domains, self.views, self.commands, ndc, time)
117 }
118
119 pub fn release(&mut self) -> Option<DragRelease> {
120 self.manipulation.release(self.commands)
121 }
122
123 pub fn release_at(&mut self, time: f64) -> Option<DragRelease> {
124 self.manipulation.release_at(self.commands, time)
125 }
126
127 pub fn cancel_drag(&mut self) -> Option<DragRelease> {
128 self.manipulation.cancel(self.commands)
129 }
130}
131
132pub trait System<A>: Send + 'static {
133 fn run(&mut self, ctx: Ctx<'_, A>) -> Result<(), DomainError>;
134}
135
136impl<A: 'static, F> System<A> for F
137where
138 F: FnMut(Ctx<'_, A>) -> Result<(), DomainError> + Send + 'static,
139{
140 fn run(&mut self, ctx: Ctx<'_, A>) -> Result<(), DomainError> {
141 self(ctx)
142 }
143}
144
145type Runner<A> = Box<dyn FnMut(Ctx<'_, A>) -> Result<(), DomainError> + Send>;
146
147pub struct SystemEntry<A> {
148 name: &'static str,
149 run: Runner<A>,
150}
151
152impl<A: 'static> SystemEntry<A> {
153 pub(crate) fn new(name: &'static str, system: impl System<A>) -> Self {
154 let mut system = system;
155 Self {
156 name,
157 run: Box::new(move |ctx| system.run(ctx)),
158 }
159 }
160}
161
162impl<A> SystemEntry<A> {
163 pub fn name(&self) -> &'static str {
164 self.name
165 }
166
167 pub(crate) fn run(&mut self, ctx: Ctx<'_, A>) -> Result<(), DomainError> {
168 (self.run)(ctx)
169 }
170}
171
172pub(crate) struct Phases<A> {
173 entries: [Vec<SystemEntry<A>>; 3],
174}
175
176impl<A> Phases<A> {
177 pub(crate) fn new() -> Self {
178 Self {
179 entries: Default::default(),
180 }
181 }
182
183 pub(crate) fn push(&mut self, phase: Phase, entry: SystemEntry<A>) {
184 self.entries[phase.index()].push(entry);
185 }
186
187 pub(crate) fn insert(
188 &mut self,
189 phase: Phase,
190 order: Order,
191 entry: SystemEntry<A>,
192 ) -> Option<()> {
193 let list = &mut self.entries[phase.index()];
194 let index = match order {
195 Order::Before(name) => list.iter().position(|entry| entry.name() == name)?,
196 Order::After(name) => list.iter().position(|entry| entry.name() == name)? + 1,
197 };
198 list.insert(index, entry);
199 Some(())
200 }
201
202 pub(crate) fn entries(&self, phase: Phase) -> &[SystemEntry<A>] {
203 &self.entries[phase.index()]
204 }
205
206 pub(crate) fn entries_mut(&mut self, phase: Phase) -> &mut [SystemEntry<A>] {
207 &mut self.entries[phase.index()]
208 }
209}