syn_prelude/
to_syn_error.rs

1use std::fmt::Display;
2
3use proc_macro2::Span;
4use syn::{punctuated::Punctuated, spanned::Spanned, Error, Ident, LitStr};
5
6use crate::ToSpan;
7
8pub trait ToErr {
9    fn to_err<T>(self) -> syn::Result<T>;
10}
11
12impl ToErr for syn::Error {
13    fn to_err<T>(self) -> syn::Result<T> {
14        Err(self)
15    }
16}
17
18pub trait ToSynError {
19    fn to_syn_error<S: Display>(&self, message: S) -> Error;
20}
21
22impl ToSynError for Span {
23    fn to_syn_error<S: Display>(&self, message: S) -> Error {
24        Error::new(self.span(), message)
25    }
26}
27
28impl ToSynError for Ident {
29    fn to_syn_error<S: Display>(&self, message: S) -> Error {
30        Error::new(self.span(), message)
31    }
32}
33
34impl ToSynError for LitStr {
35    fn to_syn_error<S: Display>(&self, message: S) -> Error {
36        Error::new(self.span(), message)
37    }
38}
39
40pub trait ToOptionalSynError {
41    fn to_optional_syn_error<S: Display>(&self, message: S) -> Option<Error>;
42}
43
44impl ToOptionalSynError for Vec<Span> {
45    fn to_optional_syn_error<S: Display>(&self, message: S) -> Option<Error> {
46        let mut span: Option<Span> = None;
47        for s in self {
48            if let Some(x) = &mut span {
49                span = x.join(*s)
50            } else {
51                span = Some(*s)
52            }
53        }
54        span.map(|s| s.to_syn_error(message))
55    }
56}
57
58impl<T: ToSpan + Clone> ToOptionalSynError for Vec<Option<T>> {
59    fn to_optional_syn_error<S: Display>(&self, message: S) -> Option<Error> {
60        self.iter()
61            .map(|s| s.as_ref().map(|s| s.to_span()))
62            .reduce(|a, b| match (a, b) {
63                (None, None) => None,
64                (None, Some(b)) => Some(b.to_span()),
65                (Some(a), None) => Some(a.to_span()),
66                (Some(a), Some(b)) => a.to_span().join(b.to_span()),
67            })
68            .flatten()
69            .map(|span| span.to_syn_error(message))
70    }
71}
72
73impl<T: ToSpan, P> ToOptionalSynError for Punctuated<T, P> {
74    fn to_optional_syn_error<S: Display>(&self, message: S) -> Option<Error> {
75        if let Some(first) = self.first() {
76            let span = first.to_span();
77            Some(if let Some(last) = self.last() {
78                Error::new(span.join(last.to_span()).unwrap_or(span), message)
79            } else {
80                Error::new(span, message)
81            })
82        } else {
83            None
84        }
85    }
86}
87
88pub trait CombineSynErrors {
89    fn combine_errors(self) -> Option<syn::Error>;
90}
91
92impl CombineSynErrors for Vec<syn::Error> {
93    fn combine_errors(self) -> Option<syn::Error> {
94        let mut i = self.into_iter();
95        if let Some(mut err) = i.next() {
96            while let Some(e) = i.next() {
97                err.combine(e);
98            }
99            Some(err)
100        } else {
101            None
102        }
103    }
104}
105
106pub trait JoinSynErrors {
107    fn join_errors(self) -> syn::Result<()>;
108}
109
110impl<T> JoinSynErrors for Vec<syn::Result<T>> {
111    fn join_errors(self) -> syn::Result<()> {
112        let mut final_err: Option<syn::Error> = None;
113        let mut i = self.into_iter();
114        while let Some(res) = i.next() {
115            if let Err(err) = res {
116                if let Some(final_err) = &mut final_err {
117                    final_err.combine(err);
118                } else {
119                    final_err = Some(err);
120                }
121            }
122        }
123        if let Some(err) = final_err {
124            Err(err)
125        } else {
126            Ok(())
127        }
128    }
129}
130
131impl<T1, T2> JoinSynErrors for (syn::Result<T1>, syn::Result<T2>) {
132    fn join_errors(self) -> syn::Result<()> {
133        match self {
134            (Ok(_), Ok(_)) => Ok(()),
135            (Ok(_), Err(err2)) => Err(err2),
136            (Err(err1), Ok(_)) => Err(err1),
137            (Err(mut err1), Err(err2)) => {
138                err1.combine(err2);
139                Err(err1)
140            }
141        }
142    }
143}
144
145impl<T1, T2, T3> JoinSynErrors for (syn::Result<T1>, syn::Result<T2>, syn::Result<T3>) {
146    fn join_errors(self) -> syn::Result<()> {
147        let mut err = self.0.err();
148        if let Err(err2) = self.1 {
149            if let Some(err) = &mut err {
150                err.combine(err2);
151            } else {
152                err = Some(err2);
153            }
154        }
155        if let Err(err3) = self.2 {
156            if let Some(err) = &mut err {
157                err.combine(err3);
158            } else {
159                err = Some(err3);
160            }
161        }
162        if let Some(err) = err {
163            Err(err)
164        } else {
165            Ok(())
166        }
167    }
168}