educe/lib.rs
1/*!
2# Educe
3
4This crate provides procedural macros to help you implement Rust-built-in traits quickly.
5
6## Features
7
8By 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.
9
10For example,
11
12```toml
13[dependencies.educe]
14version = "*"
15features = ["Debug", "Default", "Hash", "Clone", "Copy"]
16default-features = false
17```
18
19## Debug
20
21Use `#[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.
22
23#### Basic Usage
24
25```rust
26#[macro_use] extern crate educe;
27
28#[derive(Educe)]
29#[educe(Debug)]
30struct Struct {
31 f1: u8
32}
33
34#[derive(Educe)]
35#[educe(Debug)]
36enum Enum {
37 V1,
38 V2 {
39 f1: u8,
40 },
41 V3(u8),
42}
43```
44
45#### Change the Name of a Type, a Variant or a Field
46
47The `name` attribute can help you rename a type, a variant or a field.
48
49```rust
50#[macro_use] extern crate educe;
51
52#[derive(Educe)]
53#[educe(Debug(name = "Struct2"))]
54struct Struct {
55 #[educe(Debug(name = "f"))]
56 f1: u8
57}
58
59#[derive(Educe)]
60#[educe(Debug(name = true))]
61enum Enum {
62 #[educe(Debug(name = false))]
63 V1,
64 #[educe(Debug(name = "V"))]
65 V2 {
66 #[educe(Debug(name = "f"))]
67 f1: u8,
68 },
69 #[educe(Debug(name = false))]
70 V3(u8),
71}
72```
73
74#### Ignore Fields
75
76The `ignore` attribute can ignore specific fields.
77
78```rust
79#[macro_use] extern crate educe;
80
81#[derive(Educe)]
82#[educe(Debug)]
83struct Struct {
84 #[educe(Debug(ignore))]
85 f1: u8
86}
87
88#[derive(Educe)]
89#[educe(Debug)]
90enum Enum {
91 V1,
92 V2 {
93 #[educe(Debug(ignore))]
94 f1: u8,
95 },
96 V3(
97 #[educe(Debug(ignore))]
98 u8
99 ),
100}
101```
102
103#### Fake Structs and Tuples
104
105With the `named_field` attribute, structs can be formatted as tuples and tuples can be formatted as structs.
106
107```rust
108#[macro_use] extern crate educe;
109
110#[derive(Educe)]
111#[educe(Debug(named_field = false))]
112struct Struct {
113 f1: u8
114}
115
116#[derive(Educe)]
117#[educe(Debug)]
118enum Enum {
119 V1,
120 #[educe(Debug(named_field = false))]
121 V2 {
122 f1: u8,
123 },
124 #[educe(Debug(named_field = true))]
125 V3(
126 u8,
127 #[educe(Debug(name = "value"))]
128 i32
129 ),
130}
131```
132
133#### Use Another Method or Trait to Do the Format Thing
134
135The `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.
136
137```rust
138#[macro_use] extern crate educe;
139
140use std::fmt::{self, Formatter};
141
142fn fmt(_s: &u8, f: &mut Formatter) -> fmt::Result {
143 f.write_str("Hi")
144}
145
146trait A {
147 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
148 f.write_str("Hi")
149 }
150}
151
152impl A for i32 {};
153impl A for u64 {};
154
155#[derive(Educe)]
156#[educe(Debug)]
157enum Enum<T: A> {
158 V1,
159 V2 {
160 #[educe(Debug(method = "fmt"))]
161 f1: u8,
162 },
163 V3(
164 #[educe(Debug(trait = "std::fmt::UpperHex"))]
165 u8,
166 #[educe(Debug(trait = "A"))]
167 T
168 ),
169}
170```
171
172#### Generic Parameters Bound to the `Debug` Trait or Others
173
174The `#[educe(Debug(bound))]` attribute can be used to add the `Debug` trait bound to all generic parameters for the `Debug` implementation.
175
176```rust
177#[macro_use] extern crate educe;
178
179#[derive(Educe)]
180#[educe(Debug(bound))]
181enum Enum<T, K> {
182 V1,
183 V2 {
184 f1: K,
185 },
186 V3(
187 T
188 ),
189}
190```
191
192Or you can set the where predicates by yourself.
193
194```rust
195#[macro_use] extern crate educe;
196
197use std::fmt::{self, Formatter};
198
199fn fmt(_s: &u8, f: &mut Formatter) -> fmt::Result {
200 f.write_str("Hi")
201}
202
203trait A {
204 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
205 f.write_str("Hi")
206 }
207}
208
209impl A for i32 {};
210impl A for u64 {};
211
212#[derive(Educe)]
213#[educe(Debug(bound = "T: std::fmt::Debug, K: A"))]
214enum Enum<T, K> {
215 V1,
216 V2 {
217 #[educe(Debug(trait = "A"))]
218 f1: K,
219 },
220 V3(
221 T
222 ),
223}
224```
225
226#### Union
227
228A 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.
229
230```rust
231#[macro_use] extern crate educe;
232
233#[derive(Educe)]
234#[educe(Debug)]
235struct Union {
236 f1: u8,
237 f2: i32,
238}
239```
240
241## PartialEq
242
243Use `#[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.
244
245#### Basic Usage
246
247```rust
248#[macro_use] extern crate educe;
249
250#[derive(Educe)]
251#[educe(PartialEq)]
252struct Struct {
253 f1: u8
254}
255
256#[derive(Educe)]
257#[educe(PartialEq)]
258enum Enum {
259 V1,
260 V2 {
261 f1: u8,
262 },
263 V3(u8),
264}
265```
266
267#### Ignore Fields
268
269The `ignore` attribute can ignore specific fields.
270
271```rust
272#[macro_use] extern crate educe;
273
274#[derive(Educe)]
275#[educe(PartialEq)]
276struct Struct {
277 #[educe(PartialEq(ignore))]
278 f1: u8
279}
280
281#[derive(Educe)]
282#[educe(PartialEq)]
283enum Enum {
284 V1,
285 V2 {
286 #[educe(PartialEq(ignore))]
287 f1: u8,
288 },
289 V3(
290 #[educe(PartialEq(ignore))]
291 u8
292 ),
293}
294```
295
296#### Use Another Method or Trait to Do Comparing
297
298The `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.
299
300```rust
301#[macro_use] extern crate educe;
302
303fn eq(a: &u8, b: &u8) -> bool {
304 a + 1 == *b
305}
306
307trait A {
308 fn eq(&self, b: &Self) -> bool;
309}
310
311impl A for i32 {
312 fn eq(&self, b: &i32) -> bool {
313 self + 1 == *b
314 }
315}
316
317impl A for u64 {
318 fn eq(&self, b: &u64) -> bool {
319 self + 1 == *b
320 }
321}
322
323#[derive(Educe)]
324#[educe(PartialEq)]
325enum Enum<T: A> {
326 V1,
327 V2 {
328 #[educe(PartialEq(method = "eq"))]
329 f1: u8,
330 },
331 V3(
332 #[educe(PartialEq(trait = "A"))]
333 T
334 ),
335}
336```
337
338#### Generic Parameters Bound to the `PartialEq` Trait or Others
339
340The `#[educe(PartialEq(bound))]` attribute can be used to add the `PartialEq` trait bound to all generaic parameters for the `PartialEq` implementation.
341
342```rust
343#[macro_use] extern crate educe;
344
345#[derive(Educe)]
346#[educe(PartialEq(bound))]
347enum Enum<T, K> {
348 V1,
349 V2 {
350 f1: K,
351 },
352 V3(
353 T
354 ),
355}
356```
357
358Or you can set the where predicates by yourself.
359
360```rust
361#[macro_use] extern crate educe;
362
363trait A {
364 fn eq(&self, b: &Self) -> bool;
365}
366
367impl A for i32 {
368 fn eq(&self, b: &i32) -> bool {
369 self + 1 == *b
370 }
371}
372
373impl A for u64 {
374 fn eq(&self, b: &u64) -> bool {
375 self + 1 == *b
376 }
377}
378
379#[derive(Educe)]
380#[educe(PartialEq(bound = "T: std::cmp::PartialEq, K: A"))]
381enum Enum<T, K> {
382 V1,
383 V2 {
384 #[educe(PartialEq(trait = "A"))]
385 f1: K,
386 },
387 V3(
388 T
389 ),
390}
391```
392
393## Eq
394
395Use `#[derive(Educe)]` and `#[educe(Eq)]` to implement the `Eq` trait for a struct, an enum or a union.
396
397#### Basic Usage
398
399```rust
400#[macro_use] extern crate educe;
401
402#[derive(Educe)]
403#[educe(PartialEq, Eq)]
404struct Struct {
405 f1: u8
406}
407
408#[derive(Educe)]
409#[educe(PartialEq, Eq)]
410enum Enum {
411 V1,
412 V2 {
413 f1: u8,
414 },
415 V3(u8),
416}
417```
418
419#### Generic Parameters Bound to the `Eq` Trait or Others
420
421The `#[educe(Eq(bound))]` attribute can be used to add the `Eq` trait bound to all generaic parameters for the `Eq` implementation.
422
423```rust
424#[macro_use] extern crate educe;
425
426#[derive(Educe)]
427#[educe(PartialEq(bound), Eq(bound))]
428enum Enum<T, K> {
429 V1,
430 V2 {
431 f1: K,
432 },
433 V3(
434 T
435 ),
436}
437```
438
439Or you can set the where predicates by yourself. (NOTE: The `Eq` trait depends on the `PartialEq` (`PartialEq<Self>`) trait.)
440
441```rust
442#[macro_use] extern crate educe;
443
444trait A {
445 fn eq(&self, b: &Self) -> bool;
446}
447
448impl A for i32 {
449 fn eq(&self, b: &i32) -> bool {
450 self + 1 == *b
451 }
452}
453
454impl A for u64 {
455 fn eq(&self, b: &u64) -> bool {
456 self + 1 == *b
457 }
458}
459
460#[derive(Educe)]
461#[educe(PartialEq(bound = "T: std::cmp::PartialEq, K: A"), Eq(bound = "T: std::cmp::PartialEq, K: A"))]
462enum Enum<T, K> {
463 V1,
464 V2 {
465 #[educe(PartialEq(trait = "A"))]
466 f1: K,
467 },
468 V3(
469 T
470 ),
471}
472```
473
474## PartialOrd
475
476Use `#[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.
477
478#### Basic Usage
479
480```rust
481#[macro_use] extern crate educe;
482
483#[derive(Educe)]
484#[educe(PartialEq, PartialOrd)]
485struct Struct {
486 f1: u8
487}
488
489#[derive(Educe)]
490#[educe(PartialEq, PartialOrd)]
491enum Enum {
492 V1,
493 V2 {
494 f1: u8,
495 },
496 V3(u8),
497}
498```
499
500#### Ignore Fields
501
502The `ignore` attribute can ignore specific fields.
503
504```rust
505#[macro_use] extern crate educe;
506
507#[derive(Educe)]
508#[educe(PartialEq, PartialOrd)]
509struct Struct {
510 #[educe(PartialOrd(ignore))]
511 f1: u8
512}
513
514#[derive(Educe)]
515#[educe(PartialEq, PartialOrd)]
516enum Enum {
517 V1,
518 V2 {
519 #[educe(PartialOrd(ignore))]
520 f1: u8,
521 },
522 V3(
523 #[educe(PartialOrd(ignore))]
524 u8
525 ),
526}
527```
528
529#### Use Another Method or Trait to Do Comparing
530
531The `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.
532
533```rust
534#[macro_use] extern crate educe;
535
536use std::cmp::Ordering;
537
538fn partial_cmp(a: &u8, b: &u8) -> Option<Ordering> {
539 if a > b {
540 Some(Ordering::Less)
541 } else if a < b {
542 Some(Ordering::Greater)
543 } else {
544 Some(Ordering::Equal)
545 }
546}
547
548trait A {
549 fn partial_cmp(&self, b: &Self) -> Option<Ordering>;
550}
551
552impl A for i32 {
553 fn partial_cmp(&self, b: &i32) -> Option<Ordering> {
554 if self > b {
555 Some(Ordering::Less)
556 } else if self < b {
557 Some(Ordering::Greater)
558 } else {
559 Some(Ordering::Equal)
560 }
561 }
562}
563
564#[derive(Educe)]
565#[educe(PartialEq, PartialOrd)]
566enum Enum<T: std::cmp::PartialEq + A> {
567 V1,
568 V2 {
569 #[educe(PartialOrd(method = "partial_cmp"))]
570 f1: u8,
571 },
572 V3(
573 #[educe(PartialOrd(trait = "A"))]
574 T
575 ),
576}
577```
578
579#### Generic Parameters Bound to the `PartialOrd` Trait or Others
580
581The `#[educe(PartialOrd(bound))]` attribute can be used to add the `PartialOrd` trait bound to all generaic parameters for the `PartialOrd` implementation.
582
583```rust
584#[macro_use] extern crate educe;
585
586#[derive(Educe)]
587#[educe(PartialEq(bound), PartialOrd(bound))]
588enum Enum<T, K> {
589 V1,
590 V2 {
591 f1: K,
592 },
593 V3(
594 T
595 ),
596}
597```
598
599Or you can set the where predicates by yourself. (NOTE: The `PartialOrd` trait depends on the `PartialEq` (`PartialEq<Self>`) trait.)
600
601```rust
602#[macro_use] extern crate educe;
603
604use std::cmp::Ordering;
605
606trait A {
607 fn partial_cmp(&self, b: &Self) -> Option<Ordering>;
608}
609
610impl A for i32 {
611 fn partial_cmp(&self, b: &i32) -> Option<Ordering> {
612 if self > b {
613 Some(Ordering::Less)
614 } else if self < b {
615 Some(Ordering::Greater)
616 } else {
617 Some(Ordering::Equal)
618 }
619 }
620}
621
622#[derive(Educe)]
623#[educe(PartialEq(bound), PartialOrd(bound = "T: std::cmp::PartialOrd, K: std::cmp::PartialOrd + A"))]
624enum Enum<T, K> {
625 V1,
626 V2 {
627 #[educe(PartialOrd(trait = "A"))]
628 f1: K,
629 },
630 V3(
631 T
632 ),
633}
634```
635
636#### Ranking
637
638Each 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`.
639
640```rust
641#[macro_use] extern crate educe;
642
643#[derive(Educe)]
644#[educe(PartialEq, PartialOrd)]
645struct Struct {
646 #[educe(PartialOrd(rank = 1))]
647 f1: u8,
648 #[educe(PartialOrd(rank = 0))]
649 f2: u8,
650}
651```
652
653Each 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.
654
655```rust
656#[macro_use] extern crate educe;
657
658#[derive(Educe)]
659#[educe(PartialEq, PartialOrd)]
660enum Enum {
661 #[educe(PartialOrd(rank = 2))]
662 Two,
663 #[educe(PartialOrd(rank = 1))]
664 One,
665}
666```
667
668## Ord
669
670Use `#[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.
671
672#### Basic Usage
673
674```rust
675#[macro_use] extern crate educe;
676
677#[derive(Educe)]
678#[educe(PartialEq, Eq, PartialOrd, Ord)]
679struct Struct {
680 f1: u8
681}
682
683#[derive(Educe)]
684#[educe(PartialEq, Eq, PartialOrd, Ord)]
685enum Enum {
686 V1,
687 V2 {
688 f1: u8,
689 },
690 V3(u8),
691}
692```
693
694#### Ignore Fields
695
696The `ignore` attribute can ignore specific fields.
697
698```rust
699#[macro_use] extern crate educe;
700
701#[derive(Educe)]
702#[educe(PartialEq, Eq, PartialOrd, Ord)]
703struct Struct {
704 #[educe(Ord(ignore))]
705 f1: u8
706}
707
708#[derive(Educe)]
709#[educe(PartialEq, Eq, PartialOrd, Ord)]
710enum Enum {
711 V1,
712 V2 {
713 #[educe(Ord(ignore))]
714 f1: u8,
715 },
716 V3(
717 #[educe(Ord(ignore))]
718 u8
719 ),
720}
721```
722
723#### Use Another Method or Trait to Do Comparing
724
725The `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.
726
727```rust
728#[macro_use] extern crate educe;
729
730use std::cmp::Ordering;
731
732fn cmp(a: &u8, b: &u8) -> Ordering {
733 if a > b {
734 Ordering::Less
735 } else if a < b {
736 Ordering::Greater
737 } else {
738 Ordering::Equal
739 }
740}
741
742trait A {
743 fn cmp(&self, b: &Self) -> Ordering;
744}
745
746impl A for i32 {
747 fn cmp(&self, b: &i32) -> Ordering {
748 if self > b {
749 Ordering::Less
750 } else if self < b {
751 Ordering::Greater
752 } else {
753 Ordering::Equal
754 }
755 }
756}
757
758#[derive(Educe)]
759#[educe(PartialEq, Eq, PartialOrd, Ord)]
760enum Enum<T: std::cmp::PartialOrd + A> {
761 V1,
762 V2 {
763 #[educe(Ord(method = "cmp"))]
764 f1: u8,
765 },
766 V3(
767 #[educe(Ord(trait = "A"))]
768 T
769 ),
770}
771```
772
773#### Generic Parameters Bound to the `Ord` Trait or Others
774
775The `#[educe(Ord(bound))]` attribute can be used to add the `Ord` trait bound to all generaic parameters for the `Ord` implementation.
776
777```rust
778#[macro_use] extern crate educe;
779
780#[derive(Educe)]
781#[educe(PartialEq(bound), Eq(bound), PartialOrd(bound), Ord(bound))]
782enum Enum<T, K> {
783 V1,
784 V2 {
785 f1: K,
786 },
787 V3(
788 T
789 ),
790}
791```
792
793Or you can set the where predicates by yourself. (NOTE: The `Ord` trait depends on the `PartialOrd` (`PartialOrd<Self>`) trait and the `Eq` trait.)
794
795```rust
796#[macro_use] extern crate educe;
797
798use std::cmp::Ordering;
799
800trait A {
801 fn cmp(&self, b: &Self) -> Ordering;
802}
803
804impl A for i32 {
805 fn cmp(&self, b: &i32) -> Ordering {
806 if self > b {
807 Ordering::Less
808 } else if self < b {
809 Ordering::Greater
810 } else {
811 Ordering::Equal
812 }
813 }
814}
815
816#[derive(Educe)]
817#[educe(PartialEq(bound), Eq(bound), PartialOrd(bound), Ord(bound = "T: std::cmp::Ord, K: std::cmp::Ord + A"))]
818enum Enum<T, K> {
819 V1,
820 V2 {
821 #[educe(Ord(trait = "A"))]
822 f1: K,
823 },
824 V3(
825 T
826 ),
827}
828```
829
830#### Ranking
831
832Each 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`.
833
834```rust
835#[macro_use] extern crate educe;
836
837#[derive(Educe)]
838#[educe(PartialEq, Eq, PartialOrd, Ord)]
839struct Struct {
840 #[educe(Ord(rank = 1))]
841 f1: u8,
842 #[educe(Ord(rank = 0))]
843 f2: u8,
844}
845```
846
847Each 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.
848
849```rust
850#[macro_use] extern crate educe;
851
852#[derive(Educe)]
853#[educe(PartialEq, Eq, PartialOrd, Ord)]
854enum Enum {
855 #[educe(Ord(rank = 2))]
856 Two,
857 #[educe(Ord(rank = 1))]
858 One,
859}
860```
861
862## Hash
863
864Use `#[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.
865
866#### Basic Usage
867
868```rust
869#[macro_use] extern crate educe;
870
871#[derive(Educe)]
872#[educe(Hash)]
873struct Struct {
874 f1: u8
875}
876
877#[derive(Educe)]
878#[educe(Hash)]
879enum Enum {
880 V1,
881 V2 {
882 f1: u8,
883 },
884 V3(u8),
885}
886```
887
888#### Ignore Fields
889
890The `ignore` attribute can ignore specific fields.
891
892```rust
893#[macro_use] extern crate educe;
894
895#[derive(Educe)]
896#[educe(Hash)]
897struct Struct {
898 #[educe(Hash(ignore))]
899 f1: u8
900}
901
902#[derive(Educe)]
903#[educe(Hash)]
904enum Enum {
905 V1,
906 V2 {
907 #[educe(Hash(ignore))]
908 f1: u8,
909 },
910 V3(
911 #[educe(Hash(ignore))]
912 u8
913 ),
914}
915```
916
917#### Use Another Method or Trait to Do Hashing
918
919The `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.
920
921```rust
922#[macro_use] extern crate educe;
923
924use std::hash::{Hash, Hasher};
925
926fn hash<H: Hasher>(_s: &u8, state: &mut H) {
927 Hash::hash(&100, state)
928}
929
930trait A {
931 fn hash<H: Hasher>(&self, state: &mut H) {
932 Hash::hash(&100, state)
933 }
934}
935
936impl A for i32 {};
937impl A for u64 {};
938
939#[derive(Educe)]
940#[educe(Hash)]
941enum Enum<T: A> {
942 V1,
943 V2 {
944 #[educe(Hash(method = "hash"))]
945 f1: u8,
946 },
947 V3(
948 #[educe(Hash(trait = "A"))]
949 T
950 ),
951}
952```
953
954#### Generic Parameters Bound to the `Hash` Trait or Others
955
956The `#[educe(Hash(bound))]` attribute can be used to add the `Hash` trait bound to all generaic parameters for the `Hash` implementation.
957
958```rust
959#[macro_use] extern crate educe;
960
961#[derive(Educe)]
962#[educe(Hash(bound))]
963enum Enum<T, K> {
964 V1,
965 V2 {
966 f1: K,
967 },
968 V3(
969 T
970 ),
971}
972```
973
974Or you can set the where predicates by yourself.
975
976```rust
977#[macro_use] extern crate educe;
978
979use std::hash::{Hash, Hasher};
980
981fn hash<H: Hasher>(_s: &u8, state: &mut H) {
982 Hash::hash(&100, state)
983}
984
985trait A {
986 fn hash<H: Hasher>(&self, state: &mut H) {
987 Hash::hash(&100, state)
988 }
989}
990
991impl A for i32 {};
992impl A for u64 {};
993
994#[derive(Educe)]
995#[educe(Hash(bound = "T: std::hash::Hash, K: A"))]
996enum Enum<T, K> {
997 V1,
998 V2 {
999 #[educe(Hash(trait = "A"))]
1000 f1: K,
1001 },
1002 V3(
1003 T
1004 ),
1005}
1006```
1007
1008## Default
1009
1010Use `#[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.
1011
1012#### Basic Usage
1013
1014For 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.
1015
1016```rust
1017#[macro_use] extern crate educe;
1018
1019#[derive(Educe)]
1020#[educe(Default)]
1021struct Struct {
1022 f1: u8
1023}
1024
1025#[derive(Educe)]
1026#[educe(Default)]
1027enum Enum {
1028 V1,
1029 #[educe(Default)]
1030 V2 {
1031 f1: u8,
1032 },
1033 V3(u8),
1034}
1035
1036#[derive(Educe)]
1037#[educe(Default)]
1038union Union {
1039 f1: u8,
1040 #[educe(Default)]
1041 f2: f64,
1042}
1043```
1044
1045#### The Default Value for the Whole Type
1046
1047The `#[educe(Default(expression = "expression"))]` attribute can be used to set the default value for your type by an expression.
1048
1049```rust
1050#[macro_use] extern crate educe;
1051
1052#[derive(Educe)]
1053#[educe(Default(expression = "Struct { f1: 1 }"))]
1054struct Struct {
1055 f1: u8
1056}
1057
1058#[derive(Educe)]
1059#[educe(Default(expression = "Enum::Struct { f1: 1 }"))]
1060enum Enum {
1061 Unit,
1062 Struct {
1063 f1: u8
1064 },
1065 Tuple(u8),
1066}
1067
1068#[derive(Educe)]
1069#[educe(Default(expression = "Union { f1: 1 }"))]
1070union Union {
1071 f1: u8,
1072 f2: f64,
1073}
1074```
1075
1076#### The Default Values for Specific Fields
1077
1078The `#[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.
1079
1080```rust
1081#[macro_use] extern crate educe;
1082
1083#[derive(Educe)]
1084#[educe(Default)]
1085struct Struct {
1086 #[educe(Default = 1)]
1087 f1: u8,
1088 #[educe(Default = 11111111111111111111111111111)]
1089 f2: i128,
1090 #[educe(Default = 1.1)]
1091 f3: f64,
1092 #[educe(Default = true)]
1093 f4: bool,
1094 #[educe(Default = "Hi")]
1095 f5: &'static str,
1096 #[educe(Default = "Hello")]
1097 f6: String,
1098 #[educe(Default = 'M')]
1099 f7: char,
1100}
1101
1102#[derive(Educe)]
1103#[educe(Default)]
1104enum Enum {
1105 Unit,
1106 #[educe(Default)]
1107 Tuple(
1108 #[educe(Default(expression = "0 + 1"))]
1109 u8,
1110 #[educe(Default(expression = "-11111111111111111111111111111 * -1"))]
1111 i128,
1112 #[educe(Default(expression = "1.0 + 0.1"))]
1113 f64,
1114 #[educe(Default(expression = "!false"))]
1115 bool,
1116 #[educe(Default(expression = "\"Hi\""))]
1117 &'static str,
1118 #[educe(Default(expression = "String::from(\"Hello\")"))]
1119 String,
1120 #[educe(Default(expression = "'M'"))]
1121 char,
1122 ),
1123}
1124
1125#[derive(Educe)]
1126#[educe(Default)]
1127union Union {
1128 f1: u8,
1129 f2: i128,
1130 f3: f64,
1131 f4: bool,
1132 #[educe(Default = "Hi")]
1133 f5: &'static str,
1134 f6: char,
1135}
1136```
1137
1138#### Generic Parameters Bound to the `Default` Trait or Others
1139
1140The `#[educe(Default(bound))]` attribute can be used to add the `Default` trait bound to all generaic parameters for the `Default` implementation.
1141
1142```rust
1143#[macro_use] extern crate educe;
1144
1145#[derive(Educe)]
1146#[educe(Default(bound))]
1147enum Enum<T> {
1148 Unit,
1149 #[educe(Default)]
1150 Struct {
1151 f1: T
1152 },
1153 Tuple(T),
1154}
1155```
1156
1157Or you can set the where predicates by yourself.
1158
1159```rust
1160#[macro_use] extern crate educe;
1161
1162#[derive(Educe)]
1163#[educe(Default(bound = "T: std::default::Default"))]
1164enum Enum<T> {
1165 Unit,
1166 #[educe(Default)]
1167 Struct {
1168 f1: T
1169 },
1170 Tuple(T),
1171}
1172```
1173
1174#### The `new` Associated Function
1175
1176With 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.
1177
1178```rust
1179#[macro_use] extern crate educe;
1180
1181#[derive(Educe)]
1182#[educe(Default(new))]
1183struct Struct {
1184 f1: u8
1185}
1186```
1187
1188## Clone
1189
1190Use `#[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.
1191
1192#### Basic Usage
1193
1194```rust
1195#[macro_use] extern crate educe;
1196
1197#[derive(Educe)]
1198#[educe(Clone)]
1199struct Struct {
1200 f1: u8
1201}
1202
1203#[derive(Educe)]
1204#[educe(Clone)]
1205enum Enum {
1206 V1,
1207 V2 {
1208 f1: u8,
1209 },
1210 V3(u8),
1211}
1212```
1213
1214#### Use Another Method or Trait to Do Cloning
1215
1216The `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.
1217
1218```rust
1219#[macro_use] extern crate educe;
1220
1221fn clone(v: &u8) -> u8 {
1222 v + 100
1223}
1224
1225trait A {
1226 fn clone(&self) -> Self;
1227}
1228
1229impl A for i32 {
1230 fn clone(&self) -> i32 {
1231 self + 100
1232 }
1233}
1234
1235impl A for u64 {
1236 fn clone(&self) -> u64 {
1237 self + 100
1238 }
1239}
1240
1241#[derive(Educe)]
1242#[educe(Clone)]
1243enum Enum<T: A> {
1244 V1,
1245 V2 {
1246 #[educe(Clone(method = "clone"))]
1247 f1: u8,
1248 },
1249 V3(
1250 #[educe(Clone(trait = "A"))]
1251 T
1252 ),
1253}
1254```
1255
1256#### Generic Parameters Bound to the `Clone` Trait or Others
1257
1258The `#[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 generaic parameters for the `Clone` implementation.
1259
1260```rust
1261#[macro_use] extern crate educe;
1262
1263#[derive(Educe)]
1264#[educe(Clone(bound))]
1265enum Enum<T, K> {
1266 V1,
1267 V2 {
1268 f1: K,
1269 },
1270 V3(
1271 T
1272 ),
1273}
1274```
1275
1276Or you can set the where predicates by yourself.
1277
1278```rust
1279#[macro_use] extern crate educe;
1280
1281fn clone(v: &u8) -> u8 {
1282 v + 100
1283}
1284
1285trait A {
1286 fn clone(&self) -> Self;
1287}
1288
1289impl A for i32 {
1290 fn clone(&self) -> i32 {
1291 self + 100
1292 }
1293}
1294
1295impl A for u64 {
1296 fn clone(&self) -> u64 {
1297 self + 100
1298 }
1299}
1300
1301#[derive(Educe)]
1302#[educe(Clone(bound = "T: std::clone::Clone, K: A"))]
1303enum Enum<T, K> {
1304 V1,
1305 V2 {
1306 #[educe(Clone(trait = "A"))]
1307 f1: K,
1308 },
1309 V3(
1310 T
1311 ),
1312}
1313```
1314
1315#### Union
1316
1317The `#[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.
1318
1319```rust
1320#[macro_use] extern crate educe;
1321
1322#[derive(Educe)]
1323#[educe(Copy, Clone)]
1324union Union {
1325 f1: u8,
1326}
1327```
1328
1329## Copy
1330
1331Use `#[derive(Educe)]` and `#[educe(Copy)]` to implement the `Copy` trait for a struct, an enum, or a union.
1332
1333#### Basic Usage
1334
1335```rust
1336#[macro_use] extern crate educe;
1337
1338#[derive(Educe)]
1339#[educe(Copy, Clone)]
1340struct Struct {
1341 f1: u8
1342}
1343
1344#[derive(Educe)]
1345#[educe(Copy, Clone)]
1346enum Enum {
1347 V1,
1348 V2 {
1349 f1: u8,
1350 },
1351 V3(u8),
1352}
1353```
1354
1355#### Generic Parameters Bound to the `Copy` Trait or Others
1356
1357The `#[educe(Copy(bound))]` attribute can be used to add the `Copy` trait bound to all generaic parameters for the `Copy` implementation.
1358
1359```rust
1360#[macro_use] extern crate educe;
1361
1362#[derive(Educe)]
1363#[educe(Copy(bound), Clone(bound))]
1364enum Enum<T, K> {
1365 V1,
1366 V2 {
1367 f1: K,
1368 },
1369 V3(
1370 T
1371 ),
1372}
1373```
1374
1375Or you can set the where predicates by yourself.
1376
1377```rust
1378#[macro_use] extern crate educe;
1379
1380fn clone(v: &u8) -> u8 {
1381 v + 100
1382}
1383
1384trait A {
1385 fn clone(&self) -> Self;
1386}
1387
1388impl A for i32 {
1389 fn clone(&self) -> i32 {
1390 self + 100
1391 }
1392}
1393
1394impl A for u64 {
1395 fn clone(&self) -> u64 {
1396 self + 100
1397 }
1398}
1399
1400#[derive(Educe)]
1401#[educe(Copy(bound = "T: Copy, K: A + Copy"), Clone(bound = "T: Copy, K: A + Copy"))]
1402enum Enum<T, K> {
1403 V1,
1404 V2 {
1405 #[educe(Clone(trait = "A"))]
1406 f1: K,
1407 },
1408 V3(
1409 T
1410 ),
1411}
1412```
1413
1414#### Copy and Clone
1415
1416If 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.
1417
1418## Deref
1419
1420Use `#[derive(Educe)]` and `#[educe(Deref)]` to implement the `Deref` trait for a struct or an enum.
1421
1422#### Basic Usage
1423
1424You need to assign a field as a default inmutable dereferencing field unless the number of fields is exactly one.
1425
1426```rust
1427#[macro_use] extern crate educe;
1428
1429#[derive(Educe)]
1430#[educe(Deref)]
1431struct Struct {
1432 f1: u8,
1433 #[educe(Deref)]
1434 f2: u8,
1435}
1436
1437#[derive(Educe)]
1438#[educe(Deref)]
1439enum Enum {
1440 Struct {
1441 f1: u8
1442 },
1443 Struct2 {
1444 f1: u8,
1445 #[educe(Deref)]
1446 f2: u8,
1447 },
1448 Tuple(u8),
1449 Tuple2(
1450 u8,
1451 #[educe(Deref)]
1452 u8
1453 ),
1454}
1455```
1456
1457## DerefMut
1458
1459Use `#[derive(Educe)]` and `#[educe(DerefMut)]` to implement the `DerefMut` trait for a struct or an enum.
1460
1461#### Basic Usage
1462
1463You need to assign a field as a default mutable dereferencing field unless the number of fields is exactly one.
1464
1465```rust
1466#[macro_use] extern crate educe;
1467
1468#[derive(Educe)]
1469#[educe(Deref, DerefMut)]
1470struct Struct {
1471 f1: u8,
1472 #[educe(Deref, DerefMut)]
1473 f2: u8,
1474}
1475
1476#[derive(Educe)]
1477#[educe(Deref, DerefMut)]
1478enum Enum {
1479 Struct {
1480 f1: u8
1481 },
1482 Struct2 {
1483 f1: u8,
1484 #[educe(Deref, DerefMut)]
1485 f2: u8,
1486 },
1487 Tuple(u8),
1488 Tuple2(
1489 #[educe(DerefMut)]
1490 u8,
1491 #[educe(Deref)]
1492 u8
1493 ),
1494}
1495```
1496
1497The mutable dereferencing fields don't need to be the same as the inmutable dereferencing fields. But their type must be the same.
1498
1499## TODO
1500
1501There is a lot of work to be done. Unimplemented traits are listed below:
1502
15031. `From`
15041. `Into`
15051. `FromStr`
15061. `TryFrom`
15071. `TryInto`
1508
1509*/
1510
1511#![recursion_limit = "128"]
1512
1513#[macro_use]
1514extern crate enum_ordinalize;
1515
1516mod panic;
1517mod support_traits;
1518mod trait_handlers;
1519
1520use std::collections::BTreeMap;
1521
1522use proc_macro2::TokenStream;
1523use quote::ToTokens;
1524use support_traits::Trait;
1525use syn::{DeriveInput, Meta, NestedMeta};
1526use trait_handlers::TraitHandler;
1527
1528fn derive_input_handler(ast: DeriveInput) -> TokenStream {
1529 let mut tokens = TokenStream::new();
1530 let mut trait_meta_map: BTreeMap<Trait, Meta> = BTreeMap::new();
1531
1532 for attr in ast.attrs.iter() {
1533 if attr.path.is_ident("educe") {
1534 let attr_meta = attr.parse_meta().unwrap();
1535
1536 match attr_meta {
1537 Meta::List(list) => {
1538 for p in list.nested {
1539 match p {
1540 NestedMeta::Meta(meta) => {
1541 let meta_name = meta.path().into_token_stream().to_string();
1542
1543 let t = Trait::from_str(meta_name);
1544
1545 if trait_meta_map.contains_key(&t) {
1546 panic::reuse_a_trait(t);
1547 }
1548
1549 trait_meta_map.insert(t, meta);
1550 },
1551 NestedMeta::Lit(_) => {
1552 panic::educe_format_incorrect();
1553 },
1554 }
1555 }
1556 },
1557 _ => {
1558 panic::educe_format_incorrect();
1559 },
1560 }
1561 }
1562 }
1563
1564 let traits: Vec<Trait> = trait_meta_map.keys().copied().collect();
1565
1566 #[cfg(feature = "Debug")]
1567 {
1568 if let Some(meta) = trait_meta_map.get(&Trait::Debug) {
1569 trait_handlers::debug::DebugHandler::trait_meta_handler(
1570 &ast,
1571 &mut tokens,
1572 &traits,
1573 meta,
1574 );
1575 }
1576 }
1577
1578 #[cfg(feature = "PartialEq")]
1579 {
1580 if let Some(meta) = trait_meta_map.get(&Trait::PartialEq) {
1581 trait_handlers::partial_eq::PartialEqHandler::trait_meta_handler(
1582 &ast,
1583 &mut tokens,
1584 &traits,
1585 meta,
1586 );
1587 }
1588 }
1589
1590 #[cfg(feature = "Eq")]
1591 {
1592 if let Some(meta) = trait_meta_map.get(&Trait::Eq) {
1593 trait_handlers::eq::EqHandler::trait_meta_handler(&ast, &mut tokens, &traits, meta);
1594 }
1595 }
1596
1597 #[cfg(feature = "PartialOrd")]
1598 {
1599 if let Some(meta) = trait_meta_map.get(&Trait::PartialOrd) {
1600 trait_handlers::partial_ord::PartialOrdHandler::trait_meta_handler(
1601 &ast,
1602 &mut tokens,
1603 &traits,
1604 meta,
1605 );
1606 }
1607 }
1608
1609 #[cfg(feature = "Ord")]
1610 {
1611 if let Some(meta) = trait_meta_map.get(&Trait::Ord) {
1612 trait_handlers::ord::OrdHandler::trait_meta_handler(&ast, &mut tokens, &traits, meta);
1613 }
1614 }
1615
1616 #[cfg(feature = "Hash")]
1617 {
1618 if let Some(meta) = trait_meta_map.get(&Trait::Hash) {
1619 trait_handlers::hash::HashHandler::trait_meta_handler(&ast, &mut tokens, &traits, meta);
1620 }
1621 }
1622
1623 #[cfg(feature = "Default")]
1624 {
1625 if let Some(meta) = trait_meta_map.get(&Trait::Default) {
1626 trait_handlers::default::DefaultHandler::trait_meta_handler(
1627 &ast,
1628 &mut tokens,
1629 &traits,
1630 meta,
1631 );
1632 }
1633 }
1634
1635 #[cfg(feature = "Clone")]
1636 {
1637 if let Some(meta) = trait_meta_map.get(&Trait::Clone) {
1638 trait_handlers::clone::CloneHandler::trait_meta_handler(
1639 &ast,
1640 &mut tokens,
1641 &traits,
1642 meta,
1643 );
1644 }
1645 }
1646
1647 #[cfg(feature = "Copy")]
1648 {
1649 if let Some(meta) = trait_meta_map.get(&Trait::Copy) {
1650 trait_handlers::copy::CopyHandler::trait_meta_handler(&ast, &mut tokens, &traits, meta);
1651 }
1652 }
1653
1654 #[cfg(feature = "Deref")]
1655 {
1656 if let Some(meta) = trait_meta_map.get(&Trait::Deref) {
1657 trait_handlers::deref::DerefHandler::trait_meta_handler(
1658 &ast,
1659 &mut tokens,
1660 &traits,
1661 meta,
1662 );
1663 }
1664 }
1665
1666 #[cfg(feature = "DerefMut")]
1667 {
1668 if let Some(meta) = trait_meta_map.get(&Trait::DerefMut) {
1669 trait_handlers::deref_mut::DerefMutHandler::trait_meta_handler(
1670 &ast,
1671 &mut tokens,
1672 &traits,
1673 meta,
1674 );
1675 }
1676 }
1677
1678 if tokens.is_empty() {
1679 panic::derive_attribute_not_set_up_yet("Educe");
1680 }
1681
1682 tokens
1683}
1684
1685#[proc_macro_derive(Educe, attributes(educe))]
1686pub fn educe_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1687 derive_input_handler(syn::parse(input).unwrap()).into()
1688}