1use crate::core::error::{MemScopeError, MemoryOperation, SystemErrorType};
7use crate::core::safe_operations::SafeLock;
8use std::backtrace::Backtrace;
9use std::error::Error as StdError;
10use std::fmt::{self, Debug, Display};
11
12#[derive(Debug)]
14pub enum UnwrapError {
15 NoneValue {
16 context: &'static str,
17 location: Option<&'static str>,
18 backtrace: Backtrace,
19 },
20 ResultError {
21 source: Box<dyn StdError + Send + Sync>,
22 context: &'static str,
23 location: Option<&'static str>,
24 backtrace: Backtrace,
25 },
26}
27
28impl Display for UnwrapError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self {
31 Self::NoneValue {
32 context, location, ..
33 } => {
34 if let Some(loc) = location {
35 write!(f, "Attempt to unwrap None at {loc} ({context})")
36 } else {
37 write!(f, "Attempt to unwrap None ({context})")
38 }
39 }
40 Self::ResultError {
41 source,
42 context,
43 location,
44 ..
45 } => {
46 if let Some(loc) = location {
47 write!(f, "Unwrap failed at {loc} ({context}): {source}")
48 } else {
49 write!(f, "Unwrap failed ({context}): {source}")
50 }
51 }
52 }
53 }
54}
55
56impl StdError for UnwrapError {
57 fn source(&self) -> Option<&(dyn StdError + 'static)> {
58 match self {
59 Self::NoneValue { .. } => None,
60 Self::ResultError { source, .. } => Some(&**source),
61 }
62 }
63}
64
65impl UnwrapError {
66 pub fn backtrace(&self) -> &Backtrace {
68 match self {
69 Self::NoneValue { backtrace, .. } | Self::ResultError { backtrace, .. } => backtrace,
70 }
71 }
72}
73
74pub trait UnwrapSafe<T> {
76 fn try_unwrap(self, context: &'static str) -> Result<T, UnwrapError>;
78
79 fn try_unwrap_at(self, context: &'static str, location: &'static str) -> Result<T, UnwrapError>
81 where
82 Self: Sized,
83 {
84 self.try_unwrap(context).map_err(|mut e| {
85 match &mut e {
86 UnwrapError::NoneValue { location: loc, .. }
87 | UnwrapError::ResultError { location: loc, .. } => {
88 *loc = Some(location);
89 }
90 }
91 e
92 })
93 }
94
95 fn unwrap_or_default_safe(self, default: T, context: &'static str) -> T
97 where
98 Self: Sized,
99 {
100 self.try_unwrap(context).unwrap_or_else(|e| {
101 tracing::warn!("{}", e);
102 default
103 })
104 }
105
106 fn unwrap_or_else_safe<F>(self, default_fn: F, context: &'static str) -> T
108 where
109 Self: Sized,
110 F: FnOnce() -> T,
111 {
112 self.try_unwrap(context).unwrap_or_else(|e| {
113 tracing::warn!("{}", e);
114 default_fn()
115 })
116 }
117
118 #[deprecated(note = "Use try_unwrap() instead")]
120 fn try_unwrap_safe(self, context: &'static str) -> Result<T, MemScopeError>
121 where
122 Self: Sized,
123 {
124 self.try_unwrap(context).map_err(|e| {
125 MemScopeError::memory(
126 MemoryOperation::Allocation,
127 format!("Failed to unwrap value: {e}"),
128 )
129 })
130 }
131
132 #[deprecated(note = "Use try_unwrap() instead")]
139 fn unwrap_safe(self, context: &'static str) -> T
140 where
141 Self: Sized,
142 {
143 self.try_unwrap(context).unwrap_or_else(|e| {
144 tracing::error!("Fatal error: {}\nBacktrace:\n{:?}", e, e.backtrace());
145 std::process::abort();
146 })
147 }
148
149 #[deprecated(note = "Use try_unwrap_at() instead")]
156 fn unwrap_safe_at(self, context: &'static str, location: &'static str) -> T
157 where
158 Self: Sized,
159 {
160 self.try_unwrap_at(context, location).unwrap_or_else(|e| {
161 let backtrace = e.backtrace();
162 tracing::error!(
163 "Fatal error at {}: {}\nBacktrace:\n{:?}",
164 location,
165 e,
166 backtrace
167 );
168 std::process::abort();
169 })
170 }
171}
172
173impl<T> UnwrapSafe<T> for Option<T> {
174 fn try_unwrap(self, context: &'static str) -> Result<T, UnwrapError> {
175 match self {
176 Some(value) => {
177 tracing::trace!("Unwrap succeeded: {}", context);
178 Ok(value)
179 }
180 None => {
181 let error = UnwrapError::NoneValue {
182 context,
183 location: None,
184 backtrace: Backtrace::capture(),
185 };
186 tracing::error!("Unwrap failed: {}", error);
187 Err(error)
188 }
189 }
190 }
191
192 fn unwrap_or_else_safe<F>(self, default_fn: F, context: &'static str) -> T
193 where
194 F: FnOnce() -> T,
195 {
196 self.try_unwrap(context).unwrap_or_else(|e| {
197 tracing::warn!("Using default value: {}", e);
198 default_fn()
199 })
200 }
201
202 fn try_unwrap_safe(self, context: &'static str) -> Result<T, MemScopeError> {
203 self.try_unwrap(context).map_err(|e| {
204 MemScopeError::memory(
205 MemoryOperation::Allocation,
206 format!("Failed to unwrap value: {e:?}"),
207 )
208 })
209 }
210}
211
212impl<T, E: StdError + Send + Sync + 'static> UnwrapSafe<T> for Result<T, E> {
213 fn try_unwrap(self, context: &'static str) -> Result<T, UnwrapError> {
214 match self {
215 Ok(value) => {
216 tracing::trace!("Result unwrap succeeded: {}", context);
217 Ok(value)
218 }
219 Err(error) => {
220 let error = UnwrapError::ResultError {
221 source: Box::new(error),
222 context,
223 location: None,
224 backtrace: Backtrace::capture(),
225 };
226 tracing::error!("Result unwrap failed: {error:?}");
227 Err(error)
228 }
229 }
230 }
231
232 fn try_unwrap_at(
233 self,
234 context: &'static str,
235 location: &'static str,
236 ) -> Result<T, UnwrapError> {
237 self.try_unwrap(context).map_err(|mut e| {
238 if let UnwrapError::ResultError { location: loc, .. } = &mut e {
239 *loc = Some(location);
240 }
241 e
242 })
243 }
244
245 fn unwrap_or_default_safe(self, default: T, context: &str) -> T {
246 match self {
247 Ok(value) => {
248 tracing::trace!("Safe unwrap succeeded: {}", context);
249 value
250 }
251 Err(error) => {
252 tracing::warn!("Safe unwrap failed (Error: {error:?}), using default: {context}",);
253 default
254 }
255 }
256 }
257
258 fn unwrap_or_else_safe<F>(self, default_fn: F, context: &str) -> T
259 where
260 F: FnOnce() -> T,
261 {
262 match self {
263 Ok(value) => {
264 tracing::trace!("Safe unwrap succeeded: {}", context);
265 value
266 }
267 Err(error) => {
268 tracing::warn!(
269 "Safe unwrap failed (Error: {error:?}), using default function: {context}",
270 );
271 default_fn()
272 }
273 }
274 }
275
276 fn try_unwrap_safe(self, context: &str) -> Result<T, MemScopeError> {
277 match self {
278 Ok(value) => {
279 tracing::trace!("Safe unwrap succeeded: {context}");
280 Ok(value)
281 }
282 Err(error) => {
283 tracing::error!("Safe unwrap failed (Error: {error:?}): {context}");
284 Err(MemScopeError::system(
285 SystemErrorType::Io,
286 format!("Result unwrap failed in context: {context} - error: {error:?}",),
287 ))
288 }
289 }
290 }
291}
292
293#[macro_export]
295macro_rules! unwrap_safe {
296 ($expr:expr) => {
297 $expr.unwrap_safe(&format!("{}:{}", file!(), line!()))
298 };
299 ($expr:expr, $context:expr) => {
300 $expr.unwrap_safe($context)
301 };
302}
303
304#[macro_export]
306macro_rules! unwrap_safe_at {
307 ($expr:expr, $context:expr) => {
308 $expr.unwrap_safe_at($context, &format!("{}:{}", file!(), line!()))
309 };
310}
311
312#[macro_export]
314macro_rules! unwrap_or_default_safe {
315 ($expr:expr, $default:expr) => {
316 $expr.unwrap_or_default_safe($default, &format!("{}:{}", file!(), line!()))
317 };
318 ($expr:expr, $default:expr, $context:expr) => {
319 $expr.unwrap_or_default_safe($default, $context)
320 };
321}
322
323#[macro_export]
325macro_rules! unwrap_or_else_safe {
326 ($expr:expr, $default_fn:expr) => {
327 $expr.unwrap_or_else_safe($default_fn, &format!("{}:{}", file!(), line!()))
328 };
329 ($expr:expr, $default_fn:expr, $context:expr) => {
330 $expr.unwrap_or_else_safe($default_fn, $context)
331 };
332}
333
334#[macro_export]
336macro_rules! try_unwrap_safe {
337 ($expr:expr) => {
338 $expr.try_unwrap_safe(&format!("{}:{}", file!(), line!()))
339 };
340 ($expr:expr, $context:expr) => {
341 $expr.try_unwrap_safe($context)
342 };
343}
344
345#[derive(Debug, Clone, Default)]
347pub struct UnwrapStats {
348 pub successful_unwraps: u64,
349 pub failed_unwraps: u64,
350 pub default_value_uses: u64,
351 pub panic_preservations: u64,
352}
353
354impl UnwrapStats {
355 pub fn new() -> Self {
356 Self::default()
357 }
358
359 pub fn record_success(&mut self) {
360 self.successful_unwraps += 1;
361 }
362
363 pub fn record_failure(&mut self) {
364 self.failed_unwraps += 1;
365 }
366
367 pub fn record_default_use(&mut self) {
368 self.default_value_uses += 1;
369 }
370
371 pub fn record_panic_preservation(&mut self) {
372 self.panic_preservations += 1;
373 }
374
375 pub fn total_operations(&self) -> u64 {
376 self.successful_unwraps
377 + self.failed_unwraps
378 + self.default_value_uses
379 + self.panic_preservations
380 }
381
382 pub fn success_rate(&self) -> f64 {
383 let total = self.total_operations();
384 if total == 0 {
385 0.0
386 } else {
387 self.successful_unwraps as f64 / total as f64
388 }
389 }
390}
391
392use std::sync::{Mutex, OnceLock};
393
394static GLOBAL_UNWRAP_STATS: OnceLock<Mutex<UnwrapStats>> = OnceLock::new();
396
397pub fn get_unwrap_stats() -> UnwrapStats {
399 let stats_mutex = GLOBAL_UNWRAP_STATS.get_or_init(|| Mutex::new(UnwrapStats::new()));
400 match stats_mutex.safe_lock() {
401 Ok(stats) => stats.clone(),
402 Err(_) => UnwrapStats::new(),
403 }
404}
405
406pub fn update_unwrap_stats<F, R>(f: F) -> R
408where
409 F: FnOnce(&mut UnwrapStats) -> R,
410 R: Default,
411{
412 let stats_mutex = GLOBAL_UNWRAP_STATS.get_or_init(|| Mutex::new(UnwrapStats::new()));
413 match stats_mutex.try_lock() {
414 Ok(mut stats) => f(&mut stats),
415 Err(_) => R::default(),
416 }
417}
418
419#[cfg(test)]
421pub fn get_unwrap_stats_mut() -> Option<std::sync::MutexGuard<'static, UnwrapStats>> {
422 let stats_mutex = GLOBAL_UNWRAP_STATS.get_or_init(|| Mutex::new(UnwrapStats::new()));
423 stats_mutex.try_lock().ok()
424}
425
426#[cfg(test)]
427mod tests {
428 use super::*;
429
430 #[test]
431 fn test_unwrap_error_display() {
432 let none_error = UnwrapError::NoneValue {
433 context: "test context",
434 location: Some("test.rs:42"),
435 backtrace: Backtrace::capture(),
436 };
437
438 let display_str = format!("{none_error:?}");
439 assert!(display_str.contains("test context"));
440 assert!(display_str.contains("test.rs:42"));
441
442 let none_error_no_location = UnwrapError::NoneValue {
443 context: "test context",
444 location: None,
445 backtrace: Backtrace::capture(),
446 };
447
448 let display_str = format!("{none_error_no_location:?}");
449 assert!(display_str.contains("test context"));
450 assert!(!display_str.contains("test.rs:42"));
451 }
452
453 #[test]
454 fn test_unwrap_error_result_display() {
455 let source_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
456 let result_error = UnwrapError::ResultError {
457 source: Box::new(source_error),
458 context: "file operation",
459 location: Some("main.rs:10"),
460 backtrace: Backtrace::capture(),
461 };
462
463 let display_str = format!("{result_error}");
464 assert!(display_str.contains("file operation"));
465 assert!(display_str.contains("main.rs:10"));
466 assert!(display_str.contains("file not found"));
467 }
468
469 #[test]
470 fn test_option_try_unwrap_success() {
471 let option = Some(42);
472 let result = option.try_unwrap("test success");
473 assert!(result.is_ok());
474 assert_eq!(result.unwrap(), 42);
475 }
476
477 #[test]
478 fn test_option_try_unwrap_failure() {
479 let option: Option<i32> = None;
480 let result = option.try_unwrap("test failure");
481 assert!(result.is_err());
482
483 if let Err(UnwrapError::NoneValue { context, .. }) = result {
484 assert_eq!(context, "test failure");
485 } else {
486 panic!("Expected NoneValue error");
487 }
488 }
489
490 #[test]
491 fn test_option_try_unwrap_at() {
492 let option: Option<i32> = None;
493 let result = option.try_unwrap_at("test context", "test.rs:100");
494 assert!(result.is_err());
495
496 if let Err(UnwrapError::NoneValue {
497 context, location, ..
498 }) = result
499 {
500 assert_eq!(context, "test context");
501 assert_eq!(location, Some("test.rs:100"));
502 } else {
503 panic!("Expected NoneValue error with location");
504 }
505 }
506
507 #[test]
508 fn test_option_unwrap_or_default_safe() {
509 let some_option = Some(42);
510 let result = some_option.unwrap_or_default_safe(99, "test default");
511 assert_eq!(result, 42);
512
513 let none_option: Option<i32> = None;
514 let result = none_option.unwrap_or_default_safe(99, "test default");
515 assert_eq!(result, 99);
516 }
517
518 #[test]
519 fn test_option_unwrap_or_else_safe() {
520 let some_option = Some(42);
521 let result = some_option.unwrap_or_else_safe(|| 99, "test else");
522 assert_eq!(result, 42);
523
524 let none_option: Option<i32> = None;
525 let result = none_option.unwrap_or_else_safe(|| 99, "test else");
526 assert_eq!(result, 99);
527 }
528
529 #[test]
530 fn test_result_try_unwrap_success() {
531 let result: Result<i32, std::io::Error> = Ok(42);
532 let unwrap_result = result.try_unwrap("test success");
533 assert!(unwrap_result.is_ok());
534 assert_eq!(unwrap_result.unwrap(), 42);
535 }
536
537 #[test]
538 fn test_result_try_unwrap_failure() {
539 let result: Result<i32, std::io::Error> = Err(std::io::Error::other("test error"));
540 let unwrap_result = result.try_unwrap("test failure");
541 assert!(unwrap_result.is_err());
542
543 if let Err(UnwrapError::ResultError { context, .. }) = unwrap_result {
544 assert_eq!(context, "test failure");
545 } else {
546 panic!("Expected ResultError");
547 }
548 }
549
550 #[test]
551 fn test_result_try_unwrap_at() {
552 let result: Result<i32, std::io::Error> = Err(std::io::Error::other("test error"));
553 let unwrap_result = result.try_unwrap_at("test context", "main.rs:50");
554 assert!(unwrap_result.is_err());
555
556 if let Err(UnwrapError::ResultError {
557 context, location, ..
558 }) = unwrap_result
559 {
560 assert_eq!(context, "test context");
561 assert_eq!(location, Some("main.rs:50"));
562 } else {
563 panic!("Expected ResultError with location");
564 }
565 }
566
567 #[test]
568 fn test_result_unwrap_or_default_safe() {
569 let ok_result: Result<i32, std::io::Error> = Ok(42);
570 let result = ok_result.unwrap_or_default_safe(99, "test default");
571 assert_eq!(result, 42);
572
573 let err_result: Result<i32, std::io::Error> = Err(std::io::Error::other("error"));
574 let result = err_result.unwrap_or_default_safe(99, "test default");
575 assert_eq!(result, 99);
576 }
577
578 #[test]
579 fn test_result_unwrap_or_else_safe() {
580 let ok_result: Result<i32, std::io::Error> = Ok(42);
581 let result = ok_result.unwrap_or_else_safe(|| 99, "test else");
582 assert_eq!(result, 42);
583
584 let err_result: Result<i32, std::io::Error> = Err(std::io::Error::other("error"));
585 let result = err_result.unwrap_or_else_safe(|| 99, "test else");
586 assert_eq!(result, 99);
587 }
588
589 #[test]
590 fn test_unwrap_stats_creation() {
591 let stats = UnwrapStats::new();
592 assert_eq!(stats.successful_unwraps, 0);
593 assert_eq!(stats.failed_unwraps, 0);
594 assert_eq!(stats.default_value_uses, 0);
595 assert_eq!(stats.panic_preservations, 0);
596 }
597
598 #[test]
599 fn test_unwrap_stats_record_operations() {
600 let mut stats = UnwrapStats::new();
601
602 stats.record_success();
603 stats.record_failure();
604 stats.record_default_use();
605 stats.record_panic_preservation();
606
607 assert_eq!(stats.successful_unwraps, 1);
608 assert_eq!(stats.failed_unwraps, 1);
609 assert_eq!(stats.default_value_uses, 1);
610 assert_eq!(stats.panic_preservations, 1);
611 }
612
613 #[test]
614 fn test_unwrap_stats_total_operations() {
615 let mut stats = UnwrapStats::new();
616
617 stats.record_success();
618 stats.record_success();
619 stats.record_failure();
620 stats.record_default_use();
621
622 assert_eq!(stats.total_operations(), 4);
623 }
624
625 #[test]
626 fn test_unwrap_stats_success_rate() {
627 let mut stats = UnwrapStats::new();
628
629 assert_eq!(stats.success_rate(), 0.0);
631
632 stats.record_success();
634 stats.record_success();
635 stats.record_success();
636 stats.record_failure();
637
638 let expected_rate = 3.0 / 4.0;
639 assert!((stats.success_rate() - expected_rate).abs() < f64::EPSILON);
640 }
641
642 #[test]
643 fn test_update_unwrap_stats() {
644 let result = update_unwrap_stats(|stats| {
645 stats.record_success();
646 42
647 });
648 assert_eq!(result, 42);
649 }
650
651 #[test]
652 fn test_unwrap_error_backtrace() {
653 let error = UnwrapError::NoneValue {
654 context: "test",
655 location: None,
656 backtrace: Backtrace::capture(),
657 };
658
659 let _backtrace = error.backtrace();
660 }
662
663 #[test]
664 fn test_unwrap_error_source() {
665 let none_error = UnwrapError::NoneValue {
666 context: "test",
667 location: None,
668 backtrace: Backtrace::capture(),
669 };
670 assert!(none_error.source().is_none());
671
672 let source_error = std::io::Error::new(std::io::ErrorKind::NotFound, "test");
673 let result_error = UnwrapError::ResultError {
674 source: Box::new(source_error),
675 context: "test",
676 location: None,
677 backtrace: Backtrace::capture(),
678 };
679 assert!(result_error.source().is_some());
680 }
681
682 #[test]
683 fn test_option_try_unwrap_safe_deprecated() {
684 #[allow(deprecated)]
685 {
686 let some_option = Some(42);
687 let result = some_option.try_unwrap_safe("test");
688 assert!(result.is_ok());
689 assert_eq!(result.unwrap(), 42);
690
691 let none_option: Option<i32> = None;
692 let result = none_option.try_unwrap_safe("test");
693 assert!(result.is_err());
694 }
695 }
696
697 #[test]
698 fn test_result_try_unwrap_safe_deprecated() {
699 #[allow(deprecated)]
700 {
701 let ok_result: Result<i32, std::io::Error> = Ok(42);
702 let result = ok_result.try_unwrap_safe("test");
703 assert!(result.is_ok());
704 assert_eq!(result.unwrap(), 42);
705
706 let err_result: Result<i32, std::io::Error> = Err(std::io::Error::other("error"));
707 let result = err_result.try_unwrap_safe("test");
708 assert!(result.is_err());
709 }
710 }
711
712 #[test]
713 fn test_unwrap_stats_default() {
714 let stats = UnwrapStats::default();
715 assert_eq!(stats.successful_unwraps, 0);
716 assert_eq!(stats.failed_unwraps, 0);
717 assert_eq!(stats.default_value_uses, 0);
718 assert_eq!(stats.panic_preservations, 0);
719 }
720}