Skip to content

Commit 806887f

Browse files
authored
Derive traits for newtype aliases (#1802)
1 parent fc461b8 commit 806887f

File tree

4 files changed

+113
-43
lines changed

4 files changed

+113
-43
lines changed

src/codegen/mod.rs

Lines changed: 106 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,93 @@ fn root_import(
9595
}
9696
}
9797

98+
bitflags! {
99+
struct DerivableTraits: u16 {
100+
const DEBUG = 1 << 0;
101+
const DEFAULT = 1 << 1;
102+
const COPY = 1 << 2;
103+
const CLONE = 1 << 3;
104+
const HASH = 1 << 4;
105+
const PARTIAL_ORD = 1 << 5;
106+
const ORD = 1 << 6;
107+
const PARTIAL_EQ = 1 << 7;
108+
const EQ = 1 << 8;
109+
}
110+
}
111+
112+
fn derives_of_item(item: &Item, ctx: &BindgenContext) -> DerivableTraits {
113+
let mut derivable_traits = DerivableTraits::empty();
114+
115+
if item.can_derive_debug(ctx) {
116+
derivable_traits |= DerivableTraits::DEBUG;
117+
}
118+
119+
if item.can_derive_default(ctx) {
120+
derivable_traits |= DerivableTraits::DEFAULT;
121+
}
122+
123+
let all_template_params = item.all_template_params(ctx);
124+
125+
if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
126+
derivable_traits |= DerivableTraits::COPY;
127+
128+
if ctx.options().rust_features().builtin_clone_impls ||
129+
!all_template_params.is_empty()
130+
{
131+
// FIXME: This requires extra logic if you have a big array in a
132+
// templated struct. The reason for this is that the magic:
133+
// fn clone(&self) -> Self { *self }
134+
// doesn't work for templates.
135+
//
136+
// It's not hard to fix though.
137+
derivable_traits |= DerivableTraits::CLONE;
138+
}
139+
}
140+
141+
if item.can_derive_hash(ctx) {
142+
derivable_traits |= DerivableTraits::HASH;
143+
}
144+
145+
if item.can_derive_partialord(ctx) {
146+
derivable_traits |= DerivableTraits::PARTIAL_ORD;
147+
}
148+
149+
if item.can_derive_ord(ctx) {
150+
derivable_traits |= DerivableTraits::ORD;
151+
}
152+
153+
if item.can_derive_partialeq(ctx) {
154+
derivable_traits |= DerivableTraits::PARTIAL_EQ;
155+
}
156+
157+
if item.can_derive_eq(ctx) {
158+
derivable_traits |= DerivableTraits::EQ;
159+
}
160+
161+
derivable_traits
162+
}
163+
164+
impl From<DerivableTraits> for Vec<&'static str> {
165+
fn from(derivable_traits: DerivableTraits) -> Vec<&'static str> {
166+
[
167+
(DerivableTraits::DEBUG, "Debug"),
168+
(DerivableTraits::DEFAULT, "Default"),
169+
(DerivableTraits::COPY, "Copy"),
170+
(DerivableTraits::CLONE, "Clone"),
171+
(DerivableTraits::HASH, "Hash"),
172+
(DerivableTraits::PARTIAL_ORD, "PartialOrd"),
173+
(DerivableTraits::ORD, "Ord"),
174+
(DerivableTraits::PARTIAL_EQ, "PartialEq"),
175+
(DerivableTraits::EQ, "Eq"),
176+
]
177+
.iter()
178+
.filter_map(|&(flag, derive)| {
179+
Some(derive).filter(|_| derivable_traits.contains(flag))
180+
})
181+
.collect()
182+
}
183+
}
184+
98185
struct CodegenResult<'a> {
99186
items: Vec<proc_macro2::TokenStream>,
100187

@@ -793,8 +880,17 @@ impl CodeGenerator for Type {
793880
"repr_transparent feature is required to use {:?}",
794881
alias_style
795882
);
883+
884+
let mut attributes =
885+
vec![attributes::repr("transparent")];
886+
let derivable_traits = derives_of_item(item, ctx);
887+
if !derivable_traits.is_empty() {
888+
let derives: Vec<_> = derivable_traits.into();
889+
attributes.push(attributes::derives(&derives))
890+
}
891+
796892
quote! {
797-
#[repr(transparent)]
893+
#( #attributes )*
798894
pub struct #rust_name
799895
}
800896
}
@@ -1787,66 +1883,33 @@ impl CodeGenerator for CompInfo {
17871883
}
17881884
}
17891885

