This crate provides procedural macros to help you implement Rust-built-in traits quickly.
By default, every trait this crate supports will be enabled. You can disable all of them by disabling the default features and enable only the traits that you want to use by adding them to features
explictly.
For example,
[dependencies.educe]
version = "*"
features = ["Debug", "Default", "Hash", "Clone", "Copy"]
default-features = false
Use #[derive(Educe)]
and #[educe(Debug)]
to implement the Debug
trait for a struct, an enum, or a union. It supports to change the name of your types, variants and fields. You can also ignore some fields, or set a trait and/or a method to replace the Debug
trait used by default. Also, you can even format a struct to a tuple, and vice versa.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Debug)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Debug)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
The name
attribute can help you rename a type, a variant or a field.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Debug(name = "Struct2"))]
struct Struct {
#[educe(Debug(name = "f"))]
f1: u8
}
#[derive(Educe)]
#[educe(Debug(name = true))]
enum Enum {
#[educe(Debug(name = false))]
V1,
#[educe(Debug(name = "V"))]
V2 {
#[educe(Debug(name = "f"))]
f1: u8,
},
#[educe(Debug(name = false))]
V3(u8),
}
The ignore
attribute can ignore specific fields.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Debug)]
struct Struct {
#[educe(Debug(ignore))]
f1: u8
}
#[derive(Educe)]
#[educe(Debug)]
enum Enum {
V1,
V2 {
#[educe(Debug(ignore))]
f1: u8,
},
V3(
#[educe(Debug(ignore))]
u8
),
}
With the named_field
attribute, structs can be formatted as tuples and tuples can be formatted as structs.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Debug(named_field = false))]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Debug)]
enum Enum {
V1,
#[educe(Debug(named_field = false))]
V2 {
f1: u8,
},
#[educe(Debug(named_field = true))]
V3(
u8,
#[educe(Debug(name = "value"))]
i32
),
}
The trait
and method
attributes can be used to replace the Debug
trait for fields. If you only set the trait
parameter, the method
will be set to fmt
automatically by default.
#[macro_use] extern crate educe;
use std::fmt::{self, Formatter};
fn fmt(_s: &u8, f: &mut Formatter) -> fmt::Result {
f.write_str("Hi")
}
trait A {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("Hi")
}
}
impl A for i32 {};
impl A for u64 {};
#[derive(Educe)]
#[educe(Debug)]
enum Enum<T: A> {
V1,
V2 {
#[educe(Debug(method = "fmt"))]
f1: u8,
},
V3(
#[educe(Debug(trait = "std::fmt::UpperHex"))]
u8,
#[educe(Debug(trait = "A"))]
T
),
}
The #[educe(Debug(bound))]
attribute can be used to add the Debug
trait bound to all generic parameters for the Debug
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Debug(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
Or you can set the where predicates by yourself.
#[macro_use] extern crate educe;
use std::fmt::{self, Formatter};
fn fmt(_s: &u8, f: &mut Formatter) -> fmt::Result {
f.write_str("Hi")
}
trait A {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("Hi")
}
}
impl A for i32 {};
impl A for u64 {};
#[derive(Educe)]
#[educe(Debug(bound = "T: std::fmt::Debug, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Debug(trait = "A"))]
f1: K,
},
V3(
T
),
}
A union will be formatted to a u8
slice, because we don't know it's field at runtime. The fields of a union cannot be ignored, renamed or formated with other methods or traits.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Debug)]
struct Union {
f1: u8,
f2: i32,
}
Use #[derive(Educe)]
and #[educe(ParitalEq)]
to implement the ParitalEq
trait for a struct or an enum. It supports to ignore some fields, or set a trait and/or a method to replace the ParitalEq
trait used by default.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
The ignore
attribute can ignore specific fields.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq)]
struct Struct {
#[educe(PartialEq(ignore))]
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq)]
enum Enum {
V1,
V2 {
#[educe(PartialEq(ignore))]
f1: u8,
},
V3(
#[educe(PartialEq(ignore))]
u8
),
}
The trait
and method
attributes can be used to replace the PartialEq
trait for fields. If you only set the trait
parameter, the method
will be set to eq
automatically by default.
#[macro_use] extern crate educe;
fn eq(a: &u8, b: &u8) -> bool {
a + 1 == *b
}
trait A {
fn eq(&self, b: &Self) -> bool;
}
impl A for i32 {
fn eq(&self, b: &i32) -> bool {
self + 1 == *b
}
}
impl A for u64 {
fn eq(&self, b: &u64) -> bool {
self + 1 == *b
}
}
#[derive(Educe)]
#[educe(PartialEq)]
enum Enum<T: A> {
V1,
V2 {
#[educe(PartialEq(method = "eq"))]
f1: u8,
},
V3(
#[educe(PartialEq(trait = "A"))]
T
),
}
The #[educe(PartialEq(bound))]
attribute can be used to add the PartialEq
trait bound to all generic parameters for the PartialEq
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
Or you can set the where predicates by yourself.
#[macro_use] extern crate educe;
trait A {
fn eq(&self, b: &Self) -> bool;
}
impl A for i32 {
fn eq(&self, b: &i32) -> bool {
self + 1 == *b
}
}
impl A for u64 {
fn eq(&self, b: &u64) -> bool {
self + 1 == *b
}
}
#[derive(Educe)]
#[educe(PartialEq(bound = "T: std::cmp::PartialEq, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(PartialEq(trait = "A"))]
f1: K,
},
V3(
T
),
}
Use #[derive(Educe)]
and #[educe(Eq)]
to implement the Eq
trait for a struct, an enum or a union.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, Eq)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
The #[educe(Eq(bound))]
attribute can be used to add the Eq
trait bound to all generic parameters for the Eq
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq(bound), Eq(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
Or you can set the where predicates by yourself. (NOTE: The Eq
trait depends on the PartialEq
(PartialEq<Self>
) trait.)
#[macro_use] extern crate educe;
trait A {
fn eq(&self, b: &Self) -> bool;
}
impl A for i32 {
fn eq(&self, b: &i32) -> bool {
self + 1 == *b
}
}
impl A for u64 {
fn eq(&self, b: &u64) -> bool {
self + 1 == *b
}
}
#[derive(Educe)]
#[educe(PartialEq(bound = "T: std::cmp::PartialEq, K: A"), Eq(bound = "T: std::cmp::PartialEq, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(PartialEq(trait = "A"))]
f1: K,
},
V3(
T
),
}
Use #[derive(Educe)]
and #[educe(PartialOrd)]
to implement the PartialOrd
trait for a struct or an enum. It supports to ignore some fields, or set a trait and/or a method to replace the PartialOrd
trait used by default. The rank of variants and fields can also be modified.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
The ignore
attribute can ignore specific fields.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
struct Struct {
#[educe(PartialOrd(ignore))]
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum {
V1,
V2 {
#[educe(PartialOrd(ignore))]
f1: u8,
},
V3(
#[educe(PartialOrd(ignore))]
u8
),
}
The trait
and method
attributes can be used to replace the PartialOrd
trait for fields. If you only set the trait
parameter, the method
will be set to partial_cmp
automatically by default.
#[macro_use] extern crate educe;
use std::cmp::Ordering;
fn partial_cmp(a: &u8, b: &u8) -> Option<Ordering> {
if a > b {
Some(Ordering::Less)
} else if a < b {
Some(Ordering::Greater)
} else {
Some(Ordering::Equal)
}
}
trait A {
fn partial_cmp(&self, b: &Self) -> Option<Ordering>;
}
impl A for i32 {
fn partial_cmp(&self, b: &i32) -> Option<Ordering> {
if self > b {
Some(Ordering::Less)
} else if self < b {
Some(Ordering::Greater)
} else {
Some(Ordering::Equal)
}
}
}
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum<T: std::cmp::PartialEq + A> {
V1,
V2 {
#[educe(PartialOrd(method = "partial_cmp"))]
f1: u8,
},
V3(
#[educe(PartialOrd(trait = "A"))]
T
),
}
The #[educe(PartialOrd(bound))]
attribute can be used to add the PartialOrd
trait bound to all generic parameters for the PartialOrd
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq(bound), PartialOrd(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
Or you can set the where predicates by yourself. (NOTE: The PartialOrd
trait depends on the PartialEq
(PartialEq<Self>
) trait.)
#[macro_use] extern crate educe;
use std::cmp::Ordering;
trait A {
fn partial_cmp(&self, b: &Self) -> Option<Ordering>;
}
impl A for i32 {
fn partial_cmp(&self, b: &i32) -> Option<Ordering> {
if self > b {
Some(Ordering::Less)
} else if self < b {
Some(Ordering::Greater)
} else {
Some(Ordering::Equal)
}
}
}
#[derive(Educe)]
#[educe(PartialEq(bound), PartialOrd(bound = "T: std::cmp::PartialOrd, K: std::cmp::PartialOrd + A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(PartialOrd(trait = "A"))]
f1: K,
},
V3(
T
),
}
Each field can add a #[educe(PartialOrd(rank = priority_value))]
attribute where priority_value
is a positive integer value to determine their comparing precedence (lower priority_value
leads to higher priority). The default priority_value
for a field dependends on its ordinal (the lower the front) and is always lower than any custom priority_value
.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
struct Struct {
#[educe(PartialOrd(rank = 1))]
f1: u8,
#[educe(PartialOrd(rank = 0))]
f2: u8,
}
Each variant can add a #[educe(PartialOrd(rank = comparison_value))]
attribute where comparison_value
is a positive integer value to override the value or the ordinal of a variant for comparison.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, PartialOrd)]
enum Enum {
#[educe(PartialOrd(rank = 2))]
Two,
#[educe(PartialOrd(rank = 1))]
One,
}
Use #[derive(Educe)]
and #[educe(Ord)]
to implement the Ord
trait for a struct or an enum. It supports to ignore some fields, or set a trait and/or a method to replace the Ord
trait used by default. The rank of variants and fields can also be modified.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
The ignore
attribute can ignore specific fields.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
struct Struct {
#[educe(Ord(ignore))]
f1: u8
}
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum {
V1,
V2 {
#[educe(Ord(ignore))]
f1: u8,
},
V3(
#[educe(Ord(ignore))]
u8
),
}
The trait
and method
attributes can be used to replace the Ord
trait for fields. If you only set the trait
parameter, the method
will be set to cmp
automatically by default.
#[macro_use] extern crate educe;
use std::cmp::Ordering;
fn cmp(a: &u8, b: &u8) -> Ordering {
if a > b {
Ordering::Less
} else if a < b {
Ordering::Greater
} else {
Ordering::Equal
}
}
trait A {
fn cmp(&self, b: &Self) -> Ordering;
}
impl A for i32 {
fn cmp(&self, b: &i32) -> Ordering {
if self > b {
Ordering::Less
} else if self < b {
Ordering::Greater
} else {
Ordering::Equal
}
}
}
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum<T: std::cmp::PartialOrd + A> {
V1,
V2 {
#[educe(Ord(method = "cmp"))]
f1: u8,
},
V3(
#[educe(Ord(trait = "A"))]
T
),
}
The #[educe(Ord(bound))]
attribute can be used to add the Ord
trait bound to all generic parameters for the Ord
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq(bound), Eq(bound), PartialOrd(bound), Ord(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
Or you can set the where predicates by yourself. (NOTE: The Ord
trait depends on the PartialOrd
(PartialOrd<Self>
) trait and the Eq
trait.)
#[macro_use] extern crate educe;
use std::cmp::Ordering;
trait A {
fn cmp(&self, b: &Self) -> Ordering;
}
impl A for i32 {
fn cmp(&self, b: &i32) -> Ordering {
if self > b {
Ordering::Less
} else if self < b {
Ordering::Greater
} else {
Ordering::Equal
}
}
}
#[derive(Educe)]
#[educe(PartialEq(bound), Eq(bound), PartialOrd(bound), Ord(bound = "T: std::cmp::Ord, K: std::cmp::Ord + A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Ord(trait = "A"))]
f1: K,
},
V3(
T
),
}
Each field can add a #[educe(Ord(rank = priority_value))]
attribute where priority_value
is a positive integer value to determine their comparing precedence (lower priority_value
leads to higher priority). The default priority_value
for a field dependends on its ordinal (the lower the front) and is always lower than any custom priority_value
.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
struct Struct {
#[educe(Ord(rank = 1))]
f1: u8,
#[educe(Ord(rank = 0))]
f2: u8,
}
Each variant can add a #[educe(Ord(rank = comparison_value))]
attribute where comparison_value
is a positive integer value to override the value or the ordinal of a variant for comparison.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(PartialEq, Eq, PartialOrd, Ord)]
enum Enum {
#[educe(Ord(rank = 2))]
Two,
#[educe(Ord(rank = 1))]
One,
}
Use #[derive(Educe)]
and #[educe(Hash)]
to implement the Hash
trait for a struct or an enum. It supports to ignore some fields, or set a trait and/or a method to replace the Hash
trait used by default.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Hash)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Hash)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
The ignore
attribute can ignore specific fields.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Hash)]
struct Struct {
#[educe(Hash(ignore))]
f1: u8
}
#[derive(Educe)]
#[educe(Hash)]
enum Enum {
V1,
V2 {
#[educe(Hash(ignore))]
f1: u8,
},
V3(
#[educe(Hash(ignore))]
u8
),
}
The trait
and method
attributes can be used to replace the Hash
trait for fields. If you only set the trait
parameter, the method
will be set to hash
automatically by default.
#[macro_use] extern crate educe;
use std::hash::{Hash, Hasher};
fn hash<H: Hasher>(_s: &u8, state: &mut H) {
Hash::hash(&100, state)
}
trait A {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&100, state)
}
}
impl A for i32 {};
impl A for u64 {};
#[derive(Educe)]
#[educe(Hash)]
enum Enum<T: A> {
V1,
V2 {
#[educe(Hash(method = "hash"))]
f1: u8,
},
V3(
#[educe(Hash(trait = "A"))]
T
),
}
The #[educe(Hash(bound))]
attribute can be used to add the Hash
trait bound to all generic parameters for the Hash
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Hash(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
Or you can set the where predicates by yourself.
#[macro_use] extern crate educe;
use std::hash::{Hash, Hasher};
fn hash<H: Hasher>(_s: &u8, state: &mut H) {
Hash::hash(&100, state)
}
trait A {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&100, state)
}
}
impl A for i32 {};
impl A for u64 {};
#[derive(Educe)]
#[educe(Hash(bound = "T: std::hash::Hash, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Hash(trait = "A"))]
f1: K,
},
V3(
T
),
}
Use #[derive(Educe)]
and #[educe(Default)]
to implement the Default
trait for a struct, an enum, or a union. It supports to set the default value for your type directly, or set the default values for specific fields.
For enums and unions, you need to assign a variant (of a enum) and a field (of a union) as default unless the number of variants of an enum or the number of fields of a union is exactly one.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Default)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Default)]
enum Enum {
V1,
#[educe(Default)]
V2 {
f1: u8,
},
V3(u8),
}
#[derive(Educe)]
#[educe(Default)]
union Union {
f1: u8,
#[educe(Default)]
f2: f64,
}
The #[educe(Default(expression = "expression"))]
attribute can be used to set the default value for your type by an expression.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Default(expression = "Struct { f1: 1 }"))]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Default(expression = "Enum::Struct { f1: 1 }"))]
enum Enum {
Unit,
Struct {
f1: u8
},
Tuple(u8),
}
#[derive(Educe)]
#[educe(Default(expression = "Union { f1: 1 }"))]
union Union {
f1: u8,
f2: f64,
}
The #[educe(Default = literal)]
attribute or the #[educe(Default(expression = "expression"))]
attribute can be used to set the default value for a specific field by a literal value or an expression.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Default)]
struct Struct {
#[educe(Default = 1)]
f1: u8,
#[educe(Default = 11111111111111111111111111111)]
f2: i128,
#[educe(Default = 1.1)]
f3: f64,
#[educe(Default = true)]
f4: bool,
#[educe(Default = "Hi")]
f5: &'static str,
#[educe(Default = "Hello")]
f6: String,
#[educe(Default = 'M')]
f7: char,
}
#[derive(Educe)]
#[educe(Default)]
enum Enum {
Unit,
#[educe(Default)]
Tuple(
#[educe(Default(expression = "0 + 1"))]
u8,
#[educe(Default(expression = "-11111111111111111111111111111 * -1"))]
i128,
#[educe(Default(expression = "1.0 + 0.1"))]
f64,
#[educe(Default(expression = "!false"))]
bool,
#[educe(Default(expression = "\"Hi\""))]
&'static str,
#[educe(Default(expression = "String::from(\"Hello\")"))]
String,
#[educe(Default(expression = "'M'"))]
char,
),
}
#[derive(Educe)]
#[educe(Default)]
union Union {
f1: u8,
f2: i128,
f3: f64,
f4: bool,
#[educe(Default = "Hi")]
f5: &'static str,
f6: char,
}
The #[educe(Default(bound))]
attribute can be used to add the Default
trait bound to all generic parameters for the Default
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Default(bound))]
enum Enum<T> {
Unit,
#[educe(Default)]
Struct {
f1: T
},
Tuple(T),
}
Or you can set the where predicates by yourself.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Default(bound = "T: std::default::Default"))]
enum Enum<T> {
Unit,
#[educe(Default)]
Struct {
f1: T
},
Tuple(T),
}
With the #[educe(Default(new))]
attribute, your type will have an extra associated function called new
. That can be used to invoke the default
method of the Default
trait.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Default(new))]
struct Struct {
f1: u8
}
Use #[derive(Educe)]
and #[educe(Clone)]
to implement the Clone
trait for a struct, an enum, or a union. It supports to set a trait and/or a method to replace the Clone
trait used by default.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Clone)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Clone)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
The trait
and method
attributes can be used to replace the Clone
trait for fields. If you only set the trait
parameter, the method
will be set to clone
automatically by default.
#[macro_use] extern crate educe;
fn clone(v: &u8) -> u8 {
v + 100
}
trait A {
fn clone(&self) -> Self;
}
impl A for i32 {
fn clone(&self) -> i32 {
self + 100
}
}
impl A for u64 {
fn clone(&self) -> u64 {
self + 100
}
}
#[derive(Educe)]
#[educe(Clone)]
enum Enum<T: A> {
V1,
V2 {
#[educe(Clone(method = "clone"))]
f1: u8,
},
V3(
#[educe(Clone(trait = "A"))]
T
),
}
The #[educe(Clone(bound))]
attribute can be used to add the Clone
trait bound or the Copy
trait bound (if the #[educe(Copy)]
attribute exists) to all generic parameters for the Clone
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Clone(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
Or you can set the where predicates by yourself.
#[macro_use] extern crate educe;
fn clone(v: &u8) -> u8 {
v + 100
}
trait A {
fn clone(&self) -> Self;
}
impl A for i32 {
fn clone(&self) -> i32 {
self + 100
}
}
impl A for u64 {
fn clone(&self) -> u64 {
self + 100
}
}
#[derive(Educe)]
#[educe(Clone(bound = "T: std::clone::Clone, K: A"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Clone(trait = "A"))]
f1: K,
},
V3(
T
),
}
The #[educe(Clone)]
attribute can be used for a union which also needs to implement the Copy
trait. The fields of a union cannot be cloned with other methods or traits.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Copy, Clone)]
union Union {
f1: u8,
}
Use #[derive(Educe)]
and #[educe(Copy)]
to implement the Copy
trait for a struct, an enum, or a union.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Copy, Clone)]
struct Struct {
f1: u8
}
#[derive(Educe)]
#[educe(Copy, Clone)]
enum Enum {
V1,
V2 {
f1: u8,
},
V3(u8),
}
The #[educe(Copy(bound))]
attribute can be used to add the Copy
trait bound to all generic parameters for the Copy
implementation.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Copy(bound), Clone(bound))]
enum Enum<T, K> {
V1,
V2 {
f1: K,
},
V3(
T
),
}
Or you can set the where predicates by yourself.
#[macro_use] extern crate educe;
fn clone(v: &u8) -> u8 {
v + 100
}
trait A {
fn clone(&self) -> Self;
}
impl A for i32 {
fn clone(&self) -> i32 {
self + 100
}
}
impl A for u64 {
fn clone(&self) -> u64 {
self + 100
}
}
#[derive(Educe)]
#[educe(Copy(bound = "T: Copy, K: A + Copy"), Clone(bound = "T: Copy, K: A + Copy"))]
enum Enum<T, K> {
V1,
V2 {
#[educe(Clone(trait = "A"))]
f1: K,
},
V3(
T
),
}
If you implement both of the Copy
trait and the Clone
trait by Educe, the bound for the Clone
trait needs to include the Copy
trait due to Copy, Clone
optimization.
Use #[derive(Educe)]
and #[educe(Deref)]
to implement the Deref
trait for a struct or an enum.
You need to assign a field as a default inmutable dereferencing field unless the number of fields is exactly one.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Deref)]
struct Struct {
f1: u8,
#[educe(Deref)]
f2: u8,
}
#[derive(Educe)]
#[educe(Deref)]
enum Enum {
Struct {
f1: u8
},
Struct2 {
f1: u8,
#[educe(Deref)]
f2: u8,
},
Tuple(u8),
Tuple2(
u8,
#[educe(Deref)]
u8
),
}
Use #[derive(Educe)]
and #[educe(DerefMut)]
to implement the DerefMut
trait for a struct or an enum.
You need to assign a field as a default mutable dereferencing field unless the number of fields is exactly one.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Deref, DerefMut)]
struct Struct {
f1: u8,
#[educe(Deref, DerefMut)]
f2: u8,
}
#[derive(Educe)]
#[educe(Deref, DerefMut)]
enum Enum {
Struct {
f1: u8
},
Struct2 {
f1: u8,
#[educe(Deref, DerefMut)]
f2: u8,
},
Tuple(u8),
Tuple2(
#[educe(DerefMut)]
u8,
#[educe(Deref)]
u8
),
}
The mutable dereferencing fields don't need to be the same as the inmutable dereferencing fields. But their type must be the same.
There is a lot of work to be done. Unimplemented traits are listed below:
From
Into
FromStr
TryFrom
TryInto