1use std::{convert::Infallible, error::Error, fmt::Debug};
3
4use crate::{Denied, Exhausted, Fatal, Transient};
5
6mod sealed {
7 pub trait Sealed {}
8}
9
10#[doc(hidden)]
12pub trait Slot<M>: From<Infallible> + Error + Clone + Send + Sync + 'static {
13 fn marker(&self) -> &M;
14}
15impl<M: From<Infallible> + Error + Clone + Send + Sync + 'static> Slot<M> for M {
16 fn marker(&self) -> &M {
17 self
18 }
19}
20macro_rules! disabled {
21 ($($marker:ty),*) => {$ (
22 impl Slot<$marker> for Infallible { fn marker(&self) -> &$marker { match *self {} } }
23 impl From<Infallible> for $marker { fn from(value: Infallible) -> Self { match value {} } }
24 )*};
25}
26disabled!(Denied, Transient, Fatal, Exhausted);
27
28#[doc(hidden)]
38pub trait NarrowTransient<F> {
39 fn narrow(self, attempts: u32) -> F;
40}
41impl<F> NarrowTransient<F> for Infallible {
42 fn narrow(self, _: u32) -> F {
43 match self {}
44 }
45}
46impl NarrowTransient<Fatal> for Transient {
47 fn narrow(self, attempts: u32) -> Fatal {
48 Fatal::from_error(
49 crate::FatalKind::Exhausted,
50 Exhausted {
51 attempts,
52 last: self,
53 },
54 )
55 }
56}
57
58#[doc(hidden)]
64pub trait NarrowDenied<F> {
65 fn narrow(self) -> F;
66}
67impl<F> NarrowDenied<F> for Infallible {
68 fn narrow(self) -> F {
69 match self {}
70 }
71}
72impl NarrowDenied<Fatal> for Denied {
73 fn narrow(self) -> Fatal {
74 self.into_fatal()
75 }
76}
77
78pub trait LaneProfile: sealed::Sealed + Debug + Clone + Send + Sync + 'static {
81 type Denied: Slot<Denied>;
82 type Transient: Slot<Transient>;
83 type Fatal: Slot<Fatal>;
84
85 type WithoutTransient: LaneProfile<Denied = Self::Denied, Transient = Infallible, Fatal = Self::Fatal>;
89
90 type WithoutDenied: LaneProfile<Denied = Infallible, Transient = Self::Transient, Fatal = Self::Fatal>;
94
95 type WithDenied: LaneProfile<Denied = Denied, Transient = Self::Transient, Fatal = Self::Fatal>;
97
98 type WithTransient: LaneProfile<Denied = Self::Denied, Transient = Transient, Fatal = Self::Fatal>;
100
101 type WithFatal: LaneProfile<Denied = Self::Denied, Transient = Self::Transient, Fatal = Fatal>;
103}
104
105#[derive(Debug, Clone, Copy)]
106pub struct Profile<const D: bool, const T: bool, const F: bool>;
107macro_rules! profile {
108 ($d:literal, $t:literal, $f:literal; $denied:ty, $transient:ty, $fatal:ty) => {
109 impl sealed::Sealed for Profile<$d, $t, $f> {}
110 impl LaneProfile for Profile<$d, $t, $f> {
111 type Denied = $denied;
112 type Transient = $transient;
113 type Fatal = $fatal;
114 type WithoutTransient = Profile<$d, false, $f>;
115 type WithoutDenied = Profile<false, $t, $f>;
116 type WithDenied = Profile<true, $t, $f>;
117 type WithTransient = Profile<$d, true, $f>;
118 type WithFatal = Profile<$d, $t, true>;
119 }
120 impl crate::Reshape for Profile<$d, $t, $f> {
121 type WithDenied = <Self as LaneProfile>::WithDenied;
122 type WithoutDenied = <Self as LaneProfile>::WithoutDenied;
123 type WithTransient = <Self as LaneProfile>::WithTransient;
124 type WithoutTransient = <Self as LaneProfile>::WithoutTransient;
125 type WithFatal = <Self as LaneProfile>::WithFatal;
126 }
127 };
128}
129profile!(false, false, false; Infallible, Infallible, Infallible);
130profile!(false, false, true; Infallible, Infallible, Fatal);
131profile!(false, true, false; Infallible, Transient, Infallible);
132profile!(false, true, true; Infallible, Transient, Fatal);
133profile!(true, false, false; Denied, Infallible, Infallible);
134profile!(true, false, true; Denied, Infallible, Fatal);
135profile!(true, true, false; Denied, Transient, Infallible);
136profile!(true, true, true; Denied, Transient, Fatal);
137
138pub type AllLanes = Profile<true, true, true>;
139
140pub type NoLanes = Profile<false, false, false>;
143
144#[doc(hidden)]
150pub trait Union<Other: LaneProfile>: LaneProfile {
151 type Out: LaneProfile;
152}
153macro_rules! union_impl {
154 ($d1:literal,$t1:literal,$f1:literal; $d2:literal,$t2:literal,$f2:literal) => {
155 impl Union<Profile<$d2, $t2, $f2>> for Profile<$d1, $t1, $f1> {
156 type Out = Profile<{ $d1 || $d2 }, { $t1 || $t2 }, { $f1 || $f2 }>;
157 }
158 };
159}
160union_impl!(false,false,false; false,false,false);
161union_impl!(false,false,false; false,false,true);
162union_impl!(false,false,false; false,true,false);
163union_impl!(false,false,false; false,true,true);
164union_impl!(false,false,false; true,false,false);
165union_impl!(false,false,false; true,false,true);
166union_impl!(false,false,false; true,true,false);
167union_impl!(false,false,false; true,true,true);
168union_impl!(false,false,true; false,false,false);
169union_impl!(false,false,true; false,false,true);
170union_impl!(false,false,true; false,true,false);
171union_impl!(false,false,true; false,true,true);
172union_impl!(false,false,true; true,false,false);
173union_impl!(false,false,true; true,false,true);
174union_impl!(false,false,true; true,true,false);
175union_impl!(false,false,true; true,true,true);
176union_impl!(false,true,false; false,false,false);
177union_impl!(false,true,false; false,false,true);
178union_impl!(false,true,false; false,true,false);
179union_impl!(false,true,false; false,true,true);
180union_impl!(false,true,false; true,false,false);
181union_impl!(false,true,false; true,false,true);
182union_impl!(false,true,false; true,true,false);
183union_impl!(false,true,false; true,true,true);
184union_impl!(false,true,true; false,false,false);
185union_impl!(false,true,true; false,false,true);
186union_impl!(false,true,true; false,true,false);
187union_impl!(false,true,true; false,true,true);
188union_impl!(false,true,true; true,false,false);
189union_impl!(false,true,true; true,false,true);
190union_impl!(false,true,true; true,true,false);
191union_impl!(false,true,true; true,true,true);
192union_impl!(true,false,false; false,false,false);
193union_impl!(true,false,false; false,false,true);
194union_impl!(true,false,false; false,true,false);
195union_impl!(true,false,false; false,true,true);
196union_impl!(true,false,false; true,false,false);
197union_impl!(true,false,false; true,false,true);
198union_impl!(true,false,false; true,true,false);
199union_impl!(true,false,false; true,true,true);
200union_impl!(true,false,true; false,false,false);
201union_impl!(true,false,true; false,false,true);
202union_impl!(true,false,true; false,true,false);
203union_impl!(true,false,true; false,true,true);
204union_impl!(true,false,true; true,false,false);
205union_impl!(true,false,true; true,false,true);
206union_impl!(true,false,true; true,true,false);
207union_impl!(true,false,true; true,true,true);
208union_impl!(true,true,false; false,false,false);
209union_impl!(true,true,false; false,false,true);
210union_impl!(true,true,false; false,true,false);
211union_impl!(true,true,false; false,true,true);
212union_impl!(true,true,false; true,false,false);
213union_impl!(true,true,false; true,false,true);
214union_impl!(true,true,false; true,true,false);
215union_impl!(true,true,false; true,true,true);
216union_impl!(true,true,true; false,false,false);
217union_impl!(true,true,true; false,false,true);
218union_impl!(true,true,true; false,true,false);
219union_impl!(true,true,true; false,true,true);
220union_impl!(true,true,true; true,false,false);
221union_impl!(true,true,true; true,false,true);
222union_impl!(true,true,true; true,true,false);
223union_impl!(true,true,true; true,true,true);
224
225pub type WithoutTransient<L> = <L as LaneProfile>::WithoutTransient;
237
238pub type WithoutDenied<L> = <L as LaneProfile>::WithoutDenied;
243
244#[macro_export]
246macro_rules! lanes {
247 ($($lane:ident),* $(,)?) => { $crate::lanes!(@acc [false, false, false] $($lane,)*) };
248
249 (@acc [$d:expr, $t:expr, $f:expr]) => { $crate::profile::Profile<{ $d }, { $t }, { $f }> };
250 (@acc [$d:expr, $t:expr, $f:expr] Denied, $($rest:ident,)*) => {
251 $crate::lanes!(@acc [true, $t, $f] $($rest,)*)
252 };
253 (@acc [$d:expr, $t:expr, $f:expr] Transient, $($rest:ident,)*) => {
254 $crate::lanes!(@acc [$d, true, $f] $($rest,)*)
255 };
256 (@acc [$d:expr, $t:expr, $f:expr] Fatal, $($rest:ident,)*) => {
257 $crate::lanes!(@acc [$d, $t, true] $($rest,)*)
258 };
259 (@acc [$d:expr, $t:expr, $f:expr] Rejected, $($rest:ident,)*) => {
262 $crate::profile::Profile<{{
263 compile_error!(
264 "`Rejected` is not a fault lane: it is selected by the carrier, not the \
265 profile. Use `Fail<YourRejection, lanes!(..)>` instead of \
266 `Fault<lanes!(Rejected, ..)>`."
267 );
268 $d
269 }}, { $t }, { $f }>
270 };
271 (@acc [$d:expr, $t:expr, $f:expr] $other:ident, $($rest:ident,)*) => {
272 $crate::profile::Profile<{{
273 compile_error!(concat!(
274 "unknown lane `",
275 stringify!($other),
276 "`: expected `Denied`, `Transient`, or `Fatal`"
277 ));
278 $d
279 }}, { $t }, { $f }>
280 };
281}