Skip to content

Commit 86d00aa

Browse files
committed
Derive partialeq "manually" when possible
1 parent fcbe260 commit 86d00aa

29 files changed

+1422
-384
lines changed

src/codegen/impl_partialeq.rs

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
2+
use ir::comp::{CompInfo, CompKind, Field, FieldMethods};
3+
use ir::context::BindgenContext;
4+
use ir::item::{Item, IsOpaque};
5+
use ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
6+
use quote;
7+
8+
pub fn gen_partialeq_impl(ctx: &BindgenContext, comp_info: &CompInfo, item: &Item, ty_for_impl: &quote::Tokens) -> Option<quote::Tokens> {
9+
let _ty = item.expect_type();
10+
let mut tokens = vec![];
11+
12+
if item.is_opaque(ctx, &()) {
13+
tokens.push(quote! {
14+
&self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..]
15+
});
16+
} else if comp_info.kind() == CompKind::Union {
17+
tokens.push(quote! {
18+
&self.bindgen_union_field[..] == &other.bindgen_union_field[..]
19+
});
20+
} else {
21+
for base in comp_info.base_members().iter() {
22+
if base.is_virtual() {
23+
continue;
24+
}
25+
26+
let base_ty = ctx.resolve_type(base.ty);
27+
// NB: We won't include unsized types in our base chain because they
28+
// would contribute to our size given the dummy field we insert for
29+
// unsized types.
30+
if base_ty.is_unsized(ctx, &base.ty) {
31+
continue;
32+
}
33+
34+
let ty_item = ctx.resolve_item(base.ty);
35+
let field_name = &base.field_name;
36+
tokens.push(gen_field(ctx, ty_item, field_name));
37+
}
38+
39+
for field in comp_info.fields() {
40+
match *field {
41+
Field::DataMember(ref fd) => {
42+
let ty_item = ctx.resolve_item(fd.ty());
43+
let name = fd.name().unwrap();
44+
tokens.push(gen_field(ctx, ty_item, name));
45+
}
46+
Field::Bitfields(ref bu) => {
47+
for bitfield in bu.bitfields() {
48+
let name_ident = ctx.rust_ident_raw(bitfield.name());
49+
tokens.push(quote! {
50+
self.#name_ident () == other.#name_ident ()
51+
});
52+
}
53+
}
54+
}
55+
}
56+
}
57+
58+
Some(quote! {
59+
fn eq(&self, other: & #ty_for_impl) -> bool {
60+
#( #tokens )&&*
61+
}
62+
})
63+
}
64+
65+
fn gen_field(ctx: &BindgenContext, item: &Item, name: &str) -> quote::Tokens {
66+
fn quote_equals(name_ident: quote::Ident) -> quote::Tokens {
67+
quote! { self.#name_ident == other.#name_ident }
68+
}
69+
70+
let name_ident = ctx.rust_ident(name);
71+
let ty = item.expect_type();
72+
73+
match *ty.kind() {
74+
TypeKind::Void |
75+
TypeKind::NullPtr |
76+
TypeKind::Int(..) |
77+
TypeKind::Complex(..) |
78+
TypeKind::Float(..) |
79+
TypeKind::Enum(..) |
80+
TypeKind::TypeParam |
81+
TypeKind::UnresolvedTypeRef(..) |
82+
TypeKind::BlockPointer |
83+
TypeKind::Reference(..) |
84+
TypeKind::ObjCInterface(..) |
85+
TypeKind::ObjCId |
86+
TypeKind::ObjCSel |
87+
TypeKind::Comp(..) |
88+
TypeKind::Pointer(_) |
89+
TypeKind::Function(..) |
90+
TypeKind::TemplateInstantiation(..) |
91+
TypeKind::Opaque => {
92+
quote_equals(name_ident)
93+
}
94+
95+
TypeKind::Array(_t, len) => {
96+
if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
97+
quote_equals(name_ident)
98+
} else {
99+
quote! {
100+
&self. #name_ident [..] == &other. #name_ident [..]
101+
}
102+
}
103+
}
104+
105+
TypeKind::ResolvedTypeRef(t) |
106+
TypeKind::TemplateAlias(t, _) |
107+
TypeKind::Alias(t) => {
108+
let inner_item = ctx.resolve_item(t);
109+
gen_field(ctx, inner_item, name)
110+
}
111+
}
112+
}

src/codegen/mod.rs

