summaryrefslogtreecommitdiffstats
path: root/third_party/rust/bindgen/codegen/impl_partialeq.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/bindgen/codegen/impl_partialeq.rs')
-rw-r--r--third_party/rust/bindgen/codegen/impl_partialeq.rs142
1 files changed, 142 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/codegen/impl_partialeq.rs b/third_party/rust/bindgen/codegen/impl_partialeq.rs
new file mode 100644
index 0000000000..960306ffc6
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/impl_partialeq.rs
@@ -0,0 +1,142 @@
+use crate::ir::comp::{CompInfo, CompKind, Field, FieldMethods};
+use crate::ir::context::BindgenContext;
+use crate::ir::item::{IsOpaque, Item};
+use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
+
+/// Generate a manual implementation of `PartialEq` trait for the
+/// specified compound type.
+pub fn gen_partialeq_impl(
+ ctx: &BindgenContext,
+ comp_info: &CompInfo,
+ item: &Item,
+ ty_for_impl: &proc_macro2::TokenStream,
+) -> Option<proc_macro2::TokenStream> {
+ let mut tokens = vec![];
+
+ if item.is_opaque(ctx, &()) {
+ tokens.push(quote! {
+ &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..]
+ });
+ } else if comp_info.kind() == CompKind::Union {
+ assert!(!ctx.options().rust_features().untagged_union);
+ tokens.push(quote! {
+ &self.bindgen_union_field[..] == &other.bindgen_union_field[..]
+ });
+ } else {
+ for base in comp_info.base_members().iter() {
+ if !base.requires_storage(ctx) {
+ continue;
+ }
+
+ let ty_item = ctx.resolve_item(base.ty);
+ let field_name = &base.field_name;
+
+ if ty_item.is_opaque(ctx, &()) {
+ let field_name = ctx.rust_ident(field_name);
+ tokens.push(quote! {
+ &self. #field_name [..] == &other. #field_name [..]
+ });
+ } else {
+ tokens.push(gen_field(ctx, ty_item, field_name));
+ }
+ }
+
+ for field in comp_info.fields() {
+ match *field {
+ Field::DataMember(ref fd) => {
+ let ty_item = ctx.resolve_item(fd.ty());
+ let name = fd.name().unwrap();
+ tokens.push(gen_field(ctx, ty_item, name));
+ }
+ Field::Bitfields(ref bu) => {
+ for bitfield in bu.bitfields() {
+ if bitfield.name().is_some() {
+ let getter_name = bitfield.getter_name();
+ let name_ident = ctx.rust_ident_raw(getter_name);
+ tokens.push(quote! {
+ self.#name_ident () == other.#name_ident ()
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Some(quote! {
+ fn eq(&self, other: & #ty_for_impl) -> bool {
+ #( #tokens )&&*
+ }
+ })
+}
+
+fn gen_field(
+ ctx: &BindgenContext,
+ ty_item: &Item,
+ name: &str,
+) -> proc_macro2::TokenStream {
+ fn quote_equals(
+ name_ident: proc_macro2::Ident,
+ ) -> proc_macro2::TokenStream {
+ quote! { self.#name_ident == other.#name_ident }
+ }
+
+ let name_ident = ctx.rust_ident(name);
+ let ty = ty_item.expect_type();
+
+ match *ty.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Float(..) |
+ TypeKind::Enum(..) |
+ TypeKind::TypeParam |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::Reference(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel |
+ TypeKind::Comp(..) |
+ TypeKind::Pointer(_) |
+ TypeKind::Function(..) |
+ TypeKind::Opaque => quote_equals(name_ident),
+
+ TypeKind::TemplateInstantiation(ref inst) => {
+ if inst.is_opaque(ctx, ty_item) {
+ quote! {
+ &self. #name_ident [..] == &other. #name_ident [..]
+ }
+ } else {
+ quote_equals(name_ident)
+ }
+ }
+
+ TypeKind::Array(_, len) => {
+ if len <= RUST_DERIVE_IN_ARRAY_LIMIT ||
+ ctx.options().rust_features().larger_arrays
+ {
+ quote_equals(name_ident)
+ } else {
+ quote! {
+ &self. #name_ident [..] == &other. #name_ident [..]
+ }
+ }
+ }
+ TypeKind::Vector(_, len) => {
+ let self_ids = 0..len;
+ let other_ids = 0..len;
+ quote! {
+ #(self.#self_ids == other.#other_ids &&)* true
+ }
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::BlockPointer(t) => {
+ let inner_item = ctx.resolve_item(t);
+ gen_field(ctx, inner_item, name)
+ }
+ }
+}