• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::ast::{Enum, Field, Struct, Variant};
2 use crate::unraw::MemberUnraw;
3 use proc_macro2::Span;
4 use syn::Type;
5 
6 impl Struct<'_> {
from_field(&self) -> Option<&Field>7     pub(crate) fn from_field(&self) -> Option<&Field> {
8         from_field(&self.fields)
9     }
10 
source_field(&self) -> Option<&Field>11     pub(crate) fn source_field(&self) -> Option<&Field> {
12         source_field(&self.fields)
13     }
14 
backtrace_field(&self) -> Option<&Field>15     pub(crate) fn backtrace_field(&self) -> Option<&Field> {
16         backtrace_field(&self.fields)
17     }
18 
distinct_backtrace_field(&self) -> Option<&Field>19     pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
20         let backtrace_field = self.backtrace_field()?;
21         distinct_backtrace_field(backtrace_field, self.from_field())
22     }
23 }
24 
25 impl Enum<'_> {
has_source(&self) -> bool26     pub(crate) fn has_source(&self) -> bool {
27         self.variants
28             .iter()
29             .any(|variant| variant.source_field().is_some() || variant.attrs.transparent.is_some())
30     }
31 
has_backtrace(&self) -> bool32     pub(crate) fn has_backtrace(&self) -> bool {
33         self.variants
34             .iter()
35             .any(|variant| variant.backtrace_field().is_some())
36     }
37 
has_display(&self) -> bool38     pub(crate) fn has_display(&self) -> bool {
39         self.attrs.display.is_some()
40             || self.attrs.transparent.is_some()
41             || self.attrs.fmt.is_some()
42             || self
43                 .variants
44                 .iter()
45                 .any(|variant| variant.attrs.display.is_some() || variant.attrs.fmt.is_some())
46             || self
47                 .variants
48                 .iter()
49                 .all(|variant| variant.attrs.transparent.is_some())
50     }
51 }
52 
53 impl Variant<'_> {
from_field(&self) -> Option<&Field>54     pub(crate) fn from_field(&self) -> Option<&Field> {
55         from_field(&self.fields)
56     }
57 
source_field(&self) -> Option<&Field>58     pub(crate) fn source_field(&self) -> Option<&Field> {
59         source_field(&self.fields)
60     }
61 
backtrace_field(&self) -> Option<&Field>62     pub(crate) fn backtrace_field(&self) -> Option<&Field> {
63         backtrace_field(&self.fields)
64     }
65 
distinct_backtrace_field(&self) -> Option<&Field>66     pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
67         let backtrace_field = self.backtrace_field()?;
68         distinct_backtrace_field(backtrace_field, self.from_field())
69     }
70 }
71 
72 impl Field<'_> {
is_backtrace(&self) -> bool73     pub(crate) fn is_backtrace(&self) -> bool {
74         type_is_backtrace(self.ty)
75     }
76 
source_span(&self) -> Span77     pub(crate) fn source_span(&self) -> Span {
78         if let Some(source_attr) = &self.attrs.source {
79             source_attr.span
80         } else if let Some(from_attr) = &self.attrs.from {
81             from_attr.span
82         } else {
83             self.member.span()
84         }
85     }
86 }
87 
from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>>88 fn from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
89     for field in fields {
90         if field.attrs.from.is_some() {
91             return Some(field);
92         }
93     }
94     None
95 }
96 
source_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>>97 fn source_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
98     for field in fields {
99         if field.attrs.from.is_some() || field.attrs.source.is_some() {
100             return Some(field);
101         }
102     }
103     for field in fields {
104         match &field.member {
105             MemberUnraw::Named(ident) if ident == "source" => return Some(field),
106             _ => {}
107         }
108     }
109     None
110 }
111 
backtrace_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>>112 fn backtrace_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
113     for field in fields {
114         if field.attrs.backtrace.is_some() {
115             return Some(field);
116         }
117     }
118     for field in fields {
119         if field.is_backtrace() {
120             return Some(field);
121         }
122     }
123     None
124 }
125 
126 // 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>>127 fn distinct_backtrace_field<'a, 'b>(
128     backtrace_field: &'a Field<'b>,
129     from_field: Option<&Field>,
130 ) -> Option<&'a Field<'b>> {
131     if from_field.map_or(false, |from_field| {
132         from_field.member == backtrace_field.member
133     }) {
134         None
135     } else {
136         Some(backtrace_field)
137     }
138 }
139 
type_is_backtrace(ty: &Type) -> bool140 fn type_is_backtrace(ty: &Type) -> bool {
141     let path = match ty {
142         Type::Path(ty) => &ty.path,
143         _ => return false,
144     };
145 
146     let last = path.segments.last().unwrap();
147     last.ident == "Backtrace" && last.arguments.is_empty()
148 }
149