use_event_simulation/
lib.rs1#![forbid(unsafe_code)]
2#[derive(Debug, Clone, Copy, PartialEq)]
27pub struct SimulationEvent {
28 pub time: f64,
29 pub change: f64,
30}
31
32impl SimulationEvent {
33 pub fn new(time: f64, change: f64) -> Option<Self> {
34 if !time.is_finite() || time < 0.0 || !change.is_finite() {
35 return None;
36 }
37
38 Some(Self { time, change })
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq)]
43pub struct EventState {
44 pub time: f64,
45 pub state: f64,
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum EventSimulationError {
50 InvalidInitialState,
51 InvalidEvent,
52 NonFiniteState,
53}
54
55pub fn sorted_events(
56 events: &[SimulationEvent],
57) -> Result<Vec<SimulationEvent>, EventSimulationError> {
58 if events
59 .iter()
60 .any(|event| !event.time.is_finite() || event.time < 0.0 || !event.change.is_finite())
61 {
62 return Err(EventSimulationError::InvalidEvent);
63 }
64
65 let mut sorted = events.to_vec();
66 sorted.sort_by(|left, right| left.time.total_cmp(&right.time));
67 Ok(sorted)
68}
69
70pub fn run_event_simulation(
71 initial_state: f64,
72 events: &[SimulationEvent],
73) -> Result<Vec<EventState>, EventSimulationError> {
74 if !initial_state.is_finite() {
75 return Err(EventSimulationError::InvalidInitialState);
76 }
77
78 let events = sorted_events(events)?;
79 let mut states = Vec::with_capacity(events.len() + 1);
80 let mut current_state = initial_state;
81 states.push(EventState {
82 time: 0.0,
83 state: current_state,
84 });
85
86 for event in events {
87 current_state += event.change;
88 if !current_state.is_finite() {
89 return Err(EventSimulationError::NonFiniteState);
90 }
91
92 states.push(EventState {
93 time: event.time,
94 state: current_state,
95 });
96 }
97
98 Ok(states)
99}
100
101#[cfg(test)]
102mod tests {
103 use super::{EventSimulationError, SimulationEvent, run_event_simulation, sorted_events};
104
105 #[test]
106 fn sorts_events_by_time() {
107 let sorted = sorted_events(&[
108 SimulationEvent::new(3.0, 1.0).unwrap(),
109 SimulationEvent::new(1.0, 2.0).unwrap(),
110 ])
111 .unwrap();
112
113 assert_eq!(sorted[0].time, 1.0);
114 assert_eq!(sorted[1].time, 3.0);
115 }
116
117 #[test]
118 fn runs_event_simulation() {
119 let states = run_event_simulation(
120 10.0,
121 &[
122 SimulationEvent::new(2.0, -1.0).unwrap(),
123 SimulationEvent::new(1.0, 3.0).unwrap(),
124 ],
125 )
126 .unwrap();
127
128 assert_eq!(states.len(), 3);
129 assert_eq!(states[0].state, 10.0);
130 assert_eq!(states[1].time, 1.0);
131 assert_eq!(states[1].state, 13.0);
132 assert_eq!(states[2].state, 12.0);
133 }
134
135 #[test]
136 fn rejects_invalid_inputs() {
137 assert_eq!(SimulationEvent::new(-1.0, 1.0), None);
138 assert_eq!(
139 run_event_simulation(f64::NAN, &[]),
140 Err(EventSimulationError::InvalidInitialState)
141 );
142 assert_eq!(
143 sorted_events(&[SimulationEvent {
144 time: 1.0,
145 change: f64::NAN,
146 }]),
147 Err(EventSimulationError::InvalidEvent)
148 );
149 }
150}