1use crate::core::error::{MemScopeError, MemoryOperation, SystemErrorType};
8use crate::core::types::TrackingError;
9
10pub trait ErrorAdapter {
12 fn from_tracking_error(error: TrackingError) -> MemScopeError;
14
15 fn to_tracking_error(error: &MemScopeError) -> TrackingError;
17}
18
19pub struct DefaultErrorAdapter;
21
22impl ErrorAdapter for DefaultErrorAdapter {
23 fn from_tracking_error(error: TrackingError) -> MemScopeError {
24 match error {
25 TrackingError::DataError(msg) => MemScopeError::memory(MemoryOperation::Tracking, msg),
26 TrackingError::AllocationFailed(msg) => {
27 MemScopeError::memory(MemoryOperation::Allocation, msg)
28 }
29 TrackingError::DeallocationFailed(msg) => {
30 MemScopeError::memory(MemoryOperation::Deallocation, msg)
31 }
32 TrackingError::TrackingDisabled => {
33 MemScopeError::config("tracker", "Memory tracking is disabled")
34 }
35 TrackingError::InvalidPointer(msg) => {
36 MemScopeError::memory(MemoryOperation::Validation, msg)
37 }
38 TrackingError::SerializationError(msg) => {
39 MemScopeError::system(SystemErrorType::Serialization, msg)
40 }
41 TrackingError::VisualizationError(msg) => MemScopeError::export("visualization", msg),
42 TrackingError::ThreadSafetyError(msg) => MemScopeError::analysis("thread_safety", msg),
43 TrackingError::ConfigurationError(msg) => MemScopeError::config("general", msg),
44 TrackingError::AnalysisError(msg) => MemScopeError::analysis("general", msg),
45 TrackingError::ExportError(msg) => MemScopeError::export("general", msg),
46 TrackingError::MemoryCorruption(msg) => {
47 MemScopeError::memory(MemoryOperation::Validation, msg)
48 }
49 TrackingError::UnsafeOperationDetected(msg) => MemScopeError::analysis("unsafe", msg),
50 TrackingError::FFIError(msg) => MemScopeError::analysis("ffi", msg),
51 TrackingError::ScopeError(msg) => MemScopeError::memory(MemoryOperation::Tracking, msg),
52 TrackingError::BorrowCheckError(msg) => MemScopeError::analysis("borrow", msg),
53 TrackingError::LifetimeError(msg) => MemScopeError::analysis("lifetime", msg),
54 TrackingError::TypeInferenceError(msg) => MemScopeError::analysis("type", msg),
55 TrackingError::PerformanceError(msg) => MemScopeError::system(SystemErrorType::Io, msg),
56 TrackingError::ResourceExhausted(msg) => {
57 MemScopeError::system(SystemErrorType::Io, msg)
58 }
59 TrackingError::InternalError(msg) => MemScopeError::internal(msg),
60 TrackingError::IoError(msg) => MemScopeError::system(SystemErrorType::Io, msg),
61 TrackingError::LockError(msg) => MemScopeError::system(SystemErrorType::Locking, msg),
62 TrackingError::ChannelError(msg) => {
63 MemScopeError::system(SystemErrorType::Channel, msg)
64 }
65 TrackingError::ThreadError(msg) => {
66 MemScopeError::system(SystemErrorType::Threading, msg)
67 }
68 TrackingError::InitializationError(msg) => MemScopeError::config("initialization", msg),
69 TrackingError::NotImplemented(msg) => MemScopeError::internal(msg),
70 TrackingError::ValidationError(msg) => {
71 MemScopeError::memory(MemoryOperation::Validation, msg)
72 }
73 TrackingError::InvalidOperation(msg) => {
74 MemScopeError::memory(MemoryOperation::Tracking, msg)
75 }
76 TrackingError::LockContention(msg) => {
77 MemScopeError::memory(MemoryOperation::Tracking, msg)
78 }
79 }
80 }
81
82 fn to_tracking_error(error: &MemScopeError) -> TrackingError {
83 match error {
84 MemScopeError::Memory {
85 operation,
86 message,
87 context,
88 } => {
89 let full_message = if let Some(ctx) = context {
90 format!("{message} (context: {ctx})")
91 } else {
92 message.to_string()
93 };
94
95 match operation {
96 MemoryOperation::Allocation => TrackingError::AllocationFailed(full_message),
97 MemoryOperation::Deallocation => {
98 TrackingError::DeallocationFailed(full_message)
99 }
100 MemoryOperation::Association => TrackingError::InvalidOperation(full_message),
101 MemoryOperation::Tracking => TrackingError::ScopeError(full_message),
102 MemoryOperation::Validation => TrackingError::InvalidPointer(full_message),
103 }
104 }
105 MemScopeError::Analysis {
106 analyzer, message, ..
107 } => {
108 let full_message = format!("{analyzer}: {message}");
109 match analyzer.as_ref() {
110 "unsafe" => TrackingError::UnsafeOperationDetected(full_message),
111 "ffi" => TrackingError::FFIError(full_message),
112 "borrow" => TrackingError::BorrowCheckError(full_message),
113 "lifetime" => TrackingError::LifetimeError(full_message),
114 "type" => TrackingError::TypeInferenceError(full_message),
115 "thread_safety" => TrackingError::ThreadSafetyError(full_message),
116 _ => TrackingError::AnalysisError(full_message),
117 }
118 }
119 MemScopeError::Export {
120 format, message, ..
121 } => {
122 let full_message = format!("{format}: {message}");
123 match format.as_ref() {
124 "visualization" => TrackingError::VisualizationError(full_message),
125 _ => TrackingError::ExportError(full_message),
126 }
127 }
128 MemScopeError::Configuration { component, message } => {
129 let full_message = format!("{component}: {message}");
130 match component.as_ref() {
131 "tracker" => TrackingError::TrackingDisabled,
132 "initialization" => TrackingError::InitializationError(full_message),
133 _ => TrackingError::ConfigurationError(full_message),
134 }
135 }
136 MemScopeError::System {
137 error_type,
138 message,
139 ..
140 } => match error_type {
141 SystemErrorType::Io => TrackingError::IoError(message.to_string()),
142 SystemErrorType::Threading => TrackingError::ThreadSafetyError(message.to_string()),
143 SystemErrorType::Locking => TrackingError::LockError(message.to_string()),
144 SystemErrorType::Channel => TrackingError::ChannelError(message.to_string()),
145 SystemErrorType::Serialization => {
146 TrackingError::SerializationError(message.to_string())
147 }
148 SystemErrorType::Network => TrackingError::IoError(message.to_string()),
149 SystemErrorType::FileSystem => TrackingError::IoError(message.to_string()),
150 },
151 MemScopeError::Internal { message, .. } => {
152 TrackingError::InternalError(message.to_string())
153 }
154 }
155 }
156}
157
158pub fn from_tracking_error(error: TrackingError) -> MemScopeError {
160 DefaultErrorAdapter::from_tracking_error(error)
161}
162
163pub fn to_tracking_error(error: &MemScopeError) -> TrackingError {
164 DefaultErrorAdapter::to_tracking_error(error)
165}
166
167#[macro_export]
169macro_rules! convert_error {
170 ($error:expr) => {
171 $crate::core::error_adapter::from_tracking_error($error)
172 };
173}
174
175pub type AdaptedResult<T> = Result<T, MemScopeError>;
177
178pub fn adapt_result<T>(result: crate::core::types::TrackingResult<T>) -> AdaptedResult<T> {
180 result.map_err(from_tracking_error)
181}
182
183pub fn to_tracking_result<T>(result: AdaptedResult<T>) -> crate::core::types::TrackingResult<T> {
185 result.map_err(|e| to_tracking_error(&e))
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191 use crate::core::ErrorSeverity;
192
193 #[test]
194 fn test_allocation_error_conversion() {
195 let old_error = TrackingError::AllocationFailed("test allocation failed".to_string());
196 let new_error = DefaultErrorAdapter::from_tracking_error(old_error);
197
198 assert_eq!(new_error.category(), "memory");
199 assert!(new_error.user_message().contains("test allocation failed"));
200
201 let converted_back = DefaultErrorAdapter::to_tracking_error(&new_error);
202 assert!(matches!(converted_back, TrackingError::AllocationFailed(_)));
203 }
204
205 #[test]
206 fn test_analysis_error_conversion() {
207 let old_error = TrackingError::BorrowCheckError("borrow check failed".to_string());
208 let new_error = DefaultErrorAdapter::from_tracking_error(old_error);
209
210 assert_eq!(new_error.category(), "analysis");
211
212 let converted_back = DefaultErrorAdapter::to_tracking_error(&new_error);
213 assert!(matches!(converted_back, TrackingError::BorrowCheckError(_)));
214 }
215
216 #[test]
217 fn test_system_error_conversion() {
218 let old_error = TrackingError::IoError("IO operation failed".to_string());
219 let new_error = DefaultErrorAdapter::from_tracking_error(old_error);
220
221 assert_eq!(new_error.category(), "system");
222
223 let converted_back = DefaultErrorAdapter::to_tracking_error(&new_error);
224 assert!(matches!(converted_back, TrackingError::IoError(_)));
225 }
226
227 #[test]
228 fn test_result_adaptation() {
229 let old_result: crate::core::types::TrackingResult<i32> =
230 Err(TrackingError::AllocationFailed("test".to_string()));
231
232 let adapted_result = adapt_result(old_result);
233 assert!(adapted_result.is_err());
234
235 let converted_back = to_tracking_result(adapted_result);
236 assert!(matches!(
237 converted_back,
238 Err(TrackingError::AllocationFailed(_))
239 ));
240 }
241
242 #[test]
243 fn test_all_tracking_error_variants() {
244 let test_errors = vec![
246 TrackingError::AllocationFailed("allocation failed".to_string()),
247 TrackingError::DeallocationFailed("deallocation failed".to_string()),
248 TrackingError::BorrowCheckError("borrow check error".to_string()),
249 TrackingError::LifetimeError("lifetime error".to_string()),
250 TrackingError::ThreadSafetyError("thread safety error".to_string()),
251 TrackingError::InvalidPointer("invalid pointer".to_string()),
252 TrackingError::IoError("IO error".to_string()),
253 TrackingError::SerializationError("serialization error".to_string()),
254 TrackingError::ConfigurationError("configuration error".to_string()),
255 TrackingError::InternalError("internal error".to_string()),
256 ];
257
258 for original_error in test_errors {
259 let adapted_error = DefaultErrorAdapter::from_tracking_error(original_error.clone());
261
262 assert!(!adapted_error.category().is_empty());
264 assert!(!adapted_error.user_message().is_empty());
265 let converted_back = DefaultErrorAdapter::to_tracking_error(&adapted_error);
269
270 match (&original_error, &converted_back) {
272 (TrackingError::AllocationFailed(_), TrackingError::AllocationFailed(_)) => {}
273 (TrackingError::DeallocationFailed(_), TrackingError::DeallocationFailed(_)) => {}
274 (TrackingError::BorrowCheckError(_), TrackingError::BorrowCheckError(_)) => {}
275 (TrackingError::LifetimeError(_), TrackingError::LifetimeError(_)) => {}
276 (TrackingError::ThreadSafetyError(_), TrackingError::ThreadSafetyError(_)) => {}
277 (TrackingError::InvalidPointer(_), TrackingError::InvalidPointer(_)) => {}
278 (TrackingError::IoError(_), TrackingError::IoError(_)) => {}
279 (TrackingError::SerializationError(_), TrackingError::SerializationError(_)) => {}
280 (TrackingError::ConfigurationError(_), TrackingError::ConfigurationError(_)) => {}
281 (TrackingError::InternalError(_), TrackingError::InternalError(_)) => {}
282 _ => panic!(
283 "Error type mismatch: {:?} -> {:?}",
284 original_error, converted_back
285 ),
286 }
287 }
288 }
289
290 #[test]
291 fn test_error_categories() {
292 let memory_errors = vec![
294 TrackingError::AllocationFailed("test".to_string()),
295 TrackingError::DeallocationFailed("test".to_string()),
296 TrackingError::InvalidPointer("test".to_string()),
297 ];
298
299 for error in memory_errors {
300 let adapted = DefaultErrorAdapter::from_tracking_error(error);
301 assert_eq!(adapted.category(), "memory");
302 }
303
304 let analysis_errors = vec![
305 TrackingError::BorrowCheckError("test".to_string()),
306 TrackingError::LifetimeError("test".to_string()),
307 TrackingError::ThreadSafetyError("test".to_string()),
308 ];
309
310 for error in analysis_errors {
311 let adapted = DefaultErrorAdapter::from_tracking_error(error);
312 assert_eq!(adapted.category(), "analysis");
313 }
314
315 let system_errors = vec![
316 TrackingError::IoError("test".to_string()),
317 TrackingError::SerializationError("test".to_string()),
318 ];
319
320 let config_errors = vec![TrackingError::ConfigurationError("test".to_string())];
321
322 let internal_errors = vec![TrackingError::InternalError("test".to_string())];
323
324 for error in system_errors {
325 let adapted = DefaultErrorAdapter::from_tracking_error(error);
326 assert_eq!(adapted.category(), "system");
327 }
328
329 for error in config_errors {
330 let adapted = DefaultErrorAdapter::from_tracking_error(error);
331 assert_eq!(adapted.category(), "config");
332 }
333
334 for error in internal_errors {
335 let adapted = DefaultErrorAdapter::from_tracking_error(error);
336 assert_eq!(adapted.category(), "internal");
337 }
338 }
339
340 #[test]
341 fn test_successful_result_adaptation() {
342 let success_result: crate::core::types::TrackingResult<String> = Ok("success".to_string());
344 let adapted = adapt_result(success_result);
345 assert!(adapted.is_ok());
346 assert_eq!(adapted.unwrap(), "success");
347
348 let success_adapted: AdaptedResult<i32> = Ok(42);
350 let converted_back = to_tracking_result(success_adapted);
351 assert!(converted_back.is_ok());
352 assert_eq!(converted_back.unwrap(), 42);
353 }
354
355 #[test]
356 fn test_error_message_preservation() {
357 let test_cases = vec![
358 ("Simple error message", TrackingError::AllocationFailed("Simple error message".to_string())),
359 ("Error with special chars: !@#$%^&*()", TrackingError::IoError("Error with special chars: !@#$%^&*()".to_string())),
360 ("Unicode error: 错误信息 🦀", TrackingError::BorrowCheckError("Unicode error: 错误信息 🦀".to_string())),
361 ("", TrackingError::InternalError("".to_string())), ("Very long error message that spans multiple lines and contains lots of details about what went wrong in the system",
363 TrackingError::ConfigurationError("Very long error message that spans multiple lines and contains lots of details about what went wrong in the system".to_string())),
364 ];
365
366 for (expected_content, error) in test_cases {
367 let adapted = DefaultErrorAdapter::from_tracking_error(error);
368 assert!(adapted.user_message().contains(expected_content));
369 }
371 }
372
373 #[test]
374 fn test_error_adapter_trait_methods() {
375 let _adapter = DefaultErrorAdapter;
376
377 let allocation_error = TrackingError::AllocationFailed("allocation failed".to_string());
379 let adapted = DefaultErrorAdapter::from_tracking_error(allocation_error.clone());
380
381 assert!(!adapted.category().is_empty());
383 assert!(!adapted.user_message().is_empty());
384 assert!(!adapted.user_message().is_empty());
385 assert!(adapted.severity() <= ErrorSeverity::Critical); let converted = DefaultErrorAdapter::to_tracking_error(&adapted);
389 assert!(matches!(converted, TrackingError::AllocationFailed(_)));
390 }
391
392 #[test]
393 fn test_error_severity_levels() {
394 let critical_errors = vec![
396 TrackingError::InvalidPointer("test".to_string()),
397 TrackingError::AllocationFailed("test".to_string()),
398 ];
399
400 let warning_errors = vec![
401 TrackingError::BorrowCheckError("test".to_string()),
402 TrackingError::LifetimeError("test".to_string()),
403 ];
404
405 let info_errors = vec![TrackingError::ConfigurationError("test".to_string())];
406
407 for error in critical_errors {
409 let adapted = DefaultErrorAdapter::from_tracking_error(error);
410 assert_eq!(
411 adapted.severity(),
412 ErrorSeverity::Medium,
413 "Memory error should have medium severity"
414 );
415 }
416
417 for error in warning_errors {
419 let adapted = DefaultErrorAdapter::from_tracking_error(error);
420 assert_eq!(
421 adapted.severity(),
422 ErrorSeverity::Low,
423 "Analysis error should have low severity"
424 );
425 }
426
427 for error in info_errors {
429 let adapted = DefaultErrorAdapter::from_tracking_error(error);
430 assert!(
431 adapted.severity() <= ErrorSeverity::High,
432 "Info error should have reasonable severity"
433 );
434 }
435 }
436
437 #[test]
438 fn test_error_chain_preservation() {
439 let original_error = TrackingError::AllocationFailed("root cause".to_string());
441 let adapted = DefaultErrorAdapter::from_tracking_error(original_error);
442
443 assert!(adapted.user_message().contains("root cause"));
445 }
446
447 #[test]
448 fn test_concurrent_error_adaptation() {
449 use std::sync::Arc;
450 use std::thread;
451
452 let _adapter = Arc::new(DefaultErrorAdapter);
453 let mut handles = vec![];
454
455 for i in 0..10 {
457 let handle = thread::spawn(move || {
458 let error = TrackingError::AllocationFailed(format!("error_{}", i));
459 let adapted = DefaultErrorAdapter::from_tracking_error(error);
460 let converted_back = DefaultErrorAdapter::to_tracking_error(&adapted);
461
462 match converted_back {
463 TrackingError::AllocationFailed(msg) => {
464 assert!(msg.contains(&format!("error_{}", i)))
465 }
466 _ => panic!("Unexpected error type"),
467 }
468 });
469 handles.push(handle);
470 }
471
472 for handle in handles {
473 handle.join().expect("Thread should complete successfully");
474 }
475 }
476
477 #[test]
478 fn test_error_formatting() {
479 let error = TrackingError::AllocationFailed("test allocation".to_string());
480 let adapted = DefaultErrorAdapter::from_tracking_error(error);
481
482 let user_msg = adapted.user_message();
484 let category = adapted.category();
485
486 assert!(!user_msg.is_empty());
487 assert!(!category.is_empty());
488
489 let _formatted = format!("Error: {} ({})", user_msg, category);
491 }
492
493 #[test]
494 fn test_result_chain_operations() {
495 let success: crate::core::types::TrackingResult<i32> = Ok(10);
497 let adapted_success = adapt_result(success);
498
499 let mapped = adapted_success.map(|x| x * 2);
501 assert_eq!(mapped.unwrap(), 20);
502
503 let error_result: crate::core::types::TrackingResult<i32> =
505 Err(TrackingError::AllocationFailed("test".to_string()));
506 let adapted_error = adapt_result(error_result);
507
508 let mapped_error = adapted_error.map(|x| x * 2);
509 assert!(mapped_error.is_err());
510
511 let converted_back = to_tracking_result(mapped_error);
513 assert!(matches!(
514 converted_back,
515 Err(TrackingError::AllocationFailed(_))
516 ));
517 }
518}