1 use crate::ir::comp::{CompInfo, CompKind, Field, FieldMethods};
2 use crate::ir::context::BindgenContext;
3 use crate::ir::item::{IsOpaque, Item};
4 use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
5 use proc_macro2;
6
7 /// Generate a manual implementation of `PartialEq` trait for the
8 /// specified compound type.
gen_partialeq_impl( ctx: &BindgenContext, comp_info: &CompInfo, item: &Item, ty_for_impl: &proc_macro2::TokenStream, ) -> Option<proc_macro2::TokenStream>9 pub fn gen_partialeq_impl(
10 ctx: &BindgenContext,
11 comp_info: &CompInfo,
12 item: &Item,
13 ty_for_impl: &proc_macro2::TokenStream,
14 ) -> Option<proc_macro2::TokenStream> {
15 let mut tokens = vec![];
16
17 if item.is_opaque(ctx, &()) {
18 tokens.push(quote! {
19 &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..]
20 });
21 } else if comp_info.kind() == CompKind::Union {
22 assert!(!ctx.options().rust_features().untagged_union);
23 tokens.push(quote! {
24 &self.bindgen_union_field[..] == &other.bindgen_union_field[..]
25 });
26 } else {
27 for base in comp_info.base_members().iter() {
28 if !base.requires_storage(ctx) {
29 continue;
30 }
31
32 let ty_item = ctx.resolve_item(base.ty);
33 let field_name = &base.field_name;
34
35 if ty_item.is_opaque(ctx, &()) {
36 let field_name = ctx.rust_ident(field_name);
37 tokens.push(quote! {
38 &self. #field_name [..] == &other. #field_name [..]
39 });
40 } else {
41 tokens.push(gen_field(ctx, ty_item, field_name));
42 }
43 }
44
45 for field in comp_info.fields() {
46 match *field {
47 Field::DataMember(ref fd) => {
48 let ty_item = ctx.resolve_item(fd.ty());
49 let name = fd.name().unwrap();
50 tokens.push(gen_field(ctx, ty_item, name));
51 }
52 Field::Bitfields(ref bu) => {
53 for bitfield in bu.bitfields() {
54 if let Some(_) = bitfield.name() {
55 let getter_name = bitfield.getter_name();
56 let name_ident = ctx.rust_ident_raw(getter_name);
57 tokens.push(quote! {
58 self.#name_ident () == other.#name_ident ()
59 });
60 }
61 }
62 }
63 }
64 }
65 }
66
67 Some(quote! {
68 fn eq(&self, other: & #ty_for_impl) -> bool {
69 #( #tokens )&&*
70 }
71 })
72 }
73
gen_field( ctx: &BindgenContext, ty_item: &Item, name: &str, ) -> proc_macro2::TokenStream74 fn gen_field(
75 ctx: &BindgenContext,
76 ty_item: &Item,
77 name: &str,
78 ) -> proc_macro2::TokenStream {
79 fn quote_equals(
80 name_ident: proc_macro2::Ident,
81 ) -> proc_macro2::TokenStream {
82 quote! { self.#name_ident == other.#name_ident }
83 }
84
85 let name_ident = ctx.rust_ident(name);
86 let ty = ty_item.expect_type();
87
88 match *ty.kind() {
89 TypeKind::Void |
90 TypeKind::NullPtr |
91 TypeKind::Int(..) |
92 TypeKind::Complex(..) |
93 TypeKind::Float(..) |
94 TypeKind::Enum(..) |
95 TypeKind::TypeParam |
96 TypeKind::UnresolvedTypeRef(..) |
97 TypeKind::Reference(..) |
98 TypeKind::ObjCInterface(..) |
99 TypeKind::ObjCId |
100 TypeKind::ObjCSel |
101 TypeKind::Comp(..) |
102 TypeKind::Pointer(_) |
103 TypeKind::Function(..) |
104 TypeKind::Opaque => quote_equals(name_ident),
105
106 TypeKind::TemplateInstantiation(ref inst) => {
107 if inst.is_opaque(ctx, &ty_item) {
108 quote! {
109 &self. #name_ident [..] == &other. #name_ident [..]
110 }
111 } else {
112 quote_equals(name_ident)
113 }
114 }
115
116 TypeKind::Array(_, len) => {
117 if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
118 quote_equals(name_ident)
119 } else {
120 quote! {
121 &self. #name_ident [..] == &other. #name_ident [..]
122 }
123 }
124 }
125 TypeKind::Vector(_, len) => {
126 let self_ids = 0..len;
127 let other_ids = 0..len;
128 quote! {
129 #(self.#self_ids == other.#other_ids &&)* true
130 }
131 }
132
133 TypeKind::ResolvedTypeRef(t) |
134 TypeKind::TemplateAlias(t, _) |
135 TypeKind::Alias(t) |
136 TypeKind::BlockPointer(t) => {
137 let inner_item = ctx.resolve_item(t);
138 gen_field(ctx, inner_item, name)
139 }
140 }
141 }
142