1790-
let mut derives = vec![];
1791-
if item.can_derive_debug(ctx) {
1792-
derives.push("Debug");
1793-
} else {
1886+
let derivable_traits = derives_of_item(item, ctx);
1887+
if !derivable_traits.contains(DerivableTraits::DEBUG) {
17941888
needs_debug_impl =
17951889
ctx.options().derive_debug && ctx.options().impl_debug
17961890
}
17971891

1798-
if item.can_derive_default(ctx) {
1799-
derives.push("Default");
1800-
} else {
1892+
if !derivable_traits.contains(DerivableTraits::DEFAULT) {
18011893
needs_default_impl =
18021894
ctx.options().derive_default && !self.is_forward_declaration();
18031895
}
18041896

18051897
let all_template_params = item.all_template_params(ctx);
18061898

1807-
if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
1808-
derives.push("Copy");
1809-
1810-
if ctx.options().rust_features().builtin_clone_impls ||
1811-
!all_template_params.is_empty()
1812-
{
1813-
// FIXME: This requires extra logic if you have a big array in a
1814-
// templated struct. The reason for this is that the magic:
1815-
// fn clone(&self) -> Self { *self }
1816-
// doesn't work for templates.
1817-
//
1818-
// It's not hard to fix though.
1819-
derives.push("Clone");
1820-
} else {
1821-
needs_clone_impl = true;
1822-
}
1823-
}
1824-
1825-
if item.can_derive_hash(ctx) {
1826-
derives.push("Hash");
1827-
}
1828-
1829-
if item.can_derive_partialord(ctx) {
1830-
derives.push("PartialOrd");
1831-
}
1832-
1833-
if item.can_derive_ord(ctx) {
1834-
derives.push("Ord");
1899+
if derivable_traits.contains(DerivableTraits::COPY) &&
1900+
!derivable_traits.contains(DerivableTraits::CLONE)
1901+
{
1902+
needs_clone_impl = true;
18351903
}
18361904

1837-
if item.can_derive_partialeq(ctx) {
1838-
derives.push("PartialEq");
1839-
} else {
1905+
if !derivable_traits.contains(DerivableTraits::PARTIAL_EQ) {
18401906
needs_partialeq_impl = ctx.options().derive_partialeq &&
18411907
ctx.options().impl_partialeq &&
18421908
ctx.lookup_can_derive_partialeq_or_partialord(item.id()) ==
18431909
CanDerive::Manually;
18441910
}
18451911

1846-
if item.can_derive_eq(ctx) {
1847-
derives.push("Eq");
1848-
}
1849-
1912+
let mut derives: Vec<_> = derivable_traits.into();
18501913
derives.extend(item.annotations().derives().iter().map(String::as_str));
18511914

18521915
if !derives.is_empty() {

tests/expectations/tests/issue-1488-enum-new-type.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ pub const Foo_A: Foo = 0;
1111
pub const Foo_B: Foo = 1;
1212
pub type Foo = u32;
1313
#[repr(transparent)]
14+
#[derive(Debug, Copy, Clone)]
1415
pub struct FooAlias(pub Foo);
1516
pub mod Bar {
1617
pub type Type = u32;
1718
pub const C: Type = 0;
1819
pub const D: Type = 1;
1920
}
2021
#[repr(transparent)]
22+
#[derive(Debug, Copy, Clone)]
2123
pub struct BarAlias(pub Bar::Type);
2224
#[repr(u32)]
2325
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -26,11 +28,13 @@ pub enum Qux {
2628
F = 1,
2729
}
2830
#[repr(transparent)]
31+
#[derive(Debug, Copy, Clone)]
2932
pub struct QuxAlias(pub Qux);
3033
pub const Baz_G: Baz = 0;
3134
pub const Baz_H: Baz = 1;
3235
pub type Baz = u32;
3336
#[repr(transparent)]
37+
#[derive(Debug, Copy, Clone)]
3438
pub struct BazAlias(pub Baz);
3539
impl ::std::ops::Deref for BazAlias {
3640
type Target = Baz;

tests/expectations/tests/issue-1488-options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99

1010
pub type OSStatus = ::std::os::raw::c_int;
1111
#[repr(transparent)]
12+
#[derive(Debug, Copy, Clone)]
1213
pub struct SomePtr(pub *mut ::std::os::raw::c_void);
1314
#[repr(transparent)]
15+
#[derive(Debug, Copy, Clone)]
1416
pub struct AnotherPtr(pub *mut ::std::os::raw::c_void);
1517
impl ::std::ops::Deref for AnotherPtr {
1618
type Target = *mut ::std::os::raw::c_void;

tests/expectations/tests/issue-1488-template-alias-new-type.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
)]
99

1010
#[repr(transparent)]
11+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1112
pub struct Wrapped<T>(pub T);

0 commit comments

Comments
 (0)