Skip to content

Commit 567f20b

Browse files
authored
Use optimized output for Clone and PartialOrd with custom bounds (#95)
1 parent a47e8ed commit 567f20b

18 files changed

+209
-84
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Changed
11+
- Use the `Copy` implementation for `Clone` and the `Ord` implementation for
12+
`PartialOrd` when custom bounds are present.
13+
814
## [1.2.7] - 2023-12-14
915

1016
### Fixed

src/lib.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ fn generate_impl(
636636
let mut where_clause = where_clause.map(Cow::Borrowed);
637637
derive_where.where_clause(&mut where_clause, trait_, item);
638638

639-
let body = generate_body(derive_where, &derive_where.traits, trait_, item, generics);
639+
let body = generate_body(derive_where, trait_, item, generics);
640640

641641
let ident = item.ident();
642642
let path = trait_.impl_path(trait_);
@@ -666,25 +666,22 @@ fn generate_impl(
666666
/// Generate implementation method body for a [`Trait`].
667667
fn generate_body(
668668
derive_where: &DeriveWhere,
669-
traits: &[DeriveTrait],
670669
trait_: &DeriveTrait,
671670
item: &Item,
672671
generics: &SplitGenerics<'_>,
673672
) -> TokenStream {
674-
let any_bound = !derive_where.generics.is_empty();
675-
676673
match &item {
677674
Item::Item(data) => {
678-
let body = trait_.build_body(any_bound, traits, trait_, data);
679-
trait_.build_signature(any_bound, item, generics, traits, trait_, &body)
675+
let body = trait_.build_body(derive_where, trait_, data);
676+
trait_.build_signature(derive_where, item, generics, trait_, &body)
680677
}
681678
Item::Enum { variants, .. } => {
682679
let body: TokenStream = variants
683680
.iter()
684-
.map(|data| trait_.build_body(any_bound, traits, trait_, data))
681+
.map(|data| trait_.build_body(derive_where, trait_, data))
685682
.collect();
686683

687-
trait_.build_signature(any_bound, item, generics, traits, trait_, &body)
684+
trait_.build_signature(derive_where, item, generics, trait_, &body)
688685
}
689686
}
690687
}

src/test/bound.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use super::test_derive;
77
fn bound() -> Result<()> {
88
test_derive(
99
quote! {
10-
#[derive_where(Clone; T)]
10+
#[derive_where(Clone, Copy; T)]
1111
struct Test<T, U>(T, std::marker::PhantomData<U>);
1212
},
1313
quote! {
@@ -22,6 +22,11 @@ fn bound() -> Result<()> {
2222
}
2323
}
2424
}
25+
26+
#[automatically_derived]
27+
impl<T, U> ::core::marker::Copy for Test<T, U>
28+
where T: ::core::marker::Copy
29+
{ }
2530
},
2631
)
2732
}
@@ -30,7 +35,7 @@ fn bound() -> Result<()> {
3035
fn bound_multiple() -> Result<()> {
3136
test_derive(
3237
quote! {
33-
#[derive_where(Clone; T, U)]
38+
#[derive_where(Clone, Copy; T, U)]
3439
struct Test<T, U, V>((T, U), std::marker::PhantomData<V>);
3540
},
3641
quote! {
@@ -47,6 +52,13 @@ fn bound_multiple() -> Result<()> {
4752
}
4853
}
4954
}
55+
56+
#[automatically_derived]
57+
impl<T, U, V> ::core::marker::Copy for Test<T, U, V>
58+
where
59+
T: ::core::marker::Copy,
60+
U: ::core::marker::Copy
61+
{ }
5062
},
5163
)
5264
}

src/test/clone.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,59 @@ fn union_() -> Result<()> {
9595
fn clone(&self) -> Self {
9696
struct __AssertCopy<__T: ::core::marker::Copy + ?::core::marker::Sized>(::core::marker::PhantomData<__T>);
9797
let _: __AssertCopy<Self>;
98+
*self
9899
}
99100
}
100101
},
101102
)
102103
}
104+
105+
#[test]
106+
fn no_bound() -> Result<()> {
107+
test_derive(
108+
quote! {
109+
#[derive_where(Clone, Copy)]
110+
struct Test<T>(std::marker::PhantomData<T>);
111+
},
112+
quote! {
113+
#[automatically_derived]
114+
impl<T> ::core::clone::Clone for Test<T>
115+
{
116+
#[inline]
117+
fn clone(&self) -> Self {
118+
*self
119+
}
120+
}
121+
122+
#[automatically_derived]
123+
impl<T> ::core::marker::Copy for Test<T>
124+
{ }
125+
},
126+
)
127+
}
128+
129+
#[test]
130+
fn custom_bound() -> Result<()> {
131+
test_derive(
132+
quote! {
133+
#[derive_where(Clone, Copy; T: Trait)]
134+
struct Test<T>(T);
135+
},
136+
quote! {
137+
#[automatically_derived]
138+
impl<T> ::core::clone::Clone for Test<T>
139+
where T: Trait
140+
{
141+
#[inline]
142+
fn clone(&self) -> Self {
143+
*self
144+
}
145+
}
146+
147+
#[automatically_derived]
148+
impl<T> ::core::marker::Copy for Test<T>
149+
where T: Trait
150+
{ }
151+
},
152+
)
153+
}

