micro_errors/
lib.rs

1#![cfg_attr(feature = "nightly", feature(min_specialization))]
2
3use std::{any::Any, backtrace::Backtrace, fmt::{Debug, Display}};
4
5#[cfg(test)]
6mod tests {
7    #[allow(deprecated)]
8    use crate::ErrorChain;
9    use crate::ErrorLink_;
10    use crate::ErrorLinkable;
11    use crate::NextLink;
12    #[cfg(feature = "nightly")]
13    use crate::ResultExt;
14    use std::backtrace::Backtrace;
15    use crate::LinkableResult1of2;
16    use crate::LinkableResult2of2;
17
18    #[allow(dead_code)]
19    trait X {
20        fn letter() -> char;
21    }
22    impl<T> X for T {
23        fn letter() -> char {
24            'X'
25        }
26    }
27    struct B;
28    impl B {
29        fn letter() -> char {
30            'B'
31        }
32    }
33
34    #[test]
35    fn test_favour_concrete() {
36        assert!(B::letter() == 'B');
37    }
38
39    fn is_output_default(default_output: &str) {
40        assert_eq!(
41            default_output
42                .matches("Link no. 0: Higher level error.\nLink no. 1: Underlying error.")
43                .collect::<Vec<_>>()
44                .len(),
45            1
46        );
47        has_only_one_backtrace(default_output);
48    }
49    fn has_only_one_backtrace(formatted_link: &str) {
50        assert_eq!(
51            formatted_link 
52                .matches("Approximate backtrace of link no. ")
53                .collect::<Vec<_>>()
54                .len(),
55            1
56        );
57    }
58
59    #[test]
60    #[allow(non_snake_case)]
61    #[allow(deprecated)]
62    fn test__chaining_non_error_chain() {
63        let format_output = format!(
64            "{}", 
65            Err::<(), _>(std::io::Error::other("Underlying error."))
66                .map_err(ErrorChain::link_fn("Higher level error."))
67                .expect_err("look above")
68        );
69        println!("{}", format_output);
70        is_output_default(&format_output);
71    }
72    #[test]
73    #[allow(non_snake_case)]
74    fn test__chaining_non_error_link_() {
75        let error_link: ErrorLink_<String> = Err::<(), _>(std::io::Error::other("Underlying error."))
76            .map_err(|e| e.as_link())
77            .map_err(|e| e.link("Higher level error."))
78            .expect_err("look above");
79        let format_output = format!(
80            "{}", error_link
81        );
82        println!("{}", format_output);
83        is_output_default(&format_output);
84    }
85
86    #[test]
87    #[allow(deprecated)]
88    #[allow(non_snake_case)]
89    fn test__chaining_error_chain() {
90        let format_output = format!(
91            "{}", 
92            Err::<(), _>(ErrorChain::start("Underlying error."))
93                .map_err(ErrorChain::link_fn("Higher level error."))
94                .expect_err("look above")
95        );
96        println!("{}", format_output);
97        is_output_default(&format_output);
98    }
99
100    #[test]
101    #[allow(non_snake_case)]
102    fn test__chaining_error_link_() {
103        let error_link: ErrorLink_<String> = Err::<(), _>(ErrorLink_::new_string("Underlying error."))
104            .map_err(|e| e.as_link() as ErrorLink_<String>)
105            .map_err(|e| e.link("Higher level error."))
106            .expect_err("look above");
107        let format_output = format!("{error_link}");
108        println!("{}", format_output);
109        is_output_default(&format_output);
110    }
111
112    impl ErrorLink_<i32> {
113        pub fn new_i32(error_number: impl Into<i32>) -> Self {
114            Self(error_number.into(), NextLink::None(Backtrace::capture()))
115        }
116    }
117    #[derive(Debug, PartialEq)]
118    enum ErrorReasons {
119        One,
120        Two,
121        #[allow(dead_code)]
122        Three
123    }
124    impl ErrorLink_<ErrorReasons> {
125        pub fn new_reason(error_reason: ErrorReasons) -> Self {
126            Self(error_reason, NextLink::None(Backtrace::capture()))
127        }
128    }
129    impl std::fmt::Display for ErrorReasons {
130        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131            let as_string = match self {
132                ErrorReasons::One => "First reason for underlying error.",
133                ErrorReasons::Two => "Second reason for underlying error.",
134                ErrorReasons::Three => "Third reason for underlying error.",
135            }; 
136            write!(f, "{}", as_string)
137        }
138    }
139    impl std::error::Error for ErrorReasons {}
140
141    #[test]
142    #[allow(non_snake_case)]
143    fn test__chaining_error_link__non_string_payload() {
144        let error_link: ErrorLink_<String> = Err::<(), _>(ErrorLink_::new_i32(100))
145            .map_err(|e| e.link("Higher level error."))
146            .expect_err("look above");
147        let mut format_output = format!("{error_link}");
148        println!("{}", format_output);
149        assert_eq!(
150            format_output 
151                .matches("Link no. 0: Higher level error.\nLink no. 1: 100")
152                .collect::<Vec<_>>()
153                .len(),
154            1
155        );
156        has_only_one_backtrace(&format_output);
157
158        let error_link: ErrorLink_<String> = Err::<(), _>(ErrorLink_::new_reason(ErrorReasons::One))
159            .map_err(|e| e.link("Higher level error."))
160            .expect_err("look above");
161        format_output = format!("{}", error_link);
162        println!("{}", format_output);
163        assert_eq!(
164            format_output 
165                .matches("Link no. 0: Higher level error.\nLink no. 1: First reason for underlying error.")
166                .collect::<Vec<_>>()
167                .len(),
168            1
169        );
170        has_only_one_backtrace(&format_output);
171
172        match Err::<(), _>(ErrorLink_::new_reason(ErrorReasons::Two)) {
173            Err(error_chain) if error_chain.0 == ErrorReasons::Two => {
174                format_output = format!("{}", error_chain);
175                println!("{}", format_output);
176                assert_eq!(
177                    format_output 
178                        .matches("Link no. 0: Second reason for underlying error.")
179                        .collect::<Vec<_>>()
180                        .len(),
181                    1
182                );
183                has_only_one_backtrace(&format_output);       
184            },
185            _ => panic!("look above"),
186        }
187    }
188
189    #[test]
190    #[allow(deprecated)]
191    #[allow(non_snake_case)]
192    fn test__chaining_non_error_chain_and_non_error_trait() {
193        let format_output = format!(
194            "{}", 
195            Err::<(), _>(String::from("Underlying error."))
196                .map_err(ErrorChain::onboard_fn("Higher level error."))
197                .expect_err("look above")
198        );
199        println!("{}", format_output);
200        is_output_default(&format_output);
201    }
202
203    #[test]
204    #[allow(non_snake_case)]
205    fn test__chaining_non_error_link_and_non_error_trait() {
206        let format_output = format!(
207            "{}", 
208            Err::<(), _>(String::from("Underlying error."))
209                .map_err(|e| e.link("Higher level error."))
210                .expect_err("look above")
211        );
212        println!("{}", format_output);
213        is_output_default(&format_output);
214    }
215
216    #[test]
217    #[allow(non_snake_case)]
218    fn test__resultext__chaining_non() {
219        let format_output = format!(
220            "{}", 
221            Err::<(), _>(String::from("Underlying error."))
222                .map_err(|e| e.link("Higher level error."))
223                .expect_err("look above")
224        );
225        println!("{}", format_output);
226        is_output_default(&format_output);
227    }
228
229    #[cfg(feature = "nightly")]
230    #[test]
231    #[allow(non_snake_case)]
232    fn test__resultext__chaining_error_link__string_payload() {
233        let format_output = format!(
234            "{}",
235            Err::<(), _>(ErrorLink_::new_string("Underlying error."))
236                .me_al()
237                .me_l("Higher level error.")
238                .expect_err("look above")
239        );
240        println!("{}", format_output);
241        is_output_default(&format_output);
242    }
243
244    #[cfg(feature = "nightly")]
245    #[test]
246    #[allow(non_snake_case)]
247    fn test__resultext__chaining_error_link__non_string_payload() {
248        let format_output = format!(
249            "{}",
250            Err::<(), _>(ErrorLink_::new_i32(100))
251                .me_al()
252                .expect_err("look above")
253        );
254        println!("{}", format_output);
255        assert_eq!(
256            format_output 
257                .matches("100")
258                .collect::<Vec<_>>()
259                .len(),
260            1
261        );
262        has_only_one_backtrace(&format_output);
263    }
264
265    #[cfg(feature = "nightly")]
266    #[test]
267    #[allow(non_snake_case)]
268    fn test__resultext__chaining_non_error_link__string_payload() {
269        let format_output = format!(
270            "{}",
271            Err::<(), _>(String::from("Underlying error."))
272                .me_al()
273                .expect_err("look above")
274        );
275        println!("{}", format_output);
276        assert_eq!(
277            format_output 
278                .matches("Underlying error.")
279                .collect::<Vec<_>>()
280                .len(),
281            1
282        );
283        has_only_one_backtrace(&format_output);
284    }
285
286    #[cfg(feature = "nightly")]
287    #[test]
288    #[allow(non_snake_case)]
289    fn test__resultext__chaining_non_error_link__non_string_payload() {
290        let format_output = format!(
291            "{}",
292            Err::<(), _>(100)
293                .me_al()
294                .expect_err("look above")
295        );
296        println!("{}", format_output);
297        assert_eq!(
298            format_output 
299                .matches("100")
300                .collect::<Vec<_>>()
301                .len(),
302            1
303        );
304        has_only_one_backtrace(&format_output);
305    }
306
307    #[allow(dead_code)]
308    struct DisplayableAndIntoStringable(String);
309    impl From<DisplayableAndIntoStringable> for String {
310        fn from(value: DisplayableAndIntoStringable) -> Self {
311            value.0
312        }
313    }
314    impl std::fmt::Display for DisplayableAndIntoStringable {
315        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
316            write!(f, "DisplayableAndIntoStringable")
317        }
318    }
319
320    #[test]
321    #[allow(non_snake_case)]
322    fn test__link_conversion__to_error_link_string() {
323        let _ = || -> Result<(), ErrorLink_<String>> {
324            Err::<(), _>(ErrorLink_::new("These `Result`s would be typically from function calls."))?;
325            Err::<(), _>(String::from(
326                "So, if the error is an `ErrorLink_` of same payload, or the payload type itself, \
327                `?` can be used."
328            ))?;
329            #[cfg(feature = "nightly")]
330            Err::<(), _>(std::io::Error::other(
331                "`ErrorLink_<String>` is like a terminal type. `me_as_slink()?` can always be called, \
332                and all can turn into it."
333            )).me_as_slink()?;
334            Err::<(), _>(ErrorLink_::<DisplayableAndIntoStringable>::new(
335                DisplayableAndIntoStringable(String::from(
336                    "`impl<T> from <T> for T` exists, so `?` cannot cover all `ErrorLink_` to \
337                    `ErrorLink_`s. Hence `me_as_link`."
338                ))
339            )).me_as_link()?;
340            Ok(())
341        }();
342    }
343
344    #[test]
345    #[allow(non_snake_case)]
346    fn test__adding_link__to_error_link_string() {
347        let _ = || -> Result<(), ErrorLink_<String>> {
348            Err::<(), _>(ErrorLink_::<std::io::Error>::new(
349                std::io::Error::other("Some data relating to an unhappy code path.")
350            ))
351                .me_link("Some more information.")?;
352            Ok(())
353        }();
354    }
355
356    #[test]
357    #[allow(non_snake_case)]
358    fn test__replacing_payload__to_error_link_string() {
359        let _ = || -> Result<(), ErrorLink_<String>> {
360            Err::<(), _>(ErrorLink_::<std::io::Error>::new(std::io::Error::other("Something ugly.")))
361                .map_err(|_| ErrorLink_::new("Get replaced."))?;
362            Err::<(), _>(ErrorLink_::<std::io::Error>::new(std::io::Error::other("Something ugly.")))
363                .map_err(|e| e.replace("Get replaced. But keep its linkage."))?;
364            Ok(())
365        }();
366    }
367
368    #[test]
369    #[allow(non_snake_case)]
370    fn test__link_conversion__to_error_link_non_string() {
371        let _ = || -> Result<(), ErrorLink_<i32>> {
372            Err::<(), _>(ErrorLink_::new(88))?;
373            Err::<(), _>(44)?;
374            Err::<(), _>(ErrorLink_::<i8>::new(8)).me_as_link()?;
375            Ok(())
376        }();
377    }
378
379    #[test]
380    #[allow(non_snake_case)]
381    fn test__adding_link__to_error_link_non_string() {
382        let _ = || -> Result<(), ErrorLink_<i32>> {
383            Err::<(), _>(ErrorLink_::new_string(""))
384                .me_link(100)?;
385            Ok(())
386        }();
387    }
388
389    #[test]
390    #[allow(non_snake_case)]
391    fn test__replacing_payload__to_error_link_non_string() {
392        let _ = || -> Result<(), ErrorLink_<i32>> {
393            Err::<(), _>(ErrorLink_::<std::io::Error>::new(std::io::Error::other("Something ugly.")))
394                .map_err(|_| ErrorLink_::new(3))?;
395            Err::<(), _>(ErrorLink_::<std::io::Error>::new(std::io::Error::other("Something ugly.")))
396                .map_err(|e| e.replace(1))?;
397            Ok(())
398        }();
399    }
400}
401
402#[derive(Debug)]
403#[deprecated(since = "0.3.0", note="use `NextLink` instead")]
404pub enum ErrorLink {
405    Severed(Backtrace),
406    Continued(String, Box<ErrorLink>)
407}
408
409#[allow(deprecated)]
410impl ErrorLink {
411    pub fn severed() -> Self {
412        Self::Severed(Backtrace::capture())
413    }
414
415    pub fn continued(
416        error_message: impl Into<String>, 
417        next_link: impl Into<Box<ErrorLink>>
418    ) -> Self {
419        Self::Continued(error_message.into(), next_link.into())
420    }
421}
422
423#[derive(Debug)]
424#[deprecated(since = "0.3.0", note="use `ErrorLink_` instead")]
425#[allow(deprecated)]
426pub struct ErrorChain<T: Display>(pub T, pub ErrorLink);
427
428#[allow(deprecated)]
429impl<T: std::error::Error> From<T> for ErrorChain<String> {
430    fn from(value: T) -> Self {
431        ErrorChain(value.to_string(), ErrorLink::severed())
432    }
433}
434
435#[allow(deprecated)]
436impl ErrorChain<String> {
437    pub fn start(error_message: impl Into<String>) -> Self {
438        Self(error_message.into(), ErrorLink::severed())
439    }
440
441    pub fn add<T: Display>(error_message: impl Into<String>, current_chain: ErrorChain<T>) -> Self {
442        Self::add_fn(error_message)(current_chain)
443    }
444
445    pub fn add_fn<T: Display>(error_message: impl Into<String>) -> impl FnOnce(ErrorChain<T>) -> Self { 
446        move |current_chain| {
447            Self(
448                error_message.into(),
449                ErrorLink::continued(current_chain.0.to_string(), current_chain.1)
450            )
451        }
452    }
453
454    pub fn onboard<T: Display>(error_message: impl Into<String>, underlying_error: T) -> Self { 
455        Self::onboard_fn(error_message)(underlying_error)
456    }
457
458    pub fn onboard_fn<T: Display>(error_message: impl Into<String>) -> impl FnOnce(T) -> Self { 
459        move |underlying_error| {
460            Self(
461                error_message.into(),
462                ErrorLink::continued(underlying_error.to_string(), Box::new(ErrorLink::severed())) 
463            )
464        }
465    }
466
467    pub fn link(error_message: impl Into<String>, current_chain: impl Into<Self>) -> Self {
468        ErrorChain::link_fn(error_message)(current_chain)
469    }
470
471    pub fn link_fn<T: Into<Self>>(error_message: impl Into<String>) -> impl FnOnce(T) -> Self {
472        move |current_chain| {
473            let current_chain = current_chain.into();
474            Self(
475                error_message.into(), 
476                ErrorLink::continued(current_chain.0, current_chain.1)
477            )
478        }
479    }
480}
481
482#[allow(deprecated)]
483impl<T: std::fmt::Display> std::fmt::Display for ErrorChain<T> {
484    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
485        write!(f, "Link no. 0: {}\n", self.0)?;
486        let mut error_link = &self.1;
487        for error_number in 1.. {
488            error_link = match error_link {
489                ErrorLink::Severed(end_backtrace) => {
490                    write!(
491                        f, "Approximate backtrace of link no. {}:\n{end_backtrace}", 
492                        error_number - 1
493                    )?;
494                    break;
495                }, 
496                ErrorLink::Continued(error_message, error_link) => {
497                    write!(f, "Link no. {error_number}: {error_message}\n")?;
498                    error_link
499                },
500            }
501        }
502
503        Ok(())
504    }
505}
506
507pub trait LinkableResult1of2<OkVariant> {
508    fn me_link<ToPayload: Display>(self, error_payload: impl Into<ToPayload>)
509    -> Result<OkVariant, ErrorLink_<ToPayload>>;
510    fn me_as_slink(self) -> Result<OkVariant, ErrorLink_<String>>;
511}
512
513#[cfg(feature = "nightly")]
514impl<OkVariant, ErrorVariant: Display> LinkableResult1of2<OkVariant>
515for Result<OkVariant, ErrorVariant> {
516    default fn me_link<ToPayload: Display>(self, error_payload: impl Into<ToPayload>)
517    -> Result<OkVariant, ErrorLink_<ToPayload>> {
518        self.map_err(|e| {
519            let next_link = Box::new(ErrorLink_(
520                e.to_string(),
521                NextLink::None(Backtrace::capture())
522            ));
523            ErrorLink_(error_payload.into(), NextLink::Some(next_link))
524        })
525    }
526
527    default fn me_as_slink(self) -> Result<OkVariant, ErrorLink_<String>> {
528        self.map_err(|e| ErrorLink_(
529            e.to_string(),
530            NextLink::None(Backtrace::capture())
531        ))
532    }
533}
534
535impl<OkVariant, FromPayload: Display> LinkableResult1of2<OkVariant>
536for Result<OkVariant, ErrorLink_<FromPayload>> {
537    fn me_link<ToPayload: Display>(self, error_payload: impl Into<ToPayload>)
538    -> Result<OkVariant, ErrorLink_<ToPayload>> {
539        self.map_err(|e| {
540            let next_link = Box::new(ErrorLink_(e.0.to_string(), e.1));
541            ErrorLink_(error_payload.into(), NextLink::Some(next_link))
542        })
543    }
544
545    fn me_as_slink(self) -> Result<OkVariant, ErrorLink_<String>> {
546        self.map_err(|e| ErrorLink_(e.0.to_string(), e.1))
547    }
548}
549
550pub trait LinkableResult2of2<OkVariant, FromPayload: Display> {
551    fn me_as_link<ToPayload: From<FromPayload> + Display>(self)
552    -> Result<OkVariant, ErrorLink_<ToPayload>>;
553}
554
555impl<OkVariant, FromPayload: Display> LinkableResult2of2<OkVariant, FromPayload>
556for Result<OkVariant, ErrorLink_<FromPayload>> {
557    fn me_as_link<ToPayload: From<FromPayload> + Display>(self)
558    -> Result<OkVariant, ErrorLink_<ToPayload>> {
559        self.map_err(|e| ErrorLink_(e.0.into(), e.1))
560    }
561}
562
563impl<P: Display> From<P> for ErrorLink_<P> {
564    fn from(value: P) -> Self {
565        ErrorLink_(value, NextLink::None(Backtrace::capture()))
566    }
567}
568
569#[cfg(feature = "nightly")]
570pub trait ResultExt<OkVariant, ToPayload: Display> {
571    fn me_l(self, error_payload: impl Into<ToPayload>)
572    -> Result<OkVariant, ErrorLink_<ToPayload>>;
573    fn me_al(self) -> Result<OkVariant, ErrorLink_<ToPayload>>;
574}
575
576#[cfg(feature = "nightly")]
577impl<OkVariant, ErrorVariant: Display> ResultExt<OkVariant, String> 
578for Result<OkVariant, ErrorVariant> {
579    default fn me_l(self, error_payload: impl Into<String>)
580    -> Result<OkVariant, ErrorLink_<String>> {
581        self.map_err(|e| {
582            let next_link = Box::new(ErrorLink_(
583                e.to_string(), 
584                NextLink::None(Backtrace::capture()))
585            );
586            ErrorLink_(error_payload.into(), NextLink::Some(next_link))
587        })
588    }
589
590    default fn me_al(self) -> Result<OkVariant, ErrorLink_<String>> {
591        self.map_err(|e| ErrorLink_(
592            e.to_string(),
593            NextLink::None(Backtrace::capture())
594        ))
595    }
596}
597
598#[cfg(feature = "nightly")]
599impl<OkVariant> ResultExt<OkVariant, String> 
600for Result<OkVariant, String> {
601    fn me_l(self, error_payload: impl Into<String>)
602    -> Result<OkVariant, ErrorLink_<String>> {
603        self.map_err(|e| {
604            let next_link = Box::new(ErrorLink_(e, 
605                NextLink::None(Backtrace::capture()))
606            );
607            ErrorLink_(error_payload.into(), NextLink::Some(next_link))
608        })
609    }
610
611    fn me_al(self) -> Result<OkVariant, ErrorLink_<String>> {
612        self.map_err(|e| ErrorLink_(
613            e,
614            NextLink::None(Backtrace::capture())
615        ))
616    }
617}
618
619#[cfg(feature = "nightly")]
620impl<OkVariant, FromPayload: Display> ResultExt<OkVariant, String> 
621for Result<OkVariant, ErrorLink_<FromPayload>> {
622    default fn me_l(self, error_payload: impl Into<String>)
623    -> Result<OkVariant, ErrorLink_<String>> {
624        self.map_err(|e| {
625            let next_link = Box::new(ErrorLink_(e.0.to_string(), e.1));
626            ErrorLink_(
627                error_payload.into(),
628                NextLink::Some(next_link)
629            )
630        })
631    }
632
633    default fn me_al(self) -> Result<OkVariant, ErrorLink_<String>> {
634        self.map_err(|e| ErrorLink_(e.0.to_string(), e.1))
635    }
636}
637
638#[cfg(feature = "nightly")]
639impl<OkVariant> ResultExt<OkVariant, String> 
640for Result<OkVariant, ErrorLink_<String>> {
641    fn me_l(self, error_payload: impl Into<String>)
642    -> Result<OkVariant, ErrorLink_<String>> {
643        self.map_err(|e| ErrorLink_(
644            error_payload.into(),
645            NextLink::Some(Box::new(e))
646        ))
647    }
648
649    fn me_al(self) -> Result<OkVariant, ErrorLink_<String>> {
650        self
651    }
652}
653
654#[derive(Debug)]
655pub enum NextLink {
656    None(Backtrace),
657    Some(Box<ErrorLink_<String>>)
658}
659
660#[derive(Debug)]
661pub struct ErrorLink_<Payload: Display>(pub Payload, pub NextLink);
662
663impl<Payload: Display> ErrorLink_<Payload> {
664    pub fn new(error_payload: impl Into<Payload>) -> Self {
665        Self(error_payload.into(), NextLink::None(Backtrace::capture()))
666    }
667
668    pub fn replace<NewPayload: Display>(
669        self, error_payload: impl Into<NewPayload>
670    ) -> ErrorLink_<NewPayload>{
671        ErrorLink_(error_payload.into(), self.1)
672    }
673
674    pub fn link<ToPayload: Display>(self, error_payload: impl Into<ToPayload>) -> ErrorLink_<ToPayload> {
675        Self::link_fn(error_payload)(self)
676    }
677
678    pub fn link_fn<ToPayload: Display>(error_payload: impl Into<ToPayload>) -> impl FnOnce(Self) -> ErrorLink_<ToPayload> {
679        move |underlying_error| {
680            let next_link = Box::new(ErrorLink_(underlying_error.0.to_string(), underlying_error.1));
681            ErrorLink_(error_payload.into(), NextLink::Some(next_link))
682        }
683    }
684
685    pub fn as_link<ToPayload: From<Payload> + Display>(self) -> ErrorLink_<ToPayload> {
686        ErrorLink_(self.0.into(), self.1)
687    }
688}
689
690impl ErrorLink_<String> {
691    pub fn new_string(error_message: impl Into<String>) -> Self {
692        Self(error_message.into(), NextLink::None(Backtrace::capture()))
693    }
694}
695
696pub trait ErrorLinkable<Self_, Payload: Display>: Any + Display {
697    fn link(self, error_payload: impl Into<Payload>) -> ErrorLink_<Payload>;
698    fn link_fn(error_payload: impl Into<Payload>) -> impl FnOnce(Self_) -> ErrorLink_<Payload>;
699    fn as_link(self) -> ErrorLink_<Payload>;
700}
701
702impl<T: Any + Display> ErrorLinkable<T, String> for T {
703    fn link(self, error_message: impl Into<String>) -> ErrorLink_<String> {
704        Self::link_fn(error_message)(self)
705    }
706
707    fn link_fn(error_message: impl Into<String>) -> impl FnOnce(Self) -> ErrorLink_<String> {
708        move |underlying_error| {
709            let next_link = Box::new(ErrorLink_(
710                String::from(underlying_error.to_string()), 
711                NextLink::None(Backtrace::capture())
712            ));
713            ErrorLink_(error_message.into(), NextLink::Some(next_link))
714        }
715    }
716
717    fn as_link(self) -> ErrorLink_<String> {
718        ErrorLink_(
719            self.to_string(),
720            NextLink::None(Backtrace::capture())
721        )
722    }
723}
724
725impl<Payload: Display> Display for ErrorLink_<Payload> {
726    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
727        write!(f, "An error occurred.\n")?;
728        write!(f, "Link no. 0: {}\n", self.0)?;
729        let mut next_link = &self.1;
730        for error_number in 1.. {
731            next_link = match next_link {
732                NextLink::None(end_backtrace) => {
733                    write!(
734                        f, "Approximate backtrace of link no. {}:\n{end_backtrace}", 
735                        error_number - 1
736                    )?;
737                    break;
738                }, 
739                NextLink::Some(error_link) => {
740                    write!(f, "Link no. {error_number}: {}\n", error_link.0)?;
741                    &error_link.1
742                },
743            }
744        }
745
746        Ok(())
747    }
748}
749
750impl<Payload: Display + Debug> std::error::Error for ErrorLink_<Payload> {
751    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
752        match &self.1 {
753            NextLink::None(_) => None,
754            NextLink::Some(next_link) => Some(next_link)
755        }
756    }
757}