ghostscope_ui/components/loading/
state.rs

1use std::time::Instant;
2
3/// Loading states for different initialization phases
4#[derive(Debug, Clone, PartialEq)]
5pub enum LoadingState {
6    /// Application is starting up
7    Initializing,
8    /// Waiting for runtime to connect
9    ConnectingToRuntime,
10    /// Waiting for DWARF symbols to load
11    LoadingSymbols { progress: Option<f64> },
12    /// Waiting for source code information
13    LoadingSourceCode,
14    /// Loading completed, application ready
15    Ready,
16    /// Loading failed with error
17    Failed(String),
18}
19
20impl LoadingState {
21    /// Get display message for current loading state
22    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    /// Get progress value (0.0 to 1.0) if available
34    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    /// Check if loading is complete
43    pub fn is_ready(&self) -> bool {
44        matches!(self, LoadingState::Ready)
45    }
46
47    /// Check if loading failed
48    pub fn is_failed(&self) -> bool {
49        matches!(self, LoadingState::Failed(_))
50    }
51}
52
53/// Module loading status for individual modules
54#[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>, // seconds
61}
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/// Overall loading progress tracking
111#[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}