in starlark_derive/src/parse.rs [137:206]
fn process_attributes(span: Span, xs: Vec<Attribute>) -> syn::Result<ProcessedAttributes> {
const ERROR: &str = "Couldn't parse attribute. \
Expected `#[starlark(type(\"ty\")]`, \
`#[starlark(attribute)]` or `#[starlark(speculative_exec_safe)]`";
let mut attrs = Vec::with_capacity(xs.len());
let mut is_attribute = false;
let mut type_attribute = None;
let mut speculative_exec_safe = false;
let mut doc_attrs = Vec::new();
for x in xs {
if x.path.is_ident("starlark") {
match x.parse_meta()? {
Meta::List(list) => {
assert!(list.path.is_ident("starlark"));
for nested in list.nested {
match nested {
NestedMeta::Lit(lit) => {
return Err(syn::Error::new(lit.span(), ERROR));
}
NestedMeta::Meta(meta) => {
if meta.path().is_ident("type") {
match meta {
Meta::List(list) => {
if list.nested.len() != 1 {
return Err(syn::Error::new(list.span(), ERROR));
}
type_attribute =
Some(list.nested.first().unwrap().clone());
}
_ => return Err(syn::Error::new(meta.span(), ERROR)),
}
} else if meta.path().is_ident("attribute") {
is_attribute = true;
} else if meta.path().is_ident("speculative_exec_safe") {
speculative_exec_safe = true;
} else {
return Err(syn::Error::new(meta.span(), ERROR));
}
}
}
}
}
_ => return Err(syn::Error::new(x.span(), ERROR)),
}
} else if let Some(ds) = is_attribute_docstring(&x) {
doc_attrs.push(ds);
// Important the attributes remain tagged to the function, so the test annotations
// are present, and thus the doc test works properly.
attrs.push(x);
} else {
attrs.push(x);
}
}
if is_attribute && type_attribute.is_some() {
return Err(syn::Error::new(span, "Can't be an attribute with a .type"));
}
let docstring = if !doc_attrs.is_empty() {
Some(doc_attrs.join("\n"))
} else {
None
};
Ok(ProcessedAttributes {
is_attribute,
type_attribute,
speculative_exec_safe,
docstring,
attrs,
})
}