1pub(crate) const FAILURE_MESSAGE: &str = "failed to allocate";
2
3pub trait Strategy {
12 type Result<T, E>;
14
15 const UNIT: Self;
19
20 fn create<T, E>(value: Result<T, E>) -> Self::Result<T, E>;
25
26 fn map<T, E, U, F>(value: Self::Result<T, E>, f: F) -> Self::Result<U, E>
28 where
29 F: FnOnce(T) -> U;
30
31 fn map_err<T, E, V, F>(value: Self::Result<T, E>, f: F) -> Self::Result<T, V>
33 where
34 F: FnOnce(E) -> V;
35
36 fn and_then<T, E, U, F>(value: Self::Result<T, E>, f: F) -> Self::Result<U, E>
39 where
40 F: FnOnce(T) -> Self::Result<U, E>;
41
42 fn ok<T, E>(value: T) -> Self::Result<T, E> {
44 Self::create(Ok(value))
45 }
46
47 fn err<T, E>(error: E) -> Self::Result<T, E> {
49 Self::create(Err(error))
50 }
51
52 fn inspect<T, E, F>(value: Self::Result<T, E>, f: F) -> Self::Result<T, E>
54 where
55 F: FnOnce(&T),
56 {
57 Self::and_then(value, |value| {
58 f(&value);
59 Self::ok(value)
60 })
61 }
62}
63
64#[macro_export]
101macro_rules! strategy {
102 (
103 $(#[$attr:meta])*
104 $vis:vis struct $name:ident
105 $( ($($tuple_fields:tt)*) = $tuple_unit:expr; )?
106 $( {$($struct_fields:tt)*} = $struct_unit:expr; )?
107 $(;)?
108
109 type Result<$t:ident, $e:ident> = $output:ty;
110
111 Ok($ok_val:pat) => $ok:expr;
112 Err($err_val:pat) => $err:expr;
113
114 fn map($map_val:pat, $map_f:pat) => $map:expr;
115 fn map_err($map_err_val:pat, $map_err_f:pat) => $map_err:expr;
116 fn and_then($and_then_val:pat, $and_then_f:pat) => $and_then:expr;
117 ) => {
118 $(#[$attr])*
119 $vis struct $name
120 $( ($($tuple_fields)*) )?
121 $( {$($struct_fields)*} const _: () = () )?
125 ;
126
127 impl $crate::Strategy for $name {
128 type Result<$t, $e> = $output;
129
130 const UNIT: Self = $crate::__if_else!([
131 $($tuple_unit)?
132 ] || [
133 $($struct_unit)?
134 ] else [
135 Self
136 ] else "must either be a tuple struct or regular struct, not both"
137 );
138
139 fn create<$t, $e>(
140 __strategy_impl_value: ::core::result::Result<$t, $e>
141 ) -> <Self as $crate::Strategy>::Result<$t, $e> {
142 match __strategy_impl_value {
143 ::core::result::Result::Ok($ok_val) => $ok,
144 ::core::result::Result::Err($err_val) => $err,
145 }
146 }
147
148 #[allow(non_camel_case_types)]
149 fn map<$t, $e, __STRATEGY_IMPL_U, __STRATEGY_IMPL_F>(
150 $map_val: <Self as $crate::Strategy>::Result<$t, $e>,
151 $map_f: __STRATEGY_IMPL_F,
152 ) -> <Self as $crate::Strategy>::Result<__STRATEGY_IMPL_U, $e>
153 where
154 __STRATEGY_IMPL_F: ::core::ops::FnOnce($t) -> __STRATEGY_IMPL_U,
155 {
156 $map
157 }
158
159 #[allow(non_camel_case_types)]
160 fn map_err<$t, $e, __STRATEGY_IMPL_V, __STRATEGY_IMPL_F>(
161 $map_err_val: <Self as $crate::Strategy>::Result<$t, $e>,
162 $map_err_f: __STRATEGY_IMPL_F,
163 ) -> <Self as $crate::Strategy>::Result<$t, __STRATEGY_IMPL_V>
164 where
165 __STRATEGY_IMPL_F: core::ops::FnOnce($e) -> __STRATEGY_IMPL_V,
166 {
167 $map_err
168 }
169
170 #[allow(non_camel_case_types)]
171 fn and_then<$t, $e, __STRATEGY_IMPL_U, __STRATEGY_IMPL_F>(
172 $and_then_val: <Self as $crate::Strategy>::Result<$t, $e>,
173 $and_then_f: __STRATEGY_IMPL_F,
174 ) -> <Self as $crate::Strategy>::Result<__STRATEGY_IMPL_U, $e>
175 where
176 __STRATEGY_IMPL_F: core::ops::FnOnce(T)
177 -> <Self as $crate::Strategy>::Result<__STRATEGY_IMPL_U, $e>,
178 {
179 $and_then
180 }
181 }
182 }
183}
184
185fn abort() -> ! {
188 unsafe {
192 core::arch::asm!("ud2");
193 core::hint::unreachable_unchecked()
194 }
195}
196
197strategy! {
198 pub struct Abort;
203
204 type Result<T, E> = T;
205
206 Ok(v) => v;
207 Err(_) => abort();
208
209 fn map(v, f) => f(v);
210 fn map_err(v, _) => v;
211 fn and_then(v, f) => f(v);
212}
213
214strategy! {
215 pub struct Panic;
219
220 type Result<T, E> = T;
221
222 Ok(v) => v;
223 Err(_) => panic!("{}", FAILURE_MESSAGE);
224
225 fn map(v, f) => f(v);
226 fn map_err(v, _) => v;
227 fn and_then(v, f) => f(v);
228}
229
230strategy! {
231 pub struct Optional;
236
237 type Result<T, E> = Option<T>;
238
239 Ok(v) => Some(v);
240 Err(_) => None;
241
242 fn map(v, f) => v.map(f);
243 fn map_err(v, _) => v;
244 fn and_then(v, f) => v.and_then(f);
245}
246
247strategy! {
248 pub struct Fallible;
252
253 type Result<T, E> = Result<T, E>;
254
255 Ok(v) => Ok(v);
256 Err(e) => Err(e);
257
258 fn map(v, f) => v.map(f);
259 fn map_err(v, f) => v.map_err(f);
260 fn and_then(v, f) => v.and_then(f);
261}
262
263#[macro_export]
264#[doc(hidden)]
265macro_rules! __if_else {
266 ([] || [] else [$($t:tt)*] else $err:literal) => {$($t)*};
267 ([] || [$($t:tt)*] else [$($_:tt)*] else $err:literal) => {$($t)*};
268 ([$($t:tt)*] || [] else [$($_:tt)*] else $err:literal) => {$($t)*};
269 ([$($_:tt)*] || [$($__:tt)*] else [$($___:tt)*] else $err:literal) => {
270 compile_error!($err);
271 };
272
273 ([] else [$($t:tt)*]) => {$($t)*};
274 ([$($t:tt)*] else [$($_:tt)*]) => {$($t)*};
275}