1
use std::fmt::Display;
2

            
3
#[doc(hidden)]
4
pub const BUG_REPORT_VERSION: &str = git_version::git_version!();
5

            
6
/// Triggers a panic with a detailed bug report message, while ensuring the panic is ignored in coverage reports.
7
///
8
/// This macro is useful in situations where an unreachable code path is hit or when a bug occurs.
9
///
10
/// # Parameters
11
///
12
/// - `msg`: A string expression describing the cause of the panic or bug.
13
///
14
/// ```
15
#[macro_export]
16
macro_rules! bug {
17
    ($msg:expr)=> {
18
        $crate::bug!($msg,)
19
    };
20

            
21
    ($msg:expr, $($arg:tt)*) => {{
22
        let formatted_msg = format!($msg, $($arg)*);
23
        let full_message = format!(
24
            r#"
25
This should never happen, sorry!
26

            
27
However, it did happen, so it must be a bug. Please report it to us!
28

            
29
Conjure Oxide is actively developed and maintained. We will get back to you as soon as possible.
30

            
31
You can help us by providing a minimal failing example.
32

            
33
Issue tracker: http://github.com/conjure-cp/conjure-oxide/issues
34

            
35
version: {}
36
location: {}:{}:{}
37

            
38
{}
39
"#, $crate::bug::BUG_REPORT_VERSION,file!(),module_path!(),line!(), &formatted_msg);
40

            
41
        panic!("{}", full_message);
42
    }};
43
}
44

            
45
/// Like [assert!], but formats the error message using [bug!]
46
#[macro_export]
47
macro_rules! bug_assert {
48
    ($cond:expr, $msg:expr, $($arg:tt)*) => {
49
        if !$cond {
50
            let formatted_msg = format!($msg, $($arg)*);
51
            $crate::bug!("assertion failed: {}\n{}", stringify!($cond), formatted_msg);
52
        }
53
    };
54

            
55
    ($cond:expr, $msg:expr) => {
56
        if !$cond {
57
            $crate::bug!("assertion failed: {}\n{}", stringify!($cond), $msg);
58
        }
59
    };
60

            
61
    ($cond:expr) => {
62
        if !$cond {
63
            $crate::bug!("assertion failed: {}", stringify!($cond));
64
        }
65
    };
66
}
67

            
68
/// Like [assert_eq!], but formats the error message using [bug!]
69
#[macro_export]
70
macro_rules! bug_assert_eq {
71
    ($left:expr, $right:expr, $msg:expr, $($arg:tt)*) => {
72
        if &$left != &$right {
73
            let formatted_msg = format!($msg, $($arg)*);
74
            $crate::bug!(
75
                "assertion failed: {} != {}\n{}",
76
                stringify!($left),
77
                stringify!($right),
78
                formatted_msg
79
            );
80
        }
81
    };
82

            
83
    ($left:expr, $right:expr, $msg:expr) => {
84
        $crate::bug_assert_eq!($left, $right, $msg,);
85
    };
86

            
87
    ($left:expr, $right:expr) => {
88
        if &$left != &$right {
89
            $crate::bug!(
90
                "assertion failed: {} != {}",
91
                stringify!($left),
92
                stringify!($right)
93
            );
94
        }
95
    };
96
}
97

            
98
pub trait UnwrapOrBug {
99
    type Output;
100
    fn unwrap_or_bug(self) -> Self::Output;
101
}
102

            
103
impl<T, E: Display> UnwrapOrBug for Result<T, E> {
104
    type Output = T;
105
928829
    fn unwrap_or_bug(self) -> Self::Output {
106
        self.unwrap_or_else(|e| bug!("error: {}", e))
107
928829
    }
108
}
109

            
110
impl<T> UnwrapOrBug for Option<T> {
111
    type Output = T;
112
    fn unwrap_or_bug(self) -> Self::Output {
113
        self.unwrap_or_else(|| bug!("expected a value, but got None"))
114
    }
115
}