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 | |
6 | /// Generate a manual implementation of `PartialEq` trait for the |
7 | /// specified compound type. |
8 | pub(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 | |
73 | fn 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 | |