Derive traits for newtype aliases (#1802)

This commit is contained in:
eggyal
2020-06-15 16:40:11 +01:00
committed by GitHub
parent 748afe7808
commit e831d2e8ed
4 changed files with 113 additions and 43 deletions
+106 -43
View File
@@ -95,6 +95,93 @@ fn root_import(
}
}
bitflags! {
struct DerivableTraits: u16 {
const DEBUG = 1 << 0;
const DEFAULT = 1 << 1;
const COPY = 1 << 2;
const CLONE = 1 << 3;
const HASH = 1 << 4;
const PARTIAL_ORD = 1 << 5;
const ORD = 1 << 6;
const PARTIAL_EQ = 1 << 7;
const EQ = 1 << 8;
}
}
fn derives_of_item(item: &Item, ctx: &BindgenContext) -> DerivableTraits {
let mut derivable_traits = DerivableTraits::empty();
if item.can_derive_debug(ctx) {
derivable_traits |= DerivableTraits::DEBUG;
}
if item.can_derive_default(ctx) {
derivable_traits |= DerivableTraits::DEFAULT;
}
let all_template_params = item.all_template_params(ctx);
if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
derivable_traits |= DerivableTraits::COPY;
if ctx.options().rust_features().builtin_clone_impls ||
!all_template_params.is_empty()
{
// FIXME: This requires extra logic if you have a big array in a
// templated struct. The reason for this is that the magic:
// fn clone(&self) -> Self { *self }
// doesn't work for templates.
//
// It's not hard to fix though.
derivable_traits |= DerivableTraits::CLONE;
}
}
if item.can_derive_hash(ctx) {
derivable_traits |= DerivableTraits::HASH;
}
if item.can_derive_partialord(ctx) {
derivable_traits |= DerivableTraits::PARTIAL_ORD;
}
if item.can_derive_ord(ctx) {
derivable_traits |= DerivableTraits::ORD;
}
if item.can_derive_partialeq(ctx) {
derivable_traits |= DerivableTraits::PARTIAL_EQ;
}
if item.can_derive_eq(ctx) {
derivable_traits |= DerivableTraits::EQ;
}
derivable_traits
}
impl From<DerivableTraits> for Vec<&'static str> {
fn from(derivable_traits: DerivableTraits) -> Vec<&'static str> {
[
(DerivableTraits::DEBUG, "Debug"),
(DerivableTraits::DEFAULT, "Default"),
(DerivableTraits::COPY, "Copy"),
(DerivableTraits::CLONE, "Clone"),
(DerivableTraits::HASH, "Hash"),
(DerivableTraits::PARTIAL_ORD, "PartialOrd"),
(DerivableTraits::ORD, "Ord"),
(DerivableTraits::PARTIAL_EQ, "PartialEq"),
(DerivableTraits::EQ, "Eq"),
]
.iter()
.filter_map(|&(flag, derive)| {
Some(derive).filter(|_| derivable_traits.contains(flag))
})
.collect()
}
}
struct CodegenResult<'a> {
items: Vec<proc_macro2::TokenStream>,
@@ -793,8 +880,17 @@ impl CodeGenerator for Type {
"repr_transparent feature is required to use {:?}",
alias_style
);
let mut attributes =
vec![attributes::repr("transparent")];
let derivable_traits = derives_of_item(item, ctx);
if !derivable_traits.is_empty() {
let derives: Vec<_> = derivable_traits.into();
attributes.push(attributes::derives(&derives))
}
quote! {
#[repr(transparent)]
#( #attributes )*
pub struct #rust_name
}
}
@@ -1787,66 +1883,33 @@ impl CodeGenerator for CompInfo {
}
}
let mut derives = vec![];
if item.can_derive_debug(ctx) {
derives.push("Debug");
} else {
let derivable_traits = derives_of_item(item, ctx);
if !derivable_traits.contains(DerivableTraits::DEBUG) {
needs_debug_impl =
ctx.options().derive_debug && ctx.options().impl_debug
}
if item.can_derive_default(ctx) {
derives.push("Default");
} else {
if !derivable_traits.contains(DerivableTraits::DEFAULT) {
needs_default_impl =
ctx.options().derive_default && !self.is_forward_declaration();
}
let all_template_params = item.all_template_params(ctx);
if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
derives.push("Copy");
if ctx.options().rust_features().builtin_clone_impls ||
!all_template_params.is_empty()
{
// FIXME: This requires extra logic if you have a big array in a
// templated struct. The reason for this is that the magic:
// fn clone(&self) -> Self { *self }
// doesn't work for templates.
//
// It's not hard to fix though.
derives.push("Clone");
} else {
needs_clone_impl = true;
}
if derivable_traits.contains(DerivableTraits::COPY) &&
!derivable_traits.contains(DerivableTraits::CLONE)
{
needs_clone_impl = true;
}
if item.can_derive_hash(ctx) {
derives.push("Hash");
}
if item.can_derive_partialord(ctx) {
derives.push("PartialOrd");
}
if item.can_derive_ord(ctx) {
derives.push("Ord");
}
if item.can_derive_partialeq(ctx) {
derives.push("PartialEq");
} else {
if !derivable_traits.contains(DerivableTraits::PARTIAL_EQ) {
needs_partialeq_impl = ctx.options().derive_partialeq &&
ctx.options().impl_partialeq &&
ctx.lookup_can_derive_partialeq_or_partialord(item.id()) ==
CanDerive::Manually;
}
if item.can_derive_eq(ctx) {
derives.push("Eq");
}
let mut derives: Vec<_> = derivable_traits.into();
derives.extend(item.annotations().derives().iter().map(String::as_str));
if !derives.is_empty() {
@@ -11,6 +11,7 @@ pub const Foo_A: Foo = 0;
pub const Foo_B: Foo = 1;
pub type Foo = u32;
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct FooAlias(pub Foo);
pub mod Bar {
pub type Type = u32;
@@ -18,6 +19,7 @@ pub mod Bar {
pub const D: Type = 1;
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct BarAlias(pub Bar::Type);
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -26,11 +28,13 @@ pub enum Qux {
F = 1,
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct QuxAlias(pub Qux);
pub const Baz_G: Baz = 0;
pub const Baz_H: Baz = 1;
pub type Baz = u32;
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct BazAlias(pub Baz);
impl ::std::ops::Deref for BazAlias {
type Target = Baz;
@@ -9,8 +9,10 @@
pub type OSStatus = ::std::os::raw::c_int;
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct SomePtr(pub *mut ::std::os::raw::c_void);
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct AnotherPtr(pub *mut ::std::os::raw::c_void);
impl ::std::ops::Deref for AnotherPtr {
type Target = *mut ::std::os::raw::c_void;
@@ -8,4 +8,5 @@
)]
#[repr(transparent)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Wrapped<T>(pub T);