ghostscope_ui/components/loading/
state.rs1use std::time::Instant;
2
3#[derive(Debug, Clone, PartialEq)]
5pub enum LoadingState {
6 Initializing,
8 ConnectingToRuntime,
10 LoadingSymbols { progress: Option<f64> },
12 LoadingSourceCode,
14 Ready,
16 Failed(String),
18}
19
20impl LoadingState {
21 pub fn message(&self) -> &str {
23 match self {
24 LoadingState::Initializing => "Initializing application...",
25 LoadingState::ConnectingToRuntime => "Connecting to runtime...",
26 LoadingState::LoadingSymbols { .. } => "Loading debug information...",
27 LoadingState::LoadingSourceCode => "Loading source code information...",
28 LoadingState::Ready => "Ready",
29 LoadingState::Failed(error) => error,
30 }
31 }
32
33 pub fn progress(&self) -> Option<f64> {
35 match self {
36 LoadingState::LoadingSymbols { progress } => *progress,
37 LoadingState::Ready => Some(1.0),
38 _ => None,
39 }
40 }
41
42 pub fn is_ready(&self) -> bool {
44 matches!(self, LoadingState::Ready)
45 }
46
47 pub fn is_failed(&self) -> bool {
49 matches!(self, LoadingState::Failed(_))
50 }
51}
52
53#[derive(Debug, Clone)]
55pub struct ModuleLoadStatus {
56 pub path: String,
57 pub state: ModuleState,
58 pub stats: Option<ModuleStats>,
59 pub start_time: Option<Instant>,
60 pub load_time: Option<f64>, }
62
63#[derive(Debug, Clone)]
64pub enum ModuleState {
65 Queued,
66 Loading,
67 Completed,
68 Failed(String),
69}
70
71#[derive(Debug, Clone)]
72pub struct ModuleStats {
73 pub functions: usize,
74 pub variables: usize,
75 pub types: usize,
76}
77
78impl ModuleLoadStatus {
79 pub fn new(path: String) -> Self {
80 Self {
81 path,
82 state: ModuleState::Queued,
83 stats: None,
84 start_time: None,
85 load_time: None,
86 }
87 }
88
89 pub fn start_loading(&mut self) {
90 self.state = ModuleState::Loading;
91 self.start_time = Some(Instant::now());
92 }
93
94 pub fn complete(&mut self, stats: ModuleStats) {
95 if let Some(start_time) = self.start_time {
96 self.load_time = Some(start_time.elapsed().as_secs_f64());
97 }
98 self.state = ModuleState::Completed;
99 self.stats = Some(stats);
100 }
101
102 pub fn fail(&mut self, error: String) {
103 if let Some(start_time) = self.start_time {
104 self.load_time = Some(start_time.elapsed().as_secs_f64());
105 }
106 self.state = ModuleState::Failed(error);
107 }
108}
109
110#[derive(Debug, Clone)]
112pub struct LoadingProgress {
113 pub start_time: Instant,
114 pub modules: Vec<ModuleLoadStatus>,
115 pub completed_count: usize,
116 pub failed_count: usize,
117 pub current_loading: Option<String>,
118}
119
120impl LoadingProgress {
121 pub fn new() -> Self {
122 Self {
123 start_time: Instant::now(),
124 modules: Vec::new(),
125 completed_count: 0,
126 failed_count: 0,
127 current_loading: None,
128 }
129 }
130
131 pub fn add_module(&mut self, path: String) {
132 self.modules.push(ModuleLoadStatus::new(path));
133 }
134
135 pub fn start_module_loading(&mut self, path: &str) {
136 if let Some(module) = self.modules.iter_mut().find(|m| m.path == path) {
137 module.start_loading();
138 self.current_loading = Some(path.to_string());
139 }
140 }
141
142 pub fn complete_module(&mut self, path: &str, stats: ModuleStats) {
143 if let Some(module) = self.modules.iter_mut().find(|m| m.path == path) {
144 module.complete(stats);
145 self.completed_count += 1;
146 if self.current_loading.as_deref() == Some(path) {
147 self.current_loading = None;
148 }
149 }
150 }
151
152 pub fn fail_module(&mut self, path: &str, error: String) {
153 if let Some(module) = self.modules.iter_mut().find(|m| m.path == path) {
154 module.fail(error);
155 self.failed_count += 1;
156 if self.current_loading.as_deref() == Some(path) {
157 self.current_loading = None;
158 }
159 }
160 }
161
162 pub fn total_modules(&self) -> usize {
163 self.modules.len()
164 }
165
166 pub fn progress_ratio(&self) -> f64 {
167 if self.modules.is_empty() {
168 0.0
169 } else {
170 (self.completed_count + self.failed_count) as f64 / self.modules.len() as f64
171 }
172 }
173
174 pub fn elapsed_time(&self) -> f64 {
175 self.start_time.elapsed().as_secs_f64()
176 }
177
178 pub fn recently_completed(&self, limit: usize) -> Vec<&ModuleLoadStatus> {
179 self.modules
180 .iter()
181 .filter(|m| matches!(m.state, ModuleState::Completed))
182 .rev()
183 .take(limit)
184 .collect()
185 }
186
187 pub fn recently_failed(&self, limit: usize) -> Vec<&ModuleLoadStatus> {
188 self.modules
189 .iter()
190 .filter(|m| matches!(m.state, ModuleState::Failed(_)))
191 .rev()
192 .take(limit)
193 .collect()
194 }
195
196 pub fn recently_finished(&self, limit: usize) -> Vec<&ModuleLoadStatus> {
197 self.modules
198 .iter()
199 .filter(|m| matches!(m.state, ModuleState::Completed | ModuleState::Failed(_)))
200 .rev()
201 .take(limit)
202 .collect()
203 }
204
205 pub fn total_stats(&self) -> ModuleStats {
206 let mut total = ModuleStats {
207 functions: 0,
208 variables: 0,
209 types: 0,
210 };
211
212 for module in &self.modules {
213 if let Some(stats) = &module.stats {
214 total.functions += stats.functions;
215 total.variables += stats.variables;
216 total.types += stats.types;
217 }
218 }
219
220 total
221 }
222
223 pub fn is_complete(&self) -> bool {
224 !self.modules.is_empty() && (self.completed_count + self.failed_count) == self.modules.len()
225 }
226}
227
228impl Default for LoadingProgress {
229 fn default() -> Self {
230 Self::new()
231 }
232}