in starlark_derive/src/attrs.rs [90:182]
fn expand_attrs_derive(data: Data, name: Ident) -> Result<proc_macro2::TokenStream> {
let fields: Vec<_> = match data {
Data::Struct(s) => Ok(s.fields.iter().cloned().collect()),
Data::Enum(e) => Err(Error::new(
e.enum_token.span(),
"#[derive(StarlarkAttrs)] does not support enums",
)),
Data::Union(u) => Err(Error::new(
u.union_token.span(),
"#[derive(StarlarkAttrs)] does not support unions",
)),
}?;
let expose_fields: Vec<Field> = fields
.into_iter()
.map(|field| {
match field_attr(&field, "starlark") {
// by default, include all fields
None => Ok(Field {
ident: field.ident.unwrap(),
starlark_args: vec![],
ty: field.ty,
}),
Some(attr) => match attr.parse_meta() {
Ok(Meta::List(lst)) => {
let starlark_args = lst
.nested
.iter()
.map(|m| match m {
NestedMeta::Meta(Meta::Path(p)) => p
.get_ident()
.ok_or_else(|| Error::new(m.span(), STARLARK_ATTR_ERR_MSG))
.map(|i| i.clone()),
_ => Err(Error::new(m.span(), STARLARK_ATTR_ERR_MSG)),
})
.collect::<Result<_>>()?;
Ok(Field {
ident: field.ident.unwrap(),
starlark_args,
ty: field.ty,
})
}
Ok(_) => Err(Error::new(attr.span(), "starlark attr must parse as list")),
Err(e) => Err(e),
},
}
})
.filter(|f| f.as_ref().map(|f| !f.skip()).unwrap_or(true))
.collect::<Result<_>>()?;
let has_attr_items = expose_fields.iter().map(|f| f.has_attr_match_item());
let has_attr = quote! {
pub(crate) fn attrs_has_attr(&self, attr: &str) -> bool {
match attr {
#(#has_attr_items),*,
_ => false,
}
}
};
let get_attr_items = expose_fields.iter().map(|f| f.get_attr_match_item());
let get_attr = quote! {
pub(crate) fn attrs_get_attr<'v>(&self, attr: &str, heap: &'v starlark::values::Heap) -> Option<starlark::values::Value<'v>> {
match attr {
#(#get_attr_items),*,
_ => None,
}
}
};
let dir_names = expose_fields.iter().map(|f| f.ident.to_string());
let dir_attr = quote! {
pub(crate) fn attrs_dir_attr(&self) -> Vec<String> {
vec![
#(#dir_names.to_owned()),*
]
}
};
let expanded = quote! {
// Unfortunately, we can't actually implement the direct methods for
// `StarlarkValue`, because then we would have conflicting
// implementations. However, we can implement wrappers in another
// proc-macro that can then be called.
impl #name {
#has_attr
#get_attr
#dir_attr
}
};
Ok(expanded)
}