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