src/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod basic;
22
mod bound;
3+
mod clone;
34
mod discriminant;
45
mod enum_;
56
#[cfg(not(any(feature = "nightly", feature = "safe")))]

src/test/partial_ord.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,73 @@ fn bound() -> Result<()> {
200200
},
201201
)
202202
}
203+
204+
#[test]
205+
fn no_bound() -> Result<()> {
206+
test_derive(
207+
quote! {
208+
#[derive_where(Ord, PartialOrd)]
209+
struct Test<T>(std::marker::PhantomData<T>);
210+
},
211+
quote! {
212+
#[automatically_derived]
213+
impl<T> ::core::cmp::Ord for Test<T> {
214+
#[inline]
215+
fn cmp(&self, __other: &Self) -> ::core::cmp::Ordering {
216+
match (self, __other) {
217+
(Test(ref __field_0), Test(ref __other_field_0)) =>
218+
match ::core::cmp::Ord::cmp(__field_0, __other_field_0) {
219+
::core::cmp::Ordering::Equal => ::core::cmp::Ordering::Equal,
220+
__cmp => __cmp,
221+
},
222+
}
223+
}
224+
}
225+
226+
#[automatically_derived]
227+
impl<T> ::core::cmp::PartialOrd for Test<T> {
228+
#[inline]
229+
fn partial_cmp(&self, __other: &Self) -> ::core::option::Option<::core::cmp::Ordering> {
230+
::core::option::Option::Some(::core::cmp::Ord::cmp(self, __other))
231+
}
232+
}
233+
},
234+
)
235+
}
236+
237+
#[test]
238+
fn custom_bound() -> Result<()> {
239+
test_derive(
240+
quote! {
241+
#[derive_where(Ord, PartialOrd; T: TestTrait)]
242+
struct Test<T>(std::marker::PhantomData<T>);
243+
},
244+
quote! {
245+
#[automatically_derived]
246+
impl<T> ::core::cmp::Ord for Test<T>
247+
where T: TestTrait
248+
{
249+
#[inline]
250+
fn cmp(&self, __other: &Self) -> ::core::cmp::Ordering {
251+
match (self, __other) {
252+
(Test(ref __field_0), Test(ref __other_field_0)) =>
253+
match ::core::cmp::Ord::cmp(__field_0, __other_field_0) {
254+
::core::cmp::Ordering::Equal => ::core::cmp::Ordering::Equal,
255+
__cmp => __cmp,
256+
},
257+
}
258+
}
259+
}
260+
261+
#[automatically_derived]
262+
impl<T> ::core::cmp::PartialOrd for Test<T>
263+
where T: TestTrait
264+
{
265+
#[inline]
266+
fn partial_cmp(&self, __other: &Self) -> ::core::option::Option<::core::cmp::Ordering> {
267+
::core::option::Option::Some(::core::cmp::Ord::cmp(self, __other))
268+
}
269+
}
270+
},
271+
)
272+
}

src/trait_.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ mod zeroize_on_drop;
1818
use proc_macro2::{Span, TokenStream};
1919
use syn::{punctuated::Punctuated, spanned::Spanned, Meta, Path, Result, Token, TypeParamBound};
2020

21-
use crate::{Data, DeriveTrait, Error, Item, SplitGenerics};
21+
use crate::{Data, DeriveTrait, DeriveWhere, Error, Item, SplitGenerics};
2222

2323
/// Type implementing [`TraitImpl`] for every trait.
2424
#[derive(Clone, Copy, Eq, PartialEq)]
@@ -133,26 +133,23 @@ impl TraitImpl for Trait {
133133

134134
fn build_signature(
135135
&self,
136-
any_bound: bool,
136+
derive_where: &DeriveWhere,
137137
item: &Item,
138138
generics: &SplitGenerics<'_>,
139-
traits: &[DeriveTrait],
140139
trait_: &DeriveTrait,
141140
body: &TokenStream,
142141
) -> TokenStream {
143142
self.implementation()
144-
.build_signature(any_bound, item, generics, traits, trait_, body)
143+
.build_signature(derive_where, item, generics, trait_, body)
145144
}
146145

147146
fn build_body(
148147
&self,
149-
any_bound: bool,
150-
traits: &[DeriveTrait],
148+
derive_where: &DeriveWhere,
151149
trait_: &DeriveTrait,
152150
data: &Data,
153151
) -> TokenStream {
154-
self.implementation()
155-
.build_body(any_bound, traits, trait_, data)
152+
self.implementation().build_body(derive_where, trait_, data)
156153
}
157154
}
158155

@@ -199,10 +196,9 @@ pub trait TraitImpl {
199196
/// Build method signature for this [`Trait`].
200197
fn build_signature(
201198
&self,
202-
_any_bound: bool,
199+
_derive_where: &DeriveWhere,
203200
_item: &Item,
204201
_generics: &SplitGenerics<'_>,
205-
_traits: &[DeriveTrait],
206202
_trait_: &DeriveTrait,
207203
_body: &TokenStream,
208204
) -> TokenStream {
@@ -212,8 +208,7 @@ pub trait TraitImpl {
212208
/// Build method body for this [`Trait`].
213209
fn build_body(
214210
&self,
215-
_any_bound: bool,
216-
_traits: &[DeriveTrait],
211+
_derive_where: &DeriveWhere,
217212
_trait_: &DeriveTrait,
218213
_data: &Data,
219214
) -> TokenStream {

src/trait_/clone.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use proc_macro2::TokenStream;
44
use quote::quote;
55
use syn::{TraitBound, TraitBoundModifier, TypeParamBound};
66

7-
use crate::{Data, DataType, DeriveTrait, Item, SimpleType, SplitGenerics, Trait, TraitImpl};
7+
use crate::{
8+
Data, DataType, DeriveTrait, DeriveWhere, Item, SimpleType, SplitGenerics, Trait, TraitImpl,
9+
};
810

911
/// Dummy-struct implement [`Trait`] for [`Clone`](trait@std::clone::Clone).
1012
pub struct Clone;
@@ -42,15 +44,16 @@ impl TraitImpl for Clone {
4244

4345
fn build_signature(
4446
&self,
45-
any_bound: bool,
47+
derive_where: &DeriveWhere,
4648
item: &Item,
4749
_generics: &SplitGenerics<'_>,
48-
traits: &[DeriveTrait],
4950
_trait_: &DeriveTrait,
5051
body: &TokenStream,
5152
) -> TokenStream {
5253
// Special implementation for items also implementing `Copy`.
53-
if !any_bound && traits.iter().any(|trait_| trait_ == Trait::Copy) {
54+
if (derive_where.generics.is_empty() || derive_where.any_custom_bound())
55+
&& derive_where.contains(Trait::Copy)
56+
{
5457
return quote! {
5558
#[inline]
5659
fn clone(&self) -> Self { *self }
@@ -85,12 +88,13 @@ impl TraitImpl for Clone {
8588

8689
fn build_body(
8790
&self,
88-
any_bound: bool,
89-
traits: &[DeriveTrait],
91+
derive_where: &DeriveWhere,
9092
trait_: &DeriveTrait,
9193
data: &Data,
9294
) -> TokenStream {
93-
if !any_bound && traits.iter().any(|trait_| trait_ == Trait::Copy) {
95+
if (derive_where.generics.is_empty() || derive_where.any_custom_bound())
96+
&& derive_where.contains(Trait::Copy)
97+
{
9498
return TokenStream::new();
9599
}
96100

src/trait_/common_ord.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ use syn::{parse_quote, Expr, ExprLit, LitInt, Path};
1414

1515
#[cfg(not(feature = "nightly"))]
1616
use crate::{item::Representation, Discriminant, Trait};
17-
use crate::{Data, DeriveTrait, Item, SimpleType, SplitGenerics};
17+
use crate::{Data, DeriveTrait, DeriveWhere, Item, SimpleType, SplitGenerics};
1818

1919
/// Build signature for [`PartialOrd`] and [`Ord`].
2020
pub fn build_ord_signature(
2121
item: &Item,
2222
#[cfg_attr(feature = "nightly", allow(unused_variables))] generics: &SplitGenerics<'_>,
23-
#[cfg_attr(feature = "nightly", allow(unused_variables))] traits: &[DeriveTrait],
23+
#[cfg_attr(feature = "nightly", allow(unused_variables))] derive_where: &DeriveWhere,
2424
trait_: &DeriveTrait,
2525
body: &TokenStream,
2626
) -> TokenStream {
@@ -173,13 +173,13 @@ pub fn build_ord_signature(
173173
}
174174
});
175175

176-
if traits.iter().any(|trait_| trait_ == Trait::Copy) {
176+
if derive_where.contains(Trait::Copy) {
177177
quote! {
178178
#validate
179179

180180
#path::#method(&(*self as isize), &(*__other as isize))
181181
}
182-
} else if traits.iter().any(|trait_| trait_ == Trait::Clone) {
182+
} else if derive_where.contains(Trait::Clone) {
183183
let clone = DeriveTrait::Clone.path();
184184
quote! {
185185
#validate
@@ -215,11 +215,11 @@ pub fn build_ord_signature(
215215
)
216216
}
217217
Discriminant::UnitRepr(repr) => {
218-
if traits.iter().any(|trait_| trait_ == Trait::Copy) {
218+
if derive_where.contains(Trait::Copy) {
219219
quote! {
220220
#path::#method(&(*self as #repr), &(*__other as #repr))
221221
}
222-
} else if traits.iter().any(|trait_| trait_ == Trait::Clone) {
222+
} else if derive_where.contains(Trait::Clone) {
223223
let clone = DeriveTrait::Clone.path();
224224
quote! {
225225
#path::#method(&(#clone::clone(self) as #repr), &(#clone::clone(__other) as #repr))

0 commit comments

Comments
 (0)