or_panic/
lib.rs

1#![cfg_attr(feature = "no_std", no_std)]
2
3use core::fmt::{Debug, Display};
4
5/// The prelude: a collection of commonly-used types, traits, and functions.
6///
7/// Importing the prelude brings the most ergonomically important items
8/// into scope:
9///
10/// ```
11/// use or_panic::prelude::*;
12/// ```
13///
14/// This is purely for convenience—everything in the prelude is also
15/// available through their regular module paths.
16pub mod prelude {
17    pub use crate::{OptionOrPanic, ResultOrPanic};
18}
19
20pub trait OptionOrPanic<T> {
21    /// Unwrap the [`Option`] or panic with a message.
22    ///
23    /// Results:
24    /// `Some(T)` -> `T`
25    /// [`None`] -> [`panic`] with custom message
26    #[track_caller]
27    fn or_panic<M: Display>(self, msg: M) -> T;
28}
29
30impl<T> OptionOrPanic<T> for Option<T> {
31    #[track_caller]
32    fn or_panic<M: Display>(self, msg: M) -> T {
33        self.unwrap_or_else(|| panic!("{msg}"))
34    }
35}
36
37pub trait ResultOrPanic<T> {
38    /// Unwrap the [`Result`] or panic with a message.
39    ///
40    /// Results:
41    /// Ok(T) -> `T`
42    /// Err(E) -> [`panic`] with custom message
43    ///
44    /// NOTE: The error type of your [`Result`] must implement [`Debug`].
45    #[track_caller]
46    fn or_panic<M: Display>(self, msg: M) -> T;
47}
48
49impl<T, E: Debug> ResultOrPanic<T> for Result<T, E> {
50    #[track_caller]
51    fn or_panic<M: Display>(self, msg: M) -> T {
52        self.unwrap_or_else(|err| panic!("{msg}.\nCaused by: {err:?}"))
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn option_or_panic_returns_value() {
62        let x = Some(42).or_panic("should not panic");
63        assert_eq!(x, 42);
64    }
65
66    #[test]
67    #[should_panic(expected = "option is missing")]
68    fn option_or_panic_panics_on_none() {
69        let x: Option<i32> = None;
70        x.or_panic("option is missing");
71    }
72
73    #[test]
74    #[should_panic(expected = "error 123")]
75    fn option_or_panic_handles_display_types() {
76        let x: Option<i32> = None;
77        let code = 123;
78        x.or_panic(format!("error {code}"));
79    }
80
81    #[test]
82    fn result_or_panic_returns_ok_value() {
83        let r: Result<i32, &str> = Ok(7);
84        let x = r.or_panic("no panic expected");
85        assert_eq!(x, 7);
86    }
87
88    #[test]
89    #[should_panic(expected = "explicit failure.\nCaused by: \"boom\"")]
90    fn result_or_panic_panics_on_err() {
91        let r: Result<i32, &str> = Err("boom");
92        r.or_panic("explicit failure");
93    }
94
95    #[test]
96    #[should_panic(expected = "Bad stuff.\nCaused by: 404")]
97    fn result_or_panic_works_with_display_formatting() {
98        let r: Result<i32, i32> = Err(404);
99        r.or_panic("Bad stuff");
100    }
101
102    #[test]
103    fn result_or_panic_allows_non_string_message_types() {
104        let r: Result<&str, &str> = Ok("yay");
105        let msg_int = 999; // i32 implements Display
106
107        let v = r.or_panic(msg_int);
108        assert_eq!(v, "yay");
109    }
110}