+54-22
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod impl_debug;
2+
mod impl_partialeq;
23
mod error;
34
mod helpers;
45
pub mod struct_layout;
@@ -13,7 +14,7 @@ use ir::comp::{Base, Bitfield, BitfieldUnit, CompInfo, CompKind, Field,
1314
use ir::context::{BindgenContext, ItemId};
1415
use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault,
1516
CanDeriveHash, CanDerivePartialOrd, CanDeriveOrd,
16-
CanDerivePartialEq, CanDeriveEq};
17+
CanDerivePartialEq, CanDeriveEq, CannotDeriveReason};
1718
use ir::dot;
1819
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
1920
use ir::function::{Abi, Function, FunctionSig};
@@ -1419,6 +1420,7 @@ impl CodeGenerator for CompInfo {
14191420
let mut needs_clone_impl = false;
14201421
let mut needs_default_impl = false;
14211422
let mut needs_debug_impl = false;
1423+
let mut needs_partialeq_impl = false;
14221424
if let Some(comment) = item.comment(ctx) {
14231425
attributes.push(attributes::doc(comment));
14241426
}
@@ -1474,6 +1476,14 @@ impl CodeGenerator for CompInfo {
14741476

14751477
if item.can_derive_partialeq(ctx) {
14761478
derives.push("PartialEq");
1479+
} else {
1480+
needs_partialeq_impl =
1481+
ctx.options().derive_partialeq &&
1482+
ctx.options().impl_partialeq &&
1483+
ctx.lookup_item_id_can_derive_partialeq_or_partialord(item.id())
1484+
.map_or(true, |x| {
1485+
x == CannotDeriveReason::ArrayTooLarge
1486+
});
14771487
}
14781488

14791489
if item.can_derive_eq(ctx) {
@@ -1666,33 +1676,34 @@ impl CodeGenerator for CompInfo {
16661676
}
16671677
}
16681678

1669-
let mut generics = quote! {};
1679+
let mut generic_param_names = vec![];
16701680

16711681
if let Some(ref params) = used_template_params {
1672-
if !params.is_empty() {
1673-
let mut param_names = vec![];
1674-
1675-
for (idx, ty) in params.iter().enumerate() {
1676-
let param = ctx.resolve_type(*ty);
1677-
let name = param.name().unwrap();
1678-
let ident = ctx.rust_ident(name);
1679-
param_names.push(ident.clone());
1682+
for (idx, ty) in params.iter().enumerate() {
1683+
let param = ctx.resolve_type(*ty);
1684+
let name = param.name().unwrap();
1685+
let ident = ctx.rust_ident(name);
1686+
generic_param_names.push(ident.clone());
16801687

1681-
let prefix = ctx.trait_prefix();
1682-
let field_name = ctx.rust_ident(format!("_phantom_{}", idx));
1683-
fields.push(quote! {
1684-
pub #field_name : ::#prefix::marker::PhantomData<
1685-
::#prefix::cell::UnsafeCell<#ident>
1686-
> ,
1687-
});
1688-
}
1689-
1690-
generics = quote! {
1691-
< #( #param_names ),* >
1692-
};
1688+
let prefix = ctx.trait_prefix();
1689+
let field_name = ctx.rust_ident(format!("_phantom_{}", idx));
1690+
fields.push(quote! {
1691+
pub #field_name : ::#prefix::marker::PhantomData<
1692+
::#prefix::cell::UnsafeCell<#ident>
1693+
> ,
1694+
});
16931695
}
16941696
}
16951697

1698+
let generics = if !generic_param_names.is_empty() {
1699+
let generic_param_names = generic_param_names.clone();
1700+
quote! {
1701+
< #( #generic_param_names ),* >
1702+
}
1703+
} else {
1704+
quote! { }
1705+
};
1706+
16961707
tokens.append(quote! {
16971708
#generics {
16981709
#( #fields )*
@@ -1896,6 +1907,27 @@ impl CodeGenerator for CompInfo {
18961907
});
18971908
}
18981909

1910+
if needs_partialeq_impl {
1911+
if let Some(impl_) = impl_partialeq::gen_partialeq_impl(ctx, self, item, &ty_for_impl) {
1912+
1913+
let partialeq_bounds = if !generic_param_names.is_empty() {
1914+
let bounds = generic_param_names.iter().map(|t| {
1915+
quote! { #t: PartialEq }
1916+
});
1917+
quote! { where #( #bounds ),* }
1918+
} else {
1919+
quote! { }
1920+
};
1921+
1922+
let prefix = ctx.trait_prefix();
1923+
result.push(quote! {
1924+
impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds {
1925+
#impl_
1926+
}
1927+
});
1928+
}
1929+
}
1930+
18991931
if !methods.is_empty() {
19001932
result.push(quote! {
19011933
impl #generics #ty_for_impl {

0 commit comments

Comments
 (0)