Skip to content

Commit

Permalink
Merge branch 'ijackson-all-bounds'
Browse files Browse the repository at this point in the history
  • Loading branch information
magiclen committed Jun 1, 2024
2 parents fca9263 + b7567cb commit 9e23e34
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 2 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,29 @@ enum Enum<T, K> {

In the above case, `T` is bound to the `Debug` trait, but `K` is not.

Or, you can have `educe` replicate the behaviour of `std`'s `derive`'s,
where a bound is produced for *every* generic parameter,
without regard to how it's used in the structure:

```rust
#[derive(Educe)]
#[educe(Debug(bound(*)))]
struct Struct<T> {
#[educe(Debug(ignore))]
f: T,
}
```

This can be useful if you don't want to make the trait implementation
part of your permanent public API.
In this example,
`Struct<T>` doesn't implement `Debug` unless `T` does.
I.e., it has a `T: Debug` bound even though that's not needed right now.
Later we might want to display `f`; we wouldn't then need to make
a breaking API change by adding the bound.

This was the behaviour of `Trait(bound)` in educe 0.4.x and earlier.

###### Union

A union will be formatted as a `u8` slice because we don't know its fields at runtime. The fields of a union cannot be ignored, renamed, or formatted with other methods. The implementation is **unsafe** because it may expose uninitialized memory.
Expand Down
6 changes: 5 additions & 1 deletion src/common/bound.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use syn::{punctuated::Punctuated, token::Comma, GenericParam, Meta, Path, Type, WherePredicate};

use crate::common::where_predicates_bool::{
create_where_predicates_from_all_generic_parameters,
create_where_predicates_from_generic_parameters_check_types, meta_2_where_predicates,
WherePredicates, WherePredicatesOrBool,
};
Expand All @@ -9,6 +10,7 @@ pub(crate) enum Bound {
Disabled,
Auto,
Custom(WherePredicates),
All,
}

impl Bound {
Expand All @@ -27,6 +29,7 @@ impl Bound {
Self::Disabled
}
},
WherePredicatesOrBool::All => Self::All,
})
}
}
Expand All @@ -35,7 +38,7 @@ impl Bound {
#[inline]
pub(crate) fn into_where_predicates_by_generic_parameters_check_types(
self,
_params: &Punctuated<GenericParam, Comma>,
params: &Punctuated<GenericParam, Comma>,
bound_trait: &Path,
types: &[&Type],
supertraits: &[proc_macro2::TokenStream],
Expand All @@ -48,6 +51,7 @@ impl Bound {
supertraits,
),
Self::Custom(where_predicates) => where_predicates,
Self::All => create_where_predicates_from_all_generic_parameters(params, bound_trait),
}
}
}
6 changes: 5 additions & 1 deletion src/common/where_predicates_bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub(crate) type WherePredicates = Punctuated<WherePredicate, Token![,]>;
pub(crate) enum WherePredicatesOrBool {
WherePredicates(WherePredicates),
Bool(bool),
All,
}

impl WherePredicatesOrBool {
Expand Down Expand Up @@ -42,6 +43,10 @@ impl Parse for WherePredicatesOrBool {
return Self::from_lit(&lit);
}

if let Ok(_star) = input.parse::<Token![*]>() {
return Ok(Self::All);
}

Ok(Self::WherePredicates(input.parse_terminated(WherePredicate::parse, Token![,])?))
}
}
Expand Down Expand Up @@ -80,7 +85,6 @@ pub(crate) fn meta_2_where_predicates(meta: &Meta) -> syn::Result<WherePredicate
}

#[inline]
#[allow(dead_code)]
pub(crate) fn create_where_predicates_from_all_generic_parameters(
params: &Punctuated<GenericParam, Comma>,
bound_trait: &Path,
Expand Down
30 changes: 30 additions & 0 deletions tests/clone_struct.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![cfg(feature = "Clone")]
#![no_std]

use core::marker::PhantomData;

use educe::Educe;

#[test]
Expand Down Expand Up @@ -169,3 +171,31 @@ fn bound_3() {
assert_eq!(1, s.f1);
assert_eq!(1, t.0);
}

#[test]
fn bound_4() {
struct NotClone;

#[derive(Educe)]
// without `bound(*)` we get E0034: multiple applicable items in scope
// when we call Struct<NotClone>.clone(), since .clone() is then ambiguous
#[educe(Clone(bound(*)))]
struct Struct<T> {
f1: PhantomData<T>,
}

trait ClashingFakeClone {
fn clone(&self) {}
}
impl ClashingFakeClone for Struct<NotClone> {}

let _: () = Struct {
f1: PhantomData::<NotClone>
}
.clone();

let _: Struct<_> = Struct {
f1: PhantomData::<()>
}
.clone();
}

0 comments on commit 9e23e34

Please sign in to comment.