blob: 5a1ba3fed49ec16c14c25b707a8c1504610c274d [file] [log] [blame]
use crate::ir::comp::{CompInfo, CompKind, Field, FieldMethods};
use crate::ir::context::BindgenContext;
use crate::ir::item::{IsOpaque, Item};
use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
use proc_macro2;
/// Generate a manual implementation of `PartialEq` trait for the
/// specified compound type.
pub fn gen_partialeq_impl(
ctx: &BindgenContext,
comp_info: &CompInfo,
item: &Item,
ty_for_impl: &proc_macro2::TokenStream,
) -> Option<proc_macro2::TokenStream> {
let mut tokens = vec![];
if item.is_opaque(ctx, &()) {
tokens.push(quote! {
&self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..]
});
} else if comp_info.kind() == CompKind::Union {
assert!(!ctx.options().rust_features().untagged_union);
tokens.push(quote! {
&self.bindgen_union_field[..] == &other.bindgen_union_field[..]
});
} else {
for base in comp_info.base_members().iter() {
if !base.requires_storage(ctx) {
continue;
}
let ty_item = ctx.resolve_item(base.ty);
let field_name = &base.field_name;
if ty_item.is_opaque(ctx, &()) {
let field_name = ctx.rust_ident(field_name);
tokens.push(quote! {
&self. #field_name [..] == &other. #field_name [..]
});
} else {
tokens.push(gen_field(ctx, ty_item, field_name));
}
}
for field in comp_info.fields() {
match *field {
Field::DataMember(ref fd) => {
let ty_item = ctx.resolve_item(fd.ty());
let name = fd.name().unwrap();
tokens.push(gen_field(ctx, ty_item, name));
}
Field::Bitfields(ref bu) => {
for bitfield in bu.bitfields() {
if let Some(_) = bitfield.name() {
let getter_name = bitfield.getter_name();
let name_ident = ctx.rust_ident_raw(getter_name);
tokens.push(quote! {
self.#name_ident () == other.#name_ident ()
});
}
}
}
}
}
}
Some(quote! {
fn eq(&self, other: & #ty_for_impl) -> bool {
#( #tokens )&&*
}
})
}
fn gen_field(
ctx: &BindgenContext,
ty_item: &Item,
name: &str,
) -> proc_macro2::TokenStream {
fn quote_equals(
name_ident: proc_macro2::Ident,
) -> proc_macro2::TokenStream {
quote! { self.#name_ident == other.#name_ident }
}
let name_ident = ctx.rust_ident(name);
let ty = ty_item.expect_type();
match *ty.kind() {
TypeKind::Void |
TypeKind::NullPtr |
TypeKind::Int(..) |
TypeKind::Complex(..) |
TypeKind::Float(..) |
TypeKind::Enum(..) |
TypeKind::TypeParam |
TypeKind::UnresolvedTypeRef(..) |
TypeKind::Reference(..) |
TypeKind::ObjCInterface(..) |
TypeKind::ObjCId |
TypeKind::ObjCSel |
TypeKind::Comp(..) |
TypeKind::Pointer(_) |
TypeKind::Function(..) |
TypeKind::Opaque => quote_equals(name_ident),
TypeKind::TemplateInstantiation(ref inst) => {
if inst.is_opaque(ctx, &ty_item) {
quote! {
&self. #name_ident [..] == &other. #name_ident [..]
}
} else {
quote_equals(name_ident)
}
}
TypeKind::Array(_, len) => {
if len <= RUST_DERIVE_IN_ARRAY_LIMIT ||
ctx.options().rust_features().larger_arrays
{
quote_equals(name_ident)
} else {
quote! {
&self. #name_ident [..] == &other. #name_ident [..]
}
}
}
TypeKind::Vector(_, len) => {
let self_ids = 0..len;
let other_ids = 0..len;
quote! {
#(self.#self_ids == other.#other_ids &&)* true
}
}
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) |
TypeKind::BlockPointer(t) => {
let inner_item = ctx.resolve_item(t);
gen_field(ctx, inner_item, name)
}
}
}