Skip to content

Commit 83fa0a6

Browse files
daxpeddaModProg
authored andcommitted
Account for as conversion requiring Copy/Clone
1 parent 0e99f7c commit 83fa0a6

File tree

7 files changed

+343
-28
lines changed

7 files changed

+343
-28
lines changed

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,9 @@ Unions only support [`Clone`] and [`Copy`].
285285
default too. Without this feature [`transmute`] is
286286
used to convert [`Discriminant`] to a [`i32`],
287287
which is the underlying type.
288-
- `safe`: Implements [`Ord`] and [`PartialOrd`] on enums with a non-default
289-
representation and at least one non-empty variant without unsafely
290-
accessing the discriminant. This is much slower, but might be preferred if
291-
you don't trust derive-where. It also replaces all cases of
288+
- `safe`: `safe`: Uses only safe ways to access the discriminant of the enum
289+
for [`Ord`] and [`PartialOrd`]. This is much slower, but might be
290+
preferred if you don't trust derive-where. It also replaces all cases of
292291
[`core::hint::unreachable_unchecked`] in [`Ord`], [`PartialEq`] and
293292
[`PartialOrd`], which is what std uses, with [`unreachable`].
294293
- `zeroize`: Allows deriving [`Zeroize`] and [`zeroize`][method@zeroize] on

src/item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ impl Item<'_> {
9898
/// Type of discriminant used.
9999
#[cfg_attr(test, derive(Debug))]
100100
pub enum Discriminant {
101+
/// The enum has only a single variant.
102+
Single,
101103
/// The enum uses the default representation but has a non-unit variant or
102104
/// an enum with a C representation without an integer representation.
103105
Unknown,
104-
/// The enum has only a single variant.
105-
Single,
106106
/// The enum uses the default representation and has only unit variants.
107107
UnitDefault,
108108
/// The enum uses a non-default representation and has only unit variants.

src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,9 @@
324324
//! default too. Without this feature [`transmute`](core::mem::transmute) is
325325
//! used to convert [`Discriminant`](core::mem::Discriminant) to a [`i32`],
326326
//! which is the underlying type.
327-
//! - `safe`: Implements [`Ord`] and [`PartialOrd`] on enums with a non-default
328-
//! representation and at least one non-empty variant without unsafely
329-
//! accessing the discriminant. This is much slower, but might be preferred if
330-
//! you don't trust derive-where. It also replaces all cases of
327+
//! - `safe`: `safe`: Uses only safe ways to access the discriminant of the enum
328+
//! for [`Ord`] and [`PartialOrd`]. This is much slower, but might be
329+
//! preferred if you don't trust derive-where. It also replaces all cases of
331330
//! [`core::hint::unreachable_unchecked`] in [`Ord`], [`PartialEq`] and
332331
//! [`PartialOrd`], which is what std uses, with [`unreachable`].
333332
//! - `zeroize`: Allows deriving [`Zeroize`] and [`zeroize`][method@zeroize] on

src/trait_/common_ord.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@ use syn::PatOr;
77

88
#[cfg(not(feature = "nightly"))]
99
use crate::Discriminant;
10-
use crate::{data::SimpleType, Data, DeriveTrait, Item};
10+
use crate::{Data, DeriveTrait, Item, SimpleType, Trait};
1111

1212
/// Build signature for [`PartialOrd`] and [`Ord`].
13-
pub fn build_ord_signature(item: &Item, trait_: &DeriveTrait, body: &TokenStream) -> TokenStream {
13+
pub fn build_ord_signature(
14+
item: &Item,
15+
traits: &[DeriveTrait],
16+
trait_: &DeriveTrait,
17+
body: &TokenStream,
18+
) -> TokenStream {
1419
let mut equal = quote! { ::core::cmp::Ordering::Equal };
1520

1621
// Add `Option` to `Ordering` if we are implementing `PartialOrd`.
@@ -122,23 +127,50 @@ pub fn build_ord_signature(item: &Item, trait_: &DeriveTrait, body: &TokenStream
122127
Discriminant::Single => {
123128
unreachable!("we should only generate this code with multiple variants")
124129
}
125-
Discriminant::UnitDefault => quote! {
126-
#path::#method(
127-
self as isize,
128-
__other as isize,
129-
)
130-
},
130+
Discriminant::UnitDefault => {
131+
if traits.iter().any(|trait_| trait_ == Trait::Copy) {
132+
quote! {
133+
#path::#method(
134+
*self as isize,
135+
*__other as isize,
136+
)
137+
}
138+
} else if traits.iter().any(|trait_| trait_ == Trait::Clone) {
139+
quote! {
140+
#path::#method(
141+
self.clone() as isize,
142+
__other.clone() as isize,
143+
)
144+
}
145+
} else {
146+
build_recursive_order(trait_, variants, &incomparable)
147+
}
148+
}
131149
Discriminant::Unknown => {
132150
build_recursive_order(trait_, variants, &incomparable)
133151
}
134-
Discriminant::UnitRepr(repr) => quote! {
135-
#path::#method(
136-
self as #repr,
137-
__other as #repr,
138-
)
139-
},
152+
#[cfg(feature = "safe")]
153+
Discriminant::UnitRepr(repr) => {
154+
if traits.iter().any(|trait_| trait_ == Trait::Copy) {
155+
quote! {
156+
#path::#method(
157+
*self as #repr,
158+
*__other as #repr,
159+
)
160+
}
161+
} else if traits.iter().any(|trait_| trait_ == Trait::Clone) {
162+
quote! {
163+
#path::#method(
164+
self.clone() as #repr,
165+
__other.clone() as #repr,
166+
)
167+
}
168+
} else {
169+
build_recursive_order(trait_, variants, &incomparable)
170+
}
171+
}
140172
#[cfg(not(feature = "safe"))]
141-
Discriminant::Repr(repr) => {
173+
Discriminant::UnitRepr(repr) | Discriminant::Repr(repr) => {
142174
quote! {
143175
#path::#method(
144176
unsafe { *<*const _>::from(self).cast::<#repr>() },

src/trait_/ord.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ impl TraitImpl for Ord {
2323
&self,
2424
_any_bound: bool,
2525
item: &Item,
26-
_traits: &[DeriveTrait],
26+
traits: &[DeriveTrait],
2727
trait_: &DeriveTrait,
2828
body: &TokenStream,
2929
) -> TokenStream {
30-
let body = common_ord::build_ord_signature(item, trait_, body);
30+
let body = common_ord::build_ord_signature(item, traits, trait_, body);
3131

3232
quote! {
3333
#[inline]

src/trait_/partial_ord.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ impl TraitImpl for PartialOrd {
3232
::core::option::Option::Some(::core::cmp::Ord::cmp(self, __other))
3333
}
3434
} else {
35-
common_ord::build_ord_signature(item, trait_, body)
35+
common_ord::build_ord_signature(item, traits, trait_, body)
3636
};
3737

3838
quote! {

0 commit comments

Comments
 (0)