bindgen/codegen/
impl_partialeq.rs

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() {
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}