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