1use gled_model::collection::Collections;
5
6use crate::{
7 assets::collections_from, message::ServerMessage, project_update::ProjectUpdate,
8 state::EngineState,
9};
10
11#[derive(Debug, Clone, Default)]
12pub struct StateReplica {
13 pub state: EngineState,
14 pub applied_sequence: u64,
16 pub complete: bool,
18 pub assets: Collections,
20 pub(crate) assets_complete: bool,
22 pub project_changes: u64,
26 pub assets_changes: u64,
29}
30
31impl StateReplica {
32 pub fn apply(&mut self, message: &ServerMessage) -> bool {
34 match message {
35 ServerMessage::State {
36 state,
37 applied_sequence,
38 } => {
39 self.state = EngineState::clone(state);
40 self.applied_sequence = *applied_sequence;
41 self.complete = true;
42 self.project_changes += 1;
43 true
44 }
45 ServerMessage::Update {
46 state,
47 project,
48 applied_sequence,
49 } if self.complete => {
50 if !matches!(project, ProjectUpdate::Unchanged) {
51 self.project_changes += 1;
52 }
53 let mut replica_project = self.state.project.take();
54 project.clone().apply_to(&mut replica_project);
55 self.state = EngineState {
56 project: replica_project,
57 ..EngineState::clone(state)
58 };
59 self.applied_sequence = *applied_sequence;
60 true
61 }
62 ServerMessage::Assets(assets) => {
63 self.assets = collections_from(assets.clone());
64 self.assets_complete = true;
65 self.assets_changes += 1;
66 true
67 }
68 ServerMessage::AssetsChanged(changes) if self.assets_complete => {
69 changes.clone().apply_to(&mut self.assets);
70 self.assets_changes += 1;
71 true
72 }
73 ServerMessage::Timing { beat, render } if self.complete => {
74 self.state.beat = *beat;
75 self.state.render = *render;
76 true
77 }
78 _ => false,
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use std::sync::Arc;
86
87 use gled_model::asset::project::Project;
88
89 use super::*;
90
91 fn update(project: ProjectUpdate) -> ServerMessage {
92 ServerMessage::Update {
93 state: Arc::default(),
94 project,
95 applied_sequence: 0,
96 }
97 }
98
99 #[test]
100 fn only_messages_that_may_change_the_project_are_counted() {
101 let mut replica = StateReplica::default();
102 replica.apply(&ServerMessage::State {
103 state: Arc::default(),
104 applied_sequence: 0,
105 });
106 assert_eq!(replica.project_changes, 1, "a full state");
107
108 replica.apply(&update(ProjectUpdate::Unchanged));
109 assert_eq!(replica.project_changes, 1, "an update without one");
110
111 let project = Project::default();
112 replica.apply(&update(ProjectUpdate::between(None, Some(&project))));
113 assert_eq!(replica.project_changes, 2, "another project");
114 assert_eq!(replica.state.project.as_deref(), Some(&project));
115 }
116
117 #[test]
118 fn asset_messages_are_counted() {
119 let mut replica = StateReplica::default();
120 replica.apply(&ServerMessage::AssetsChanged(Default::default()));
121 assert_eq!(replica.assets_changes, 0, "changes before the assets");
122 replica.apply(&ServerMessage::Assets(Vec::new()));
123 replica.apply(&ServerMessage::AssetsChanged(Default::default()));
124 assert_eq!(replica.assets_changes, 2);
125 }
126}