diff options
author | Sergey Pepyakin <s.pepyakin@gmail.com> | 2017-09-23 01:48:19 +0300 |
---|---|---|
committer | Sergey Pepyakin <s.pepyakin@gmail.com> | 2017-10-03 00:37:09 +0300 |
commit | dde9376cf32511debbb4b0e068c6ca776d13349b (patch) | |
tree | d47244770a0fe187e7c2fec0db0366cfdbd17092 /src/codegen/impl_partialeq.rs | |
parent | c66598d28b7ffe8b8e30a58e9268db50dd109986 (diff) |
Derive partialeq "manually" when possible
Remove derive-partialeq-template-inst test.
Add comments.
Don't implement PartialEq for incomplete arrays
Handle opaque bases and template instantiations
Extract constrain_type.
Extract `is whitelisted?` check
Add failing partialeq-anonfield
join for comps
Fix: return insert if not whitelisted
Delegate TypeRefs and alias to constrain_join.
Delegate Template instantiations to constrain_join
Add derive-partialeq-pointer.hpp test
Update comment.
Fix layout alignment larger that array limit
Add missing test for derive-partialeq-anonfield.rs
Clean
Clean
Fix typo in opaque-template-inst-member test
Remove redudant stmt
Add comment on can_supersede.
Format impl_partialeq and leave a comment
Extract requires_storage into it's own function.
Clean
Diffstat (limited to 'src/codegen/impl_partialeq.rs')
-rw-r--r-- | src/codegen/impl_partialeq.rs | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/codegen/impl_partialeq.rs b/src/codegen/impl_partialeq.rs new file mode 100644 index 00000000..15a8953e --- /dev/null +++ b/src/codegen/impl_partialeq.rs @@ -0,0 +1,121 @@ + +use ir::comp::{CompInfo, CompKind, Field, FieldMethods}; +use ir::context::BindgenContext; +use ir::item::{IsOpaque, Item}; +use ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; +use quote; + +/// 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: "e::Tokens, +) -> Option<quote::Tokens> { + 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 { + 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() { + let name_ident = ctx.rust_ident_raw(bitfield.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) -> quote::Tokens { + fn quote_equals(name_ident: quote::Ident) -> quote::Tokens { + 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::BlockPointer | + 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::ResolvedTypeRef(t) | + TypeKind::TemplateAlias(t, _) | + TypeKind::Alias(t) => { + let inner_item = ctx.resolve_item(t); + gen_field(ctx, inner_item, name) + } + } +} |