rich_result/
lib.rs

1#![feature(try_trait_v2)]
2#![cfg_attr(not(any(test, feature = "std")), no_std)]
3
4use core::{convert::Infallible, fmt, iter, ops};
5
6pub use core::result::Result::{self as StdResult, Err as StdErr, Ok as StdOk};
7
8mod sealed {
9    use super::StdResult;
10
11    pub trait StdResultExt {
12        type Ok;
13        type Err;
14    }
15
16    impl<O, E> StdResultExt for StdResult<O, E> {
17        type Ok = O;
18        type Err = E;
19    }
20}
21
22pub trait StdResultExt: Into<StdResult<Self::Ok, Self::Err>> + sealed::StdResultExt {
23    fn rich(
24        self,
25    ) -> Result<
26        <Self::Ok as sealed::StdResultExt>::Ok,
27        <Self::Ok as sealed::StdResultExt>::Err,
28        Self::Err,
29    >
30    where
31        Self::Ok: StdResultExt,
32    {
33        Result::from_std(self.into().map(Into::into))
34    }
35
36    fn ok_or_recoverable<FE>(self) -> Result<Self::Ok, Self::Err, FE> {
37        Result::ok_or_recoverable(self.into())
38    }
39
40    fn ok_or_fatal<RE>(self) -> Result<Self::Ok, RE, Self::Err> {
41        Result::ok_or_fatal(self.into())
42    }
43
44    fn recoverable_or_fatal<T>(self) -> Result<T, Self::Ok, Self::Err> {
45        Result::from_err(self.into())
46    }
47
48    fn local(self) -> LocalResult<Self::Ok, Self::Err> {
49        LocalResult::from_std(self.into())
50    }
51}
52
53impl<O, E> StdResultExt for StdResult<O, E> { }
54
55#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
56pub struct CollectedErrs<C>(pub C);
57
58impl<T, E, C, EC> FromIterator<StdResult<T, E>> for CollectedErrs<StdResult<C, EC>>
59where
60    C: FromIterator<T>,
61    EC: FromIterator<E>,
62{
63    fn from_iter<I: IntoIterator<Item = StdResult<T, E>>>(iter: I) -> Self {
64        let mut iter = iter.into_iter();
65        let first_err = match (&mut iter).collect() {
66            StdOk(all_ok) => return CollectedErrs(StdOk(all_ok)),
67            StdErr(err) => err,
68        };
69        CollectedErrs(StdErr(
70            iter::once(first_err)
71                .chain(iter.filter_map(|i| i.err()))
72                .collect(),
73        ))
74    }
75}
76
77#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
78pub struct CollectedRecoverables<T>(pub T);
79
80struct CollectSum<T>(T);
81
82impl<T, U> FromIterator<U> for CollectSum<T>
83where
84    T: iter::Sum<U>,
85{
86    fn from_iter<I: IntoIterator<Item = U>>(iter: I) -> Self {
87        CollectSum(iter.into_iter().sum())
88    }
89}
90
91struct CollectProduct<T>(T);
92
93impl<T, U> FromIterator<U> for CollectProduct<T>
94where
95    T: iter::Product<U>,
96{
97    fn from_iter<I: IntoIterator<Item = U>>(iter: I) -> Self {
98        CollectProduct(iter.into_iter().product())
99    }
100}
101
102#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
103#[must_use]
104pub enum Result<T, RE, FE> {
105    Ok(T),
106    Recoverable(RE),
107    Fatal(FE),
108}
109
110pub use crate::Result::*;
111
112impl<T, RE, FE> Result<T, RE, FE> {
113    pub fn from_std(value: StdResult<StdResult<T, RE>, FE>) -> Self {
114        match value {
115            StdOk(StdOk(ok)) => Ok(ok),
116            StdOk(StdErr(err)) => Recoverable(err),
117            StdErr(err) => Fatal(err),
118        }
119    }
120
121    pub fn from_split<E>(
122        split: impl FnOnce(E) -> StdResult<RE, FE>,
123        value: StdResult<T, E>,
124    ) -> Self {
125        match value {
126            StdOk(ok) => Ok(ok),
127            StdErr(err) => Self::from_err(split(err)),
128        }
129    }
130
131    pub fn ok_or_recoverable(value: StdResult<T, RE>) -> Self {
132        StdOk(value).into()
133    }
134
135    pub fn ok_or_fatal(value: StdResult<T, FE>) -> Self {
136        value.map(StdOk).into()
137    }
138
139    pub fn from_err(error: StdResult<RE, FE>) -> Self {
140        match error {
141            StdOk(err) => Recoverable(err),
142            StdErr(err) => Fatal(err),
143        }
144    }
145
146    pub fn to_std(self) -> StdResult<StdResult<T, RE>, FE> {
147        match self {
148            Ok(ok) => StdOk(StdOk(ok)),
149            Recoverable(err) => StdOk(StdErr(err)),
150            Fatal(err) => StdErr(err),
151        }
152    }
153
154    pub fn to_std_flipped(self) -> StdResult<T, StdResult<RE, FE>> {
155        match self {
156            Ok(ok) => StdOk(ok),
157            Recoverable(err) => StdErr(StdOk(err)),
158            Fatal(err) => StdErr(StdErr(err)),
159        }
160    }
161
162    pub const fn is_ok(&self) -> bool {
163        matches!(self, Ok(_))
164    }
165
166    pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool {
167        self.ok().map(f).unwrap_or(false)
168    }
169
170    pub const fn is_any_err(&self) -> bool {
171        !self.is_ok()
172    }
173
174    pub const fn is_recoverable(&self) -> bool {
175        matches!(self, Recoverable(_))
176    }
177
178    pub fn is_recoverable_and(self, f: impl FnOnce(RE) -> bool) -> bool {
179        self.recoverable().map(f).unwrap_or(false)
180    }
181
182    pub const fn is_fatal(&self) -> bool {
183        matches!(self, Fatal(_))
184    }
185
186    pub fn is_fatal_and(self, f: impl FnOnce(FE) -> bool) -> bool {
187        self.fatal().map(f).unwrap_or(false)
188    }
189
190    pub fn ok(self) -> Option<T> {
191        match self {
192            Ok(out) => Some(out),
193            _ => None,
194        }
195    }
196
197    pub fn recoverable(self) -> Option<RE> {
198        match self {
199            Recoverable(out) => Some(out),
200            _ => None,
201        }
202    }
203
204    pub fn fatal(self) -> Option<FE> {
205        match self {
206            Fatal(out) => Some(out),
207            _ => None,
208        }
209    }
210
211    pub fn non_fatal(self) -> Option<StdResult<T, RE>> {
212        match self {
213            Ok(out) => Some(StdOk(out)),
214            Recoverable(err) => Some(StdErr(err)),
215            Fatal(_) => None,
216        }
217    }
218
219    pub fn err(self) -> Option<StdResult<RE, FE>> {
220        match self {
221            Ok(_) => None,
222            Recoverable(err) => Some(StdOk(err)),
223            Fatal(err) => Some(StdErr(err)),
224        }
225    }
226
227    pub fn as_ref(&self) -> Result<&T, &RE, &FE> {
228        match self {
229            Ok(ok) => Ok(ok),
230            Recoverable(err) => Recoverable(err),
231            Fatal(err) => Fatal(err),
232        }
233    }
234
235    pub fn as_mut(&mut self) -> Result<&mut T, &mut RE, &mut FE> {
236        match self {
237            Ok(ok) => Ok(ok),
238            Recoverable(err) => Recoverable(err),
239            Fatal(err) => Fatal(err),
240        }
241    }
242
243    fn map_all<O, REO, FEO>(
244        self,
245        f: impl FnOnce(T) -> O,
246        g: impl FnOnce(RE) -> REO,
247        h: impl FnOnce(FE) -> FEO,
248    ) -> Result<O, REO, FEO> {
249        match self {
250            Ok(ok) => Ok(f(ok)),
251            Recoverable(err) => Recoverable(g(err)),
252            Fatal(err) => Fatal(h(err)),
253        }
254    }
255
256    pub fn map<O>(self, f: impl FnOnce(T) -> O) -> Result<O, RE, FE> {
257        self.map_all(f, |x| x, |x| x)
258    }
259
260    pub fn map_or<O>(self, default: O, f: impl FnOnce(T) -> O) -> O {
261        self.map(f).unwrap_or(default)
262    }
263
264    pub fn map_or_else<O>(self, default: impl FnOnce() -> O, f: impl FnOnce(T) -> O) -> O {
265        self.map(f).unwrap_or_else(default)
266    }
267
268    pub fn map_recoverable<REO>(self, f: impl FnOnce(RE) -> REO) -> Result<T, REO, FE> {
269        self.map_all(|x| x, f, |x| x)
270    }
271
272    pub fn map_fatal<FEO>(self, f: impl FnOnce(FE) -> FEO) -> Result<T, RE, FEO> {
273        self.map_all(|x| x, |x| x, f)
274    }
275
276    pub fn inspect(self, f: impl FnOnce(&T)) -> Self {
277        self.map(|x| {
278            f(&x);
279            x
280        })
281    }
282
283    pub fn inspect_recoverable(self, f: impl FnOnce(&RE)) -> Self {
284        self.map_recoverable(|x| {
285            f(&x);
286            x
287        })
288    }
289
290    pub fn inspect_fatal(self, f: impl FnOnce(&FE)) -> Self {
291        self.map_fatal(|x| {
292            f(&x);
293            x
294        })
295    }
296
297    pub fn as_deref(&self) -> Result<&T::Target, &RE, &FE>
298    where
299        T: ops::Deref,
300    {
301        self.as_ref().map_deref()
302    }
303
304    pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut RE, &mut FE>
305    where
306        T: ops::DerefMut,
307    {
308        self.as_mut().map_deref_mut()
309    }
310
311    pub fn iter(&self) -> core::option::IntoIter<&T> {
312        self.as_ref().ok().into_iter()
313    }
314
315    pub fn iter_mut(&mut self) -> core::option::IntoIter<&mut T> {
316        self.as_mut().ok().into_iter()
317    }
318
319    pub fn expect_nonfatal(self, msg: &str) -> LocalResult<T, RE>
320    where
321        FE: fmt::Debug,
322    {
323        self.to_std().expect(msg).into()
324    }
325
326    pub fn expect_ok(self, msg: &str) -> T
327    where
328        RE: fmt::Debug,
329        FE: fmt::Debug,
330    {
331        self.to_std().expect(msg).expect(msg)
332    }
333
334    pub fn unwrap_nonfatal(self) -> LocalResult<T, RE>
335    where
336        FE: fmt::Debug,
337    {
338        self.to_std().unwrap().into()
339    }
340
341    pub fn unwrap_ok(self) -> T
342    where
343        RE: fmt::Debug,
344        FE: fmt::Debug,
345    {
346        self.to_std().unwrap().unwrap()
347    }
348
349    pub fn unwrap_or_default(self) -> T
350    where
351        T: Default,
352    {
353        self.unwrap_or_else(T::default)
354    }
355
356    pub fn unwrap_or(self, default: T) -> T {
357        self.unwrap_or_else(move || default)
358    }
359
360    pub fn unwrap_or_else(self, default: impl FnOnce() -> T) -> T {
361        match self {
362            Ok(out) => out,
363            _ => default(),
364        }
365    }
366
367    pub fn and<O>(self, res: Result<O, RE, FE>) -> Result<O, RE, FE> {
368        self.and_then(move |_| res)
369    }
370
371    pub fn and_then<O>(self, f: impl FnOnce(T) -> Result<O, RE, FE>) -> Result<O, RE, FE> {
372        match self {
373            Ok(out) => f(out),
374            Recoverable(err) => Recoverable(err),
375            Fatal(err) => Fatal(err),
376        }
377    }
378
379    pub fn flatten_err<E: From<RE> + From<FE>>(self) -> StdResult<T, E> {
380        match self {
381            Ok(out) => StdOk(out),
382            Recoverable(err) => StdErr(err.into()),
383            Fatal(err) => StdErr(err.into()),
384        }
385    }
386
387    pub fn convert_err<REO: From<RE>, FEO: From<FE>>(self) -> Result<T, REO, FEO> {
388        match self {
389            Ok(out) => Ok(out),
390            Recoverable(err) => Recoverable(err.into()),
391            Fatal(err) => Fatal(err.into()),
392        }
393    }
394
395    pub fn more_fatal<REO>(self, f: impl FnOnce(RE) -> StdResult<REO, FE>) -> Result<T, REO, FE> {
396        match self {
397            Ok(out) => Ok(out),
398            Recoverable(err) => match f(err) {
399                StdOk(err) => Recoverable(err),
400                StdErr(err) => Fatal(err),
401            },
402            Fatal(err) => Fatal(err),
403        }
404    }
405
406    pub fn less_fatal<FEO>(self, f: impl FnOnce(FE) -> StdResult<RE, FEO>) -> Result<T, RE, FEO> {
407        match self {
408            Ok(out) => Ok(out),
409            Recoverable(err) => Recoverable(err),
410            Fatal(err) => match f(err) {
411                StdOk(err) => Recoverable(err),
412                StdErr(err) => Fatal(err),
413            },
414        }
415    }
416
417    pub fn collect_layered<U>(iter: impl IntoIterator<Item = Result<U, RE, FE>>) -> Self
418    where
419        T: FromIterator<U>,
420    {
421        let mut iter = iter.into_iter().map(Result::to_std);
422        let mut out: StdResult<_, _> = match (&mut iter).collect() {
423            StdOk(out) => out,
424            StdErr(err) => return Fatal(err),
425        };
426        for i in iter {
427            match i {
428                StdOk(StdOk(_)) => (),
429                StdOk(StdErr(recoverable)) if out.is_ok() => out = StdErr(recoverable),
430                StdOk(StdErr(_)) => (),
431                StdErr(err) => return Fatal(err),
432            }
433        }
434        Self::ok_or_recoverable(out)
435    }
436}
437
438impl<'a, T, RE, FE> Result<&'a T, RE, FE> {
439    pub fn map_deref(self) -> Result<&'a <T as ops::Deref>::Target, RE, FE>
440    where
441        T: ops::Deref,
442    {
443        self.map(|x| &**x)
444    }
445
446    pub fn copied(self) -> Result<T, RE, FE>
447    where
448        T: Copy,
449    {
450        self.map(|ok| *ok)
451    }
452
453    pub fn cloned(self) -> Result<T, RE, FE>
454    where
455        T: Clone,
456    {
457        self.map(|ok| ok.clone())
458    }
459}
460
461impl<'a, T, RE, FE> Result<&'a mut T, RE, FE> {
462    pub fn map_deref(self) -> Result<&'a T::Target, RE, FE>
463    where
464        T: ops::DerefMut,
465    {
466        self.map(|x| &**x)
467    }
468
469    pub fn map_deref_mut(self) -> Result<&'a mut T::Target, RE, FE>
470    where
471        T: ops::DerefMut,
472    {
473        self.map(|x| &mut **x)
474    }
475
476    pub fn copied(self) -> Result<T, RE, FE>
477    where
478        T: Copy,
479    {
480        self.map(|ok| *ok)
481    }
482
483    pub fn cloned(self) -> Result<T, RE, FE>
484    where
485        T: Clone,
486    {
487        self.map(|ok| ok.clone())
488    }
489}
490
491impl<T, RE, FE> Result<Result<T, RE, FE>, RE, FE> {
492    pub fn flatten(self) -> Result<T, RE, FE> {
493        self.and_then(|x| x)
494    }
495}
496
497impl<T, RE, FE> From<Result<T, RE, FE>> for StdResult<StdResult<T, RE>, FE> {
498    fn from(value: Result<T, RE, FE>) -> Self {
499        value.to_std()
500    }
501}
502
503impl<T, RE, FE> From<StdResult<StdResult<T, RE>, FE>> for Result<T, RE, FE> {
504    fn from(value: StdResult<StdResult<T, RE>, FE>) -> Self {
505        Self::from_std(value)
506    }
507}
508
509impl<T, RE, FE> IntoIterator for Result<T, RE, FE> {
510    type Item = T;
511    type IntoIter = core::option::IntoIter<T>;
512
513    fn into_iter(self) -> Self::IntoIter {
514        self.ok().into_iter()
515    }
516}
517
518impl<'a, T, RE, FE> IntoIterator for &'a Result<T, RE, FE> {
519    type Item = &'a T;
520    type IntoIter = core::option::IntoIter<&'a T>;
521
522    fn into_iter(self) -> Self::IntoIter {
523        self.iter()
524    }
525}
526
527impl<'a, T, RE, FE> IntoIterator for &'a mut Result<T, RE, FE> {
528    type Item = &'a mut T;
529    type IntoIter = core::option::IntoIter<&'a mut T>;
530
531    fn into_iter(self) -> Self::IntoIter {
532        self.iter_mut()
533    }
534}
535
536impl<T, RE, FE, C> FromIterator<Result<T, RE, FE>> for Result<C, RE, FE>
537where
538    C: FromIterator<T>,
539{
540    fn from_iter<I: IntoIterator<Item = Result<T, RE, FE>>>(iter: I) -> Self {
541        Self::from_std(iter.into_iter().map(Result::to_std).collect())
542    }
543}
544
545impl<T, RE, FE, C, REC, FEC> FromIterator<Result<T, RE, FE>> for CollectedErrs<Result<C, REC, FEC>>
546where
547    C: FromIterator<T>,
548    REC: FromIterator<RE>,
549    FEC: FromIterator<FE>,
550{
551    fn from_iter<I: IntoIterator<Item = Result<T, RE, FE>>>(iter: I) -> Self {
552        let collected: CollectedErrs<StdResult<CollectedErrs<StdResult<C, REC>>, FEC>> =
553            iter.into_iter().map(Result::to_std).collect();
554
555        CollectedErrs(collected.0.map(|collected| collected.0).into())
556    }
557}
558
559impl<T, RE, FE, C, EC> FromIterator<Result<T, RE, FE>> for CollectedErrs<StdResult<C, EC>>
560where
561    C: FromIterator<T>,
562    EC: FromIterator<StdResult<RE, FE>>,
563{
564    fn from_iter<I: IntoIterator<Item = Result<T, RE, FE>>>(iter: I) -> Self {
565        iter.into_iter().map(Result::to_std_flipped).collect()
566    }
567}
568
569impl<T, RE, FE, C, REC> FromIterator<Result<T, RE, FE>>
570    for CollectedRecoverables<Result<C, REC, FE>>
571where
572    C: FromIterator<T>,
573    REC: FromIterator<RE>,
574{
575    fn from_iter<I: IntoIterator<Item = Result<T, RE, FE>>>(iter: I) -> Self {
576        let collected: StdResult<CollectedErrs<StdResult<C, REC>>, FE> =
577            iter.into_iter().map(Result::to_std).collect();
578
579        CollectedRecoverables(collected.map(|collected| collected.0).into())
580    }
581}
582
583#[cfg(feature = "std")]
584impl<T: std::process::Termination, RE: fmt::Debug, FE: fmt::Debug> std::process::Termination
585    for Result<T, RE, FE>
586{
587    fn report(self) -> std::process::ExitCode {
588        self.to_std().report()
589    }
590}
591
592impl<T, RE, FE, FEO: From<FE>> ops::FromResidual<Result<Infallible, Infallible, FE>>
593    for Result<T, RE, FEO>
594{
595    fn from_residual(residual: Result<Infallible, Infallible, FE>) -> Self {
596        match residual {
597            Ok(infallible) | Recoverable(infallible) => match infallible {},
598            Fatal(err) => Fatal(err.into()),
599        }
600    }
601}
602
603impl<T, RE, FE> ops::Try for Result<T, RE, FE> {
604    type Output = LocalResult<T, RE>;
605    type Residual = Result<Infallible, Infallible, FE>;
606
607    fn from_output(output: Self::Output) -> Self {
608        match output {
609            NoErr(ok) => Ok(ok),
610            Handle(err) => Recoverable(err),
611        }
612    }
613
614    fn branch(self) -> ops::ControlFlow<Self::Residual, Self::Output> {
615        match self {
616            Ok(ok) => ops::ControlFlow::Continue(NoErr(ok)),
617            Recoverable(err) => ops::ControlFlow::Continue(Handle(err)),
618            Fatal(err) => ops::ControlFlow::Break(Fatal(err)),
619        }
620    }
621}
622
623#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
624#[must_use]
625pub enum LocalResult<T, RE> {
626    NoErr(T),
627    Handle(RE),
628}
629
630pub use LocalResult::*;
631
632impl<T, RE> LocalResult<T, RE> {
633    pub fn from_std(res: StdResult<T, RE>) -> Self {
634        match res {
635            StdOk(ok) => NoErr(ok),
636            StdErr(err) => Handle(err),
637        }
638    }
639
640    pub fn to_std(self) -> StdResult<T, RE> {
641        match self {
642            NoErr(ok) => StdOk(ok),
643            Handle(err) => StdErr(err),
644        }
645    }
646
647    pub fn to_result<FE>(self) -> Result<T, RE, FE> {
648        Result::ok_or_recoverable(self.to_std())
649    }
650
651    pub const fn is_ok(&self) -> bool {
652        matches!(self, NoErr(_))
653    }
654
655    pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool {
656        self.ok().map(f).unwrap_or(false)
657    }
658
659    pub fn is_ok_or(self, f: impl FnOnce(RE) -> bool) -> bool {
660        self.err().map(f).unwrap_or(true)
661    }
662
663    pub const fn is_err(&self) -> bool {
664        !self.is_ok()
665    }
666
667    pub fn is_err_and(self, f: impl FnOnce(RE) -> bool) -> bool {
668        self.err().map(f).unwrap_or(false)
669    }
670
671    pub fn is_err_or(self, f: impl FnOnce(T) -> bool) -> bool {
672        self.ok().map(f).unwrap_or(true)
673    }
674
675    pub fn ok(self) -> Option<T> {
676        match self {
677            NoErr(out) => Some(out),
678            Handle(_) => None,
679        }
680    }
681
682    pub fn err(self) -> Option<RE> {
683        match self {
684            NoErr(_) => None,
685            Handle(err) => Some(err),
686        }
687    }
688
689    pub fn expect(self, msg: &str) -> T
690    where
691        RE: fmt::Debug,
692    {
693        self.to_std().expect(msg)
694    }
695
696    pub fn unwrap(self) -> T
697    where
698        RE: fmt::Debug,
699    {
700        self.to_std().unwrap()
701    }
702}
703
704impl<T, RE> From<LocalResult<T, RE>> for StdResult<T, RE> {
705    fn from(value: LocalResult<T, RE>) -> Self {
706        value.to_std()
707    }
708}
709
710impl<T, RE> From<StdResult<T, RE>> for LocalResult<T, RE> {
711    fn from(value: StdResult<T, RE>) -> Self {
712        Self::from_std(value)
713    }
714}
715
716impl<T, RE, FE> From<LocalResult<T, RE>> for Result<T, RE, FE> {
717    fn from(value: LocalResult<T, RE>) -> Self {
718        value.to_result()
719    }
720}
721
722/// only necessary because the `ops::Try` instance requires a `FromResidual` instance, this type is
723/// *not* intended to be used as a return type.
724impl<T, RE, REO: From<RE>> ops::FromResidual<LocalResult<Infallible, RE>> for LocalResult<T, REO> {
725    fn from_residual(residual: LocalResult<Infallible, RE>) -> Self {
726        match residual {
727            NoErr(infallible) => match infallible {},
728            Handle(err) => Handle(err.into()),
729        }
730    }
731}
732
733impl<T, RE> ops::Try for LocalResult<T, RE> {
734    type Output = T;
735    type Residual = LocalResult<Infallible, RE>;
736
737    fn from_output(output: Self::Output) -> Self {
738        NoErr(output)
739    }
740
741    fn branch(self) -> ops::ControlFlow<Self::Residual, Self::Output> {
742        match self {
743            NoErr(ok) => ops::ControlFlow::Continue(ok),
744            Handle(err) => ops::ControlFlow::Break(Handle(err)),
745        }
746    }
747}
748
749// cross compatibility: -> StdResult<_, _>
750impl<T, FE, FEO: From<FE>> ops::FromResidual<Result<Infallible, Infallible, FE>>
751    for StdResult<T, FEO>
752{
753    fn from_residual(residual: Result<Infallible, Infallible, FE>) -> Self {
754        match residual {
755            Ok(infallible) | Recoverable(infallible) => match infallible {},
756            Fatal(err) => StdResult::Err(err.into()),
757        }
758    }
759}
760
761impl<T, RE, REO: From<RE>, FEO> ops::FromResidual<LocalResult<Infallible, RE>>
762    for StdResult<StdResult<T, REO>, FEO>
763{
764    fn from_residual(residual: LocalResult<Infallible, RE>) -> Self {
765        match residual {
766            NoErr(infallible) => match infallible {},
767            Handle(err) => StdResult::Ok(StdResult::Err(err.into())),
768        }
769    }
770}
771
772// cross compatibility: -> Result<_, _, _>
773impl<T, FE, REO, FEO: From<FE>> ops::FromResidual<StdResult<Infallible, FE>>
774    for Result<T, REO, FEO>
775{
776    fn from_residual(residual: StdResult<Infallible, FE>) -> Self {
777        match residual {
778            StdOk(infallible) => match infallible {},
779            StdErr(err) => Fatal(err.into()),
780        }
781    }
782}
783
784impl<T, RE, FE, REO: From<RE>> ops::FromResidual<LocalResult<Infallible, RE>>
785    for Result<T, REO, FE>
786{
787    fn from_residual(residual: LocalResult<Infallible, RE>) -> Self {
788        match residual {
789            NoErr(infallible) => match infallible {},
790            Handle(err) => Recoverable(err.into()),
791        }
792    }
793}
794
795#[cfg(test)]
796mod tests {
797    use super::*;
798
799    #[test]
800    fn test_collected_errs_std() {
801        type Collected = CollectedErrs<StdResult<Vec<u8>, Vec<&'static str>>>;
802
803        let ok = StdOk::<u8, &'static str>;
804        let err = StdErr::<u8, &'static str>;
805
806        // empty
807        assert_eq!(
808            Vec::<StdResult<u8, &'static str>>::new()
809                .into_iter()
810                .collect::<Collected>(),
811            CollectedErrs(StdOk(Vec::new())),
812        );
813
814        // only `Ok`
815        assert_eq!(
816            vec![ok(1), ok(2), ok(3)].into_iter().collect::<Collected>(),
817            CollectedErrs(StdOk(vec![1, 2, 3]))
818        );
819
820        // only `Err`
821        assert_eq!(
822            vec![err("A"), err("B"), err("C")]
823                .into_iter()
824                .collect::<Collected>(),
825            CollectedErrs(StdErr(vec!["A", "B", "C"])),
826        );
827
828        // interspliced `Err`
829        assert_eq!(
830            vec![ok(1), err("A"), err("B"), ok(2), err("C")]
831                .into_iter()
832                .collect::<Collected>(),
833            CollectedErrs(StdErr(vec!["A", "B", "C"])),
834        );
835    }
836
837    #[test]
838    fn test_collected_layered() {
839        type Collected = Result<Vec<u8>, &'static str, ()>;
840
841        // empty
842        assert_eq!(Collected::collect_layered([]), Ok(vec![]),);
843
844        // only `Ok`
845        assert_eq!(
846            Collected::collect_layered([Ok(1), Ok(2), Ok(3)]),
847            Ok(vec![1, 2, 3]),
848        );
849
850        // has `Recoverable`
851        assert_eq!(
852            Collected::collect_layered([Ok(1), Ok(2), Recoverable("X"), Ok(3)]),
853            Recoverable("X"),
854        );
855
856        // has `Fatal` before `Recoverable`
857        assert_eq!(
858            Collected::collect_layered([Ok(1), Fatal(()), Ok(2), Recoverable("X"), Ok(3)]),
859            Fatal(()),
860        );
861
862        // has `Fatal` after `Recoverable`, but still returns `Fatal`
863        assert_eq!(
864            Collected::collect_layered([Ok(1), Recoverable("X"), Ok(2), Fatal(()), Ok(3)]),
865            Fatal(()),
866        );
867    }
868
869    #[test]
870    fn test_from_iter() {
871        type Collected = Result<Vec<u8>, &'static str, ()>;
872
873        // empty
874        assert_eq!(Collected::from_iter([]), Ok(vec![]),);
875
876        // only `Ok`
877        assert_eq!(
878            Collected::from_iter([Ok(1), Ok(2), Ok(3)]),
879            Ok(vec![1, 2, 3]),
880        );
881
882        // has `Recoverable`
883        assert_eq!(
884            Collected::from_iter([Ok(1), Ok(2), Recoverable("X"), Ok(3)]),
885            Recoverable("X"),
886        );
887
888        // has `Fatal` before `Recoverable`
889        assert_eq!(
890            Collected::from_iter([Ok(1), Fatal(()), Ok(2), Recoverable("X"), Ok(3)]),
891            Fatal(()),
892        );
893
894        // has `Fatal` after `Recoverable`, but doesn't scan until that point
895        assert_eq!(
896            Collected::from_iter([Ok(1), Recoverable("X"), Ok(2), Fatal(()), Ok(3)]),
897            Recoverable("X"),
898        );
899    }
900
901    #[test]
902    fn test_from_collected_errs() {
903        type Collected = CollectedErrs<Result<Vec<u8>, Vec<&'static str>, Vec<()>>>;
904
905        // empty
906        assert_eq!(Collected::from_iter([]), CollectedErrs(Ok(vec![])),);
907
908        // only `Ok`
909        assert_eq!(
910            Collected::from_iter([Ok(1), Ok(2), Ok(3)]),
911            CollectedErrs(Ok(vec![1, 2, 3])),
912        );
913
914        // has `Recoverable`
915        assert_eq!(
916            Collected::from_iter([
917                Ok(1),
918                Ok(2),
919                Recoverable("X"),
920                Ok(3),
921                Recoverable("Y"),
922                Ok(4)
923            ]),
924            CollectedErrs(Recoverable(vec!["X", "Y"])),
925        );
926
927        // has `Fatal` before `Recoverable`
928        assert_eq!(
929            Collected::from_iter([Ok(1), Fatal(()), Ok(2), Recoverable("X"), Ok(3)]),
930            CollectedErrs(Fatal(vec![()])),
931        );
932
933        // has `Fatal` after `Recoverable`
934        assert_eq!(
935            Collected::from_iter([Ok(1), Recoverable("X"), Ok(2), Fatal(()), Ok(3)]),
936            CollectedErrs(Fatal(vec![()])),
937        );
938    }
939
940    #[test]
941    fn test_from_collected_errs_mixed() {
942        type Collected = CollectedErrs<StdResult<Vec<u8>, Vec<StdResult<&'static str, ()>>>>;
943
944        // empty
945        assert_eq!(
946            Collected::from_iter(Vec::<Result<u8, &'static str, ()>>::new()),
947            CollectedErrs(StdOk(vec![])),
948        );
949
950        // only `Ok`
951        assert_eq!(
952            Collected::from_iter([Ok(1), Ok(2), Ok(3)]),
953            CollectedErrs(StdOk(vec![1, 2, 3])),
954        );
955
956        // has `Recoverable`
957        assert_eq!(
958            Collected::from_iter([
959                Ok(1),
960                Ok(2),
961                Recoverable("X"),
962                Ok(3),
963                Recoverable("Y"),
964                Ok(4)
965            ]),
966            CollectedErrs(StdErr(vec![StdOk("X"), StdOk("Y")])),
967        );
968
969        // has `Fatal`
970        assert_eq!(
971            Collected::from_iter([Ok(1), Fatal(()), Ok(2), Recoverable("X"), Ok(3)]),
972            CollectedErrs(StdErr(vec![StdErr(()), StdOk("X")])),
973        );
974    }
975
976    #[test]
977    fn test_from_collected_recoverables() {
978        type Collected = CollectedRecoverables<Result<Vec<u8>, Vec<&'static str>, ()>>;
979
980        // empty
981        assert_eq!(Collected::from_iter([]), CollectedRecoverables(Ok(vec![])),);
982
983        // only `Ok`
984        assert_eq!(
985            Collected::from_iter([Ok(1), Ok(2), Ok(3)]),
986            CollectedRecoverables(Ok(vec![1, 2, 3])),
987        );
988
989        // has `Recoverable`
990        assert_eq!(
991            Collected::from_iter([
992                Ok(1),
993                Ok(2),
994                Recoverable("X"),
995                Ok(3),
996                Recoverable("Y"),
997                Ok(4)
998            ]),
999            CollectedRecoverables(Recoverable(vec!["X", "Y"])),
1000        );
1001
1002        // has `Fatal` before `Recoverable`
1003        assert_eq!(
1004            Collected::from_iter([Ok(1), Fatal(()), Ok(2), Recoverable("X"), Ok(3)]),
1005            CollectedRecoverables(Fatal(())),
1006        );
1007
1008        // has `Fatal` after `Recoverable`
1009        assert_eq!(
1010            Collected::from_iter([Ok(1), Recoverable("X"), Ok(2), Fatal(()), Ok(3)]),
1011            CollectedRecoverables(Fatal(())),
1012        );
1013    }
1014
1015    mod type_checks {
1016        use super::*;
1017
1018        struct OkTy;
1019        struct RecoverableTy;
1020        struct FatalTy;
1021
1022        type NormalResultTy = StdResult<OkTy, FatalTy>;
1023        type StackedResultTy = StdResult<StdResult<OkTy, RecoverableTy>, FatalTy>;
1024        type ResultTy = Result<OkTy, RecoverableTy, FatalTy>;
1025
1026        fn std_result() -> NormalResultTy {
1027            unimplemented!()
1028        }
1029        fn result() -> ResultTy {
1030            unimplemented!()
1031        }
1032
1033        mod tests {
1034            #![allow(dead_code)]
1035            use super::*;
1036
1037            fn returns_std_result() -> StackedResultTy {
1038                std_result()?;
1039                match result()? {
1040                    NoErr(_) | Handle(_) => (),
1041                }
1042                result()??;
1043
1044                StdOk(StdOk(OkTy))
1045            }
1046
1047            fn returns_result() -> ResultTy {
1048                std_result()?;
1049                match result()? {
1050                    NoErr(_) | Handle(_) => (),
1051                }
1052                result()??;
1053
1054                Ok(OkTy)
1055            }
1056
1057            /// This should warn because `result()?` still has an unhandled error
1058            fn this_should_warn() -> ResultTy { result()?; Ok(OkTy) }
1059        }
1060    }
1061}