in src/bindgen/ir/enumeration.rs [98:231]
fn load(
inline_tag_field: bool,
variant: &syn::Variant,
generic_params: GenericParams,
mod_cfg: Option<&Cfg>,
self_path: &Path,
enum_annotations: &AnnotationSet,
config: &Config,
) -> Result<Self, String> {
let discriminant = match variant.discriminant {
Some((_, ref expr)) => Some(Literal::load(expr)?),
None => None,
};
fn parse_fields(
inline_tag_field: bool,
fields: &syn::punctuated::Punctuated<syn::Field, syn::token::Comma>,
self_path: &Path,
inline_name: Option<&str>,
) -> Result<Vec<Field>, String> {
let mut res = Vec::new();
if inline_tag_field {
res.push(Field::from_name_and_type(
inline_name.map_or_else(|| "tag".to_string(), |name| format!("{}_tag", name)),
Type::Path(GenericPath::new(Path::new("Tag"), vec![])),
));
}
for (i, field) in fields.iter().enumerate() {
if let Some(mut ty) = Type::load(&field.ty)? {
ty.replace_self_with(self_path);
res.push(Field {
name: inline_name.map_or_else(
|| match field.ident {
Some(ref ident) => ident.unraw().to_string(),
None => i.to_string(),
},
|name| name.to_string(),
),
ty,
cfg: Cfg::load(&field.attrs),
annotations: AnnotationSet::load(&field.attrs)?,
documentation: Documentation::load(&field.attrs),
});
}
}
Ok(res)
}
let variant_cfg = Cfg::append(mod_cfg, Cfg::load(&variant.attrs));
let mut annotations = AnnotationSet::load(&variant.attrs)?;
if let Some(b) = enum_annotations.bool("derive-ostream") {
annotations.add_default("derive-ostream", AnnotationValue::Bool(b));
}
let body_rule = enum_annotations.parse_atom::<RenameRule>("rename-variant-name-fields");
let body_rule = body_rule
.as_ref()
.unwrap_or(&config.enumeration.rename_variant_name_fields);
let body = match variant.fields {
syn::Fields::Unit => VariantBody::Empty(annotations),
syn::Fields::Named(ref fields) => {
let path = Path::new(format!("{}_Body", variant.ident));
let name = body_rule
.apply(
&variant.ident.unraw().to_string(),
IdentifierType::StructMember,
)
.into_owned();
VariantBody::Body {
body: Struct::new(
path,
generic_params,
parse_fields(inline_tag_field, &fields.named, self_path, None)?,
inline_tag_field,
true,
None,
false,
None,
annotations,
Documentation::none(),
),
name,
inline: false,
inline_casts: false,
}
}
syn::Fields::Unnamed(ref fields) => {
let path = Path::new(format!("{}_Body", variant.ident));
let name = body_rule
.apply(
&variant.ident.unraw().to_string(),
IdentifierType::StructMember,
)
.into_owned();
let inline_casts = fields.unnamed.len() == 1;
// In C++ types with destructors cannot be put into unnamed structs like the
// inlining requires, and it's hard to detect such types.
// Besides that for C++ we generate casts/getters that can be used instead of
// direct field accesses and also have a benefit of being checked.
// As a result we don't currently inline variant definitions in C++ mode at all.
let inline = inline_casts && config.language != Language::Cxx;
let inline_name = if inline { Some(&*name) } else { None };
VariantBody::Body {
body: Struct::new(
path,
generic_params,
parse_fields(inline_tag_field, &fields.unnamed, self_path, inline_name)?,
inline_tag_field,
true,
None,
false,
None,
annotations,
Documentation::none(),
),
name,
inline,
inline_casts,
}
}
};
Ok(EnumVariant::new(
variant.ident.unraw().to_string(),
discriminant,
body,
variant_cfg,
Documentation::load(&variant.attrs),
))
}