1#![deny(clippy::all)]
6#![warn(clippy::pedantic)]
7#![warn(clippy::restriction)]
8#![warn(clippy::nursery)]
9#![warn(clippy::cargo)]
10#![allow(clippy::blanket_clippy_restriction_lints)]
11#![allow(clippy::implicit_return)]
12#![allow(clippy::panic)]
13#![allow(clippy::expect_used)]
14#![allow(clippy::arithmetic_side_effects)]
15#![allow(clippy::integer_arithmetic)]
16#![allow(clippy::pub_use)]
17#![cfg_attr(not(feature = "std"), no_std)]
18
19use core::{fmt::Debug, option::Option, result::Result};
20
21include!(concat!(env!("OUT_DIR"), "/assets.rs"));
23
24pub trait ExpectoPatronumExt: sealed::Sealed {
26 type Success;
28
29 fn expecto_patronum(self, msg: &str) -> Self::Success;
38}
39
40impl<T, E: Debug> ExpectoPatronumExt for Result<T, E> {
41 type Success = T;
42
43 #[inline]
44 fn expecto_patronum(self, msg: &str) -> Self::Success {
45 self.unwrap_or_else(|error| {
46 let patronus = choose_patronus(msg);
47 let panic_msg = construct_panic_msg(patronus, msg);
48 panic!("{panic_msg}: {error:?}")
49 })
50 }
51}
52
53impl<T> ExpectoPatronumExt for Option<T> {
54 type Success = T;
55
56 #[inline]
57 fn expecto_patronum(self, msg: &str) -> Self::Success {
58 self.unwrap_or_else(|| {
59 let patronus = choose_patronus(msg);
60 let panic_msg = construct_panic_msg(patronus, msg);
61 panic!("{panic_msg}")
62 })
63 }
64}
65
66mod sealed {
67 pub trait Sealed {}
71
72 impl<T, E: super::Debug> Sealed for super::Result<T, E> {}
73
74 impl<T> Sealed for super::Option<T> {}
75}
76
77type Patronus = &'static str;
79
80#[allow(clippy::indexing_slicing)]
82fn choose_patronus(msg: &str) -> Patronus {
83 let n: u128 = fastmurmur3::hash(msg.as_bytes())
86 % u128::try_from(ASSETS.len()).expect("`usize` should fit in `u128`");
87
88 ASSETS[usize::try_from(n).expect("Calculated index should fit in `usize`")]
89}
90
91fn construct_panic_msg(patronus: Patronus, base_msg: &str) -> String {
93 let mut new_msg = String::with_capacity(patronus.len() + base_msg.len() + 1);
96 new_msg.push('\n');
97 new_msg.push_str(patronus);
98 new_msg.push_str(base_msg);
99 new_msg
100}
101
102pub mod prelude {
103 pub use super::ExpectoPatronumExt as _;
106}