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