1#![no_std]
2
3#[cfg(feature = "std")]
70extern crate std;
71
72#[cfg(feature = "std")]
73use std::io::Write;
74
75#[macro_export]
78#[cfg(not(debug_assertions))]
79macro_rules! safe_unwrap {
80 ($reason:expr, $e:expr) => ($e.unwrap())
81}
82
83#[macro_export]
84#[cfg(debug_assertions)]
85macro_rules! safe_unwrap {
86 ($reason:expr, $e:expr) => (
87 $e.expect(concat!("[BUG] violated: ",
88 $reason))
89 )
90}
91
92pub trait SafeUnwrap<T> {
93 fn safe_unwrap(self, msg: &str) -> T;
94 #[cfg(feature = "std")]
95 fn unwrap_or_abort(self, msg: &str) -> T;
96 #[cfg(feature = "std")]
97 fn unwrap_or_exit(self, msg: &str) -> T;
98}
99
100#[cfg(not(debug_assertions))]
101impl<T, E: core::fmt::Debug> SafeUnwrap<T> for Result<T, E> {
102 #[inline]
103 fn safe_unwrap(self, _: &str) -> T {
104 self.unwrap()
105 }
106
107 #[cfg(feature = "std")]
108 #[inline]
109 fn unwrap_or_abort(self, _: &str) -> T {
110 self.unwrap_or_else(|_| std::process::abort())
111 }
112
113 #[cfg(feature = "std")]
114 #[inline]
115 fn unwrap_or_exit(self, _: &str) -> T {
116 self.unwrap_or_else(|_| std::process::exit(1))
117 }
118}
119
120#[cfg(not(debug_assertions))]
121impl<T> SafeUnwrap<T> for Option<T> {
122 #[inline]
123 fn safe_unwrap(self, _: &str) -> T {
124 self.unwrap()
125 }
126
127 #[cfg(feature = "std")]
128 #[inline]
129 fn unwrap_or_abort(self, _: &str) -> T {
130 self.unwrap_or_else(|| std::process::abort())
131 }
132
133 #[cfg(feature = "std")]
134 #[inline]
135 fn unwrap_or_exit(self, _: &str) -> T {
136 self.unwrap_or_else(|| std::process::exit(1))
137 }
138}
139
140#[cfg(debug_assertions)]
141impl<T, E: core::fmt::Debug> SafeUnwrap<T> for Result<T, E> {
142 #[inline]
143 fn safe_unwrap(self, msg: &str) -> T {
144 self.expect(msg)
145 }
146
147 #[cfg(feature = "std")]
148 #[inline]
149 fn unwrap_or_abort(self, msg: &str) -> T {
150 self.unwrap_or_else(|_| {
151 let _ = writeln!(std::io::stderr(), "{}", msg);
152 std::process::abort()
153 })
154 }
155
156 #[cfg(feature = "std")]
157 #[inline]
158 fn unwrap_or_exit(self, msg: &str) -> T {
159 self.unwrap_or_else(|_| {
160 let _ = writeln!(std::io::stderr(), "{}", msg);
161 std::process::exit(1)
162 })
163 }
164}
165
166#[cfg(debug_assertions)]
167impl<T> SafeUnwrap<T> for Option<T> {
168 #[inline]
169 fn safe_unwrap(self, msg: &str) -> T {
170 self.expect(msg)
171 }
172
173 #[cfg(feature = "std")]
174 #[inline]
175 fn unwrap_or_abort(self, msg: &str) -> T {
176 self.unwrap_or_else(|| {
177 let _ = writeln!(std::io::stderr(), "{}", msg);
178 std::process::abort()
179 })
180 }
181
182 #[cfg(feature = "std")]
183 #[inline]
184 fn unwrap_or_exit(self, msg: &str) -> T {
185 self.unwrap_or_else(|| {
186 let _ = writeln!(std::io::stderr(), "{}", msg);
187 std::process::exit(1)
188 })
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::SafeUnwrap;
195
196 #[test]
197 fn works_when_ok() {
198 let x = safe_unwrap!("this comment is meaningless", Some(42));
199 assert_eq!(x, 42);
200 }
201
202 #[test]
203 #[should_panic]
204 fn doesnt_work_when_err() {
205 let _: Option<()> = safe_unwrap!("should fail", None);
206 }
207
208 #[test]
209 fn trait_works_when_ok() {
210 let x = Some(42).safe_unwrap("meaningless comment");
211 assert_eq!(x, 42);
212
213 let r: Result<usize, ()> = Ok(42);
214 let y = r.safe_unwrap("meaningless comment");
215 assert_eq!(y, 42);
216 }
217
218 #[test]
219 #[should_panic]
220 fn trait_doesnt_work_when_err() {
221 let _: Option<()> = None.safe_unwrap("should fail");
222 let _: Result<(), ()> = Err(()).safe_unwrap("should fail");
223 }
224
225}