abi_stable_derive/sabi_trait/
attribute_parsing.rs
1use super::{TraitDefinition, *};
2
3use as_derive_utils::parse_utils::ParseBufferExt;
4
5use syn::{parse::ParseBuffer, Attribute, ItemTrait, TraitItem, TraitItemMethod};
6
7#[allow(unused_imports)]
8use core_extensions::SelfOps;
9
10use crate::{arenas::Arenas, attribute_parsing::contains_doc_hidden, utils::LinearResult};
11
12pub(crate) struct SabiTraitOptions<'a> {
14 pub(crate) debug_print_trait: bool,
16 pub(crate) debug_output_tokens: bool,
17 pub(crate) doc_hidden_attr: Option<&'a TokenStream2>,
18 pub(crate) trait_definition: TraitDefinition<'a>,
19}
20
21impl<'a> SabiTraitOptions<'a> {
22 fn new(
23 trait_: &'a ItemTrait,
24 this: SabiTraitAttrs<'a>,
25 arenas: &'a Arenas,
26 ctokens: &'a CommonTokens,
27 ) -> Result<Self, syn::Error> {
28 let doc_hidden_attr = if this.is_hidden {
29 Some(arenas.alloc(quote!(#[doc(hidden)])))
30 } else {
31 None
32 };
33
34 Ok(Self {
35 debug_print_trait: this.debug_print_trait,
36 debug_output_tokens: this.debug_output_tokens,
37 doc_hidden_attr,
38 trait_definition: TraitDefinition::new(trait_, this, arenas, ctokens)?,
39 })
40 }
41}
42
43mod kw {
44 syn::custom_keyword! {no_default_fallback}
45 syn::custom_keyword! {debug_print_trait}
46 syn::custom_keyword! {debug_output_tokens}
47 syn::custom_keyword! {use_dyntrait}
48 syn::custom_keyword! {use_dyn_trait}
49 syn::custom_keyword! {no_trait_impl}
50}
51
52#[derive(Debug, Clone, Default)]
56pub(crate) struct OwnedDeriveAndOtherAttrs {
57 pub(crate) derive_attrs: Vec<Attribute>,
59 pub(crate) other_attrs: Vec<Attribute>,
61}
62
63#[derive(Debug, Clone)]
67pub(crate) struct MethodWithAttrs<'a> {
68 pub(crate) attrs: OwnedDeriveAndOtherAttrs,
70 pub(crate) item: &'a TraitItemMethod,
71}
72
73impl<'a> MethodWithAttrs<'a> {
74 fn new(item: &'a TraitItemMethod) -> Self {
76 Self {
77 attrs: OwnedDeriveAndOtherAttrs {
78 derive_attrs: Vec::new(),
79 other_attrs: Vec::new(),
80 },
81 item,
82 }
83 }
84}
85
86#[derive(Default)]
90pub(super) struct SabiTraitAttrs<'a> {
91 pub(super) debug_print_trait: bool,
93 pub(super) attrs: OwnedDeriveAndOtherAttrs,
95 pub(super) methods_with_attrs: Vec<MethodWithAttrs<'a>>,
97 pub(super) which_object: WhichObject,
100 pub(super) disable_trait_impl: bool,
102 pub(super) disable_inherent_default: Vec<bool>,
105
106 pub(super) is_hidden: bool,
107 pub(super) debug_output_tokens: bool,
108
109 pub(super) errors: LinearResult<()>,
110}
111
112#[derive(Debug, Copy, Clone)]
114enum ParseContext {
115 TraitAttr,
116 Method { index: usize },
117}
118
119pub(crate) fn parse_attrs_for_sabi_trait<'a>(
121 trait_: &'a ItemTrait,
122 arenas: &'a Arenas,
123 ctokens: &'a CommonTokens,
124) -> Result<SabiTraitOptions<'a>, syn::Error> {
125 let mut this = SabiTraitAttrs::default();
126
127 let assoc_fns: Vec<&'a TraitItemMethod> = trait_
128 .items
129 .iter()
130 .filter_map(|item| match item {
131 TraitItem::Method(x) => Some(x),
132 _ => None,
133 })
134 .collect();
135
136 this.methods_with_attrs.reserve(assoc_fns.len());
137
138 this.disable_inherent_default.resize(assoc_fns.len(), false);
139
140 parse_inner(&mut this, &*trait_.attrs, ParseContext::TraitAttr, arenas)?;
141
142 for (index, assoc_fn) in assoc_fns.iter().cloned().enumerate() {
143 this.methods_with_attrs.push(MethodWithAttrs::new(assoc_fn));
144
145 parse_inner(
146 &mut this,
147 &*assoc_fn.attrs,
148 ParseContext::Method { index },
149 arenas,
150 )?;
151 }
152
153 this.errors.take()?;
154
155 SabiTraitOptions::new(trait_, this, arenas, ctokens)
156}
157
158fn parse_inner<'a, I>(
160 this: &mut SabiTraitAttrs<'a>,
161 attrs: I,
162 pctx: ParseContext,
163 arenas: &'a Arenas,
164) -> Result<(), syn::Error>
165where
166 I: IntoIterator<Item = &'a Attribute>,
167{
168 for attr in attrs {
169 if attr.path.is_ident("sabi") {
170 attr.parse_args_with(|input: &ParseBuffer<'_>| {
171 parse_sabi_trait_attr(this, pctx, input, attr, arenas)
172 })?;
173 } else if attr.path.is_ident("doc")
174 && matches!(pctx, ParseContext::TraitAttr)
175 && syn::parse::Parser::parse2(contains_doc_hidden, attr.tokens.clone())?
176 {
177 this.is_hidden = true;
178 } else if let ParseContext::TraitAttr = pctx {
179 this.attrs.other_attrs.push(attr.clone());
180 } else if let ParseContext::Method { .. } = pctx {
181 this.methods_with_attrs
182 .last_mut()
183 .unwrap()
184 .attrs
185 .other_attrs
186 .push(attr.clone());
187 }
188 }
189 Ok(())
190}
191
192fn parse_sabi_trait_attr<'a>(
194 this: &mut SabiTraitAttrs<'a>,
195 pctx: ParseContext,
196 input: &ParseBuffer<'_>,
197 attr: &Attribute,
198 _arenas: &'a Arenas,
199) -> Result<(), syn::Error> {
200 fn push_attr(
201 this: &mut SabiTraitAttrs<'_>,
202 pctx: ParseContext,
203 input: &ParseBuffer<'_>,
204 attr: Attribute,
205 ) {
206 input.ignore_rest();
207 match pctx {
208 ParseContext::Method { .. } => {
209 this.methods_with_attrs
210 .last_mut()
211 .unwrap()
212 .attrs
213 .derive_attrs
214 .push(attr);
215 }
216 ParseContext::TraitAttr => {
217 this.attrs.derive_attrs.push(attr);
218 }
219 }
220 }
221
222 if input.check_parse(kw::no_default_fallback)? {
223 match pctx {
224 ParseContext::TraitAttr => {
225 for is_disabled in &mut this.disable_inherent_default {
226 *is_disabled = true;
227 }
228 }
229 ParseContext::Method { index } => {
230 this.disable_inherent_default[index] = true;
231 }
232 }
233 } else if input.check_parse(kw::debug_print_trait)? {
234 this.debug_print_trait = true;
235 } else if input.check_parse(kw::debug_output_tokens)? {
236 this.debug_output_tokens = true;
237 } else if let ParseContext::TraitAttr = pctx {
238 if input.check_parse(kw::use_dyntrait)? || input.check_parse(kw::use_dyn_trait)? {
239 this.which_object = WhichObject::DynTrait;
240 } else if input.check_parse(kw::no_trait_impl)? {
241 this.disable_trait_impl = true;
242 } else {
243 push_attr(this, pctx, input, attr.clone());
244 }
245 } else {
246 push_attr(this, pctx, input, attr.clone())
247 }
248 Ok(())
249}