ricecoder_tui/
performance.rs1use std::collections::VecDeque;
7
8#[derive(Debug, Clone)]
10pub struct LazyLoadConfig {
11 pub chunk_size: usize,
13 pub max_chunks: usize,
15}
16
17impl Default for LazyLoadConfig {
18 fn default() -> Self {
19 Self {
20 chunk_size: 50,
21 max_chunks: 10,
22 }
23 }
24}
25
26#[derive(Debug, Clone)]
28pub struct LazyMessageHistory {
29 messages: VecDeque<String>,
31 config: LazyLoadConfig,
33 total_count: usize,
35 first_loaded_index: usize,
37}
38
39impl LazyMessageHistory {
40 pub fn new(config: LazyLoadConfig) -> Self {
42 Self {
43 messages: VecDeque::with_capacity(config.chunk_size * config.max_chunks),
44 config,
45 total_count: 0,
46 first_loaded_index: 0,
47 }
48 }
49
50 pub fn add_message(&mut self, message: String) {
52 self.messages.push_back(message);
53 self.total_count += 1;
54
55 let max_capacity = self.config.chunk_size * self.config.max_chunks;
57 while self.messages.len() > max_capacity {
58 self.messages.pop_front();
59 self.first_loaded_index += 1;
60 }
61 }
62
63 pub fn visible_messages(&self, start_index: usize, count: usize) -> Vec<&String> {
65 let end_index = (start_index + count).min(self.total_count);
66 let relative_start = start_index.saturating_sub(self.first_loaded_index);
67 let relative_end = end_index.saturating_sub(self.first_loaded_index);
68
69 if relative_start >= self.messages.len() || relative_end <= relative_start {
70 return Vec::new();
71 }
72
73 self.messages
74 .iter()
75 .skip(relative_start)
76 .take(relative_end - relative_start)
77 .collect()
78 }
79
80 pub fn total_count(&self) -> usize {
82 self.total_count
83 }
84
85 pub fn loaded_count(&self) -> usize {
87 self.messages.len()
88 }
89
90 pub fn clear(&mut self) {
92 self.messages.clear();
93 self.total_count = 0;
94 self.first_loaded_index = 0;
95 }
96}
97
98#[derive(Debug, Clone)]
100pub struct DiffRenderOptimizer {
101 pub max_lines_per_render: usize,
103 pub enable_syntax_highlighting: bool,
105}
106
107impl Default for DiffRenderOptimizer {
108 fn default() -> Self {
109 Self {
110 max_lines_per_render: 1000,
111 enable_syntax_highlighting: true,
112 }
113 }
114}
115
116impl DiffRenderOptimizer {
117 pub fn new() -> Self {
119 Self::default()
120 }
121
122 pub fn is_large_diff(&self, total_lines: usize) -> bool {
124 total_lines > self.max_lines_per_render * 2
125 }
126
127 pub fn recommended_chunk_size(&self, total_lines: usize) -> usize {
129 if self.is_large_diff(total_lines) {
130 self.max_lines_per_render / 2
131 } else {
132 total_lines
133 }
134 }
135
136 pub fn should_disable_syntax_highlighting(&self, total_lines: usize) -> bool {
138 total_lines > self.max_lines_per_render * 5
139 }
140}
141
142#[derive(Debug, Clone, Default)]
144pub struct ThemeSwitchPerformance {
145 pub last_switch_time_ms: u64,
147 pub average_switch_time_ms: u64,
149 pub switch_count: u32,
151}
152
153impl ThemeSwitchPerformance {
154 pub fn record_switch(&mut self, time_ms: u64) {
156 self.last_switch_time_ms = time_ms;
157 self.average_switch_time_ms = (self.average_switch_time_ms * self.switch_count as u64
158 + time_ms)
159 / (self.switch_count as u64 + 1);
160 self.switch_count += 1;
161 }
162
163 pub fn is_performant(&self) -> bool {
165 self.last_switch_time_ms < 100 && self.average_switch_time_ms < 100
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 #[test]
174 fn test_lazy_message_history_add_and_retrieve() {
175 let mut history = LazyMessageHistory::new(LazyLoadConfig {
176 chunk_size: 10,
177 max_chunks: 2,
178 });
179
180 for i in 0..15 {
181 history.add_message(format!("Message {}", i));
182 }
183
184 assert_eq!(history.total_count(), 15);
185 assert_eq!(history.loaded_count(), 15);
186 }
187
188 #[test]
189 fn test_lazy_message_history_eviction() {
190 let mut history = LazyMessageHistory::new(LazyLoadConfig {
191 chunk_size: 5,
192 max_chunks: 2,
193 });
194
195 for i in 0..20 {
196 history.add_message(format!("Message {}", i));
197 }
198
199 assert_eq!(history.loaded_count(), 10);
201 assert_eq!(history.total_count(), 20);
202 }
203
204 #[test]
205 fn test_lazy_message_history_visible_messages() {
206 let mut history = LazyMessageHistory::new(LazyLoadConfig {
207 chunk_size: 10,
208 max_chunks: 2,
209 });
210
211 for i in 0..15 {
212 history.add_message(format!("Message {}", i));
213 }
214
215 let visible = history.visible_messages(5, 5);
216 assert_eq!(visible.len(), 5);
217 }
218
219 #[test]
220 fn test_diff_render_optimizer_large_diff() {
221 let optimizer = DiffRenderOptimizer::new();
222 assert!(!optimizer.is_large_diff(500));
223 assert!(optimizer.is_large_diff(3000));
224 }
225
226 #[test]
227 fn test_theme_switch_performance_tracking() {
228 let mut perf = ThemeSwitchPerformance::default();
229 perf.record_switch(50);
230 perf.record_switch(75);
231
232 assert_eq!(perf.last_switch_time_ms, 75);
233 assert_eq!(perf.switch_count, 2);
234 assert!(perf.is_performant());
235 }
236
237 #[test]
238 fn test_theme_switch_performance_slow() {
239 let mut perf = ThemeSwitchPerformance::default();
240 perf.record_switch(150);
241
242 assert!(!perf.is_performant());
243 }
244}