Skip to main content

conjure_cp_core/
bug.rs

1use std::fmt::Display;
2
3#[doc(hidden)]
4pub 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]
16macro_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#"
25This should never happen, sorry!
26
27However, it did happen, so it must be a bug. Please report it to us!
28
29Conjure Oxide is actively developed and maintained. We will get back to you as soon as possible.
30
31You can help us by providing a minimal failing example.
32
33Issue tracker: http://github.com/conjure-cp/conjure-oxide/issues
34
35version: {}
36location: {}:{}:{}
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]
47macro_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]
70macro_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
98pub trait UnwrapOrBug {
99    type Output;
100    fn unwrap_or_bug(self) -> Self::Output;
101}
102
103impl<T, E: Display> UnwrapOrBug for Result<T, E> {
104    type Output = T;
105    fn unwrap_or_bug(self) -> Self::Output {
106        self.unwrap_or_else(|e| bug!("error: {}", e))
107    }
108}
109
110impl<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}