fn process_attributes()

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,
    })
}