1 use crate::ast::{Enum, Field, Struct, Variant};
2 use syn::{Member, Type};
3 
4 impl Struct<'_> {
from_field(&self) -> Option<&Field>5     pub(crate) fn from_field(&self) -> Option<&Field> {
6         from_field(&self.fields)
7     }
8 
source_field(&self) -> Option<&Field>9     pub(crate) fn source_field(&self) -> Option<&Field> {
10         source_field(&self.fields)
11     }
12 
backtrace_field(&self) -> Option<&Field>13     pub(crate) fn backtrace_field(&self) -> Option<&Field> {
14         backtrace_field(&self.fields)
15     }
16 
distinct_backtrace_field(&self) -> Option<&Field>17     pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
18         let backtrace_field = self.backtrace_field()?;
19         distinct_backtrace_field(backtrace_field, self.from_field())
20     }
21 }
22 
23 impl Enum<'_> {
has_source(&self) -> bool24     pub(crate) fn has_source(&self) -> bool {
25         self.variants
26             .iter()
27             .any(|variant| variant.source_field().is_some() || variant.attrs.transparent.is_some())
28     }
29 
has_backtrace(&self) -> bool30     pub(crate) fn has_backtrace(&self) -> bool {
31         self.variants
32             .iter()
33             .any(|variant| variant.backtrace_field().is_some())
34     }
35 
has_display(&self) -> bool36     pub(crate) fn has_display(&self) -> bool {
37         self.attrs.display.is_some()
38             || self.attrs.transparent.is_some()
39             || self
40                 .variants
41                 .iter()
42                 .any(|variant| variant.attrs.display.is_some())
43             || self
44                 .variants
45                 .iter()
46                 .all(|variant| variant.attrs.transparent.is_some())
47     }
48 }
49 
50 impl Variant<'_> {
from_field(&self) -> Option<&Field>51     pub(crate) fn from_field(&self) -> Option<&Field> {
52         from_field(&self.fields)
53     }
54 
source_field(&self) -> Option<&Field>55     pub(crate) fn source_field(&self) -> Option<&Field> {
56         source_field(&self.fields)
57     }
58 
backtrace_field(&self) -> Option<&Field>59     pub(crate) fn backtrace_field(&self) -> Option<&Field> {
60         backtrace_field(&self.fields)
61     }
62 
distinct_backtrace_field(&self) -> Option<&Field>63     pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
64         let backtrace_field = self.backtrace_field()?;
65         distinct_backtrace_field(backtrace_field, self.from_field())
66     }
67 }
68 
69 impl Field<'_> {
is_backtrace(&self) -> bool70     pub(crate) fn is_backtrace(&self) -> bool {
71         type_is_backtrace(self.ty)
72     }
73 }
74 
from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>>75 fn from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
76     for field in fields {
77         if field.attrs.from.is_some() {
78             return Some(field);
79         }
80     }
81     None
82 }
83 
source_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>>84 fn source_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
85     for field in fields {
86         if field.attrs.from.is_some() || field.attrs.source.is_some() {
87             return Some(field);
88         }
89     }
90     for field in fields {
91         match &field.member {
92             Member::Named(ident) if ident == "source" => return Some(field),
93             _ => {}
94         }
95     }
96     None
97 }
98 
backtrace_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>>99 fn backtrace_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
100     for field in fields {
101         if field.attrs.backtrace.is_some() {
102             return Some(field);
103         }
104     }
105     for field in fields {
106         if field.is_backtrace() {
107             return Some(field);
108         }
109     }
110     None
111 }
112 
113 // The #[backtrace] field, if it is not the same as the #[from] field.
distinct_backtrace_field<'a, 'b>( backtrace_field: &'a Field<'b>, from_field: Option<&Field>, ) -> Option<&'a Field<'b>>114 fn distinct_backtrace_field<'a, 'b>(
115     backtrace_field: &'a Field<'b>,
116     from_field: Option<&Field>,
117 ) -> Option<&'a Field<'b>> {
118     if from_field.map_or(false, |from_field| {
119         from_field.member == backtrace_field.member
120     }) {
121         None
122     } else {
123         Some(backtrace_field)
124     }
125 }
126 
type_is_backtrace(ty: &Type) -> bool127 fn type_is_backtrace(ty: &Type) -> bool {
128     let path = match ty {
129         Type::Path(ty) => &ty.path,
130         _ => return false,
131     };
132 
133     let last = path.segments.last().unwrap();
134     last.ident == "Backtrace" && last.arguments.is_empty()
135 }
136