File tree 6 files changed +108
-0
lines changed
6 files changed +108
-0
lines changed Original file line number Diff line number Diff line change
1
+ /target
2
+ /Cargo.lock
Original file line number Diff line number Diff line change
1
+ [package ]
2
+ name = " tagname"
3
+ version = " 0.1.0"
4
+ edition = " 2021"
5
+
6
+ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
+ [dependencies ]
8
+ tagname_derive = { path = " tagname_derive" }
9
+
10
+ [workspace ]
11
+ members = [" tagname_derive" ]
Original file line number Diff line number Diff line change
1
+ pub use tagname_derive:: Variant ;
2
+
3
+ pub trait Variant {
4
+ fn tag_name ( & self ) -> & ' static str ;
5
+ }
Original file line number Diff line number Diff line change
1
+ [package ]
2
+ name = " tagname_derive"
3
+ version = " 0.1.0"
4
+ edition = " 2021"
5
+
6
+ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
+
8
+ [lib ]
9
+ proc-macro = true
10
+
11
+ [dependencies ]
12
+ syn = " 1.0"
13
+ quote = " 1.0"
14
+ proc-macro2 = " 1.0.47"
15
+
Original file line number Diff line number Diff line change
1
+ use proc_macro:: TokenStream ;
2
+ use quote:: quote;
3
+ use syn:: { Ident , Variant } ;
4
+
5
+ #[ proc_macro_derive( Variant ) ]
6
+ pub fn variant_derive ( input : TokenStream ) -> TokenStream {
7
+ let ast = syn:: parse ( input) . unwrap ( ) ;
8
+
9
+ // Build the trait implementation
10
+ impl_variant_derive_macro ( ast)
11
+ }
12
+
13
+ fn impl_variant_derive_macro ( ast : syn:: DeriveInput ) -> TokenStream {
14
+ let name = & ast. ident ;
15
+ let variants: Vec < Variant > = match ast. data {
16
+ syn:: Data :: Enum ( enum_data) => enum_data
17
+ . variants
18
+ . into_pairs ( )
19
+ . into_iter ( )
20
+ . map ( |pair| pair. into_value ( ) )
21
+ . collect ( ) ,
22
+ _ => panic ! ( "cannot derive Variant for non-enum types" ) ,
23
+ } ;
24
+
25
+ let variants_with_fields = variants. iter ( ) . cloned ( ) . filter ( |v| !v. fields . is_empty ( ) ) ;
26
+ let variants_without_fields = variants. iter ( ) . cloned ( ) . filter ( |v| v. fields . is_empty ( ) ) ;
27
+ let with_field_tags: Vec < Ident > = variants_with_fields. into_iter ( ) . map ( |v| v. ident ) . collect ( ) ;
28
+ let no_field_tags: Vec < Ident > = variants_without_fields
29
+ . into_iter ( )
30
+ . map ( |v| v. ident )
31
+ . collect ( ) ;
32
+
33
+ let gen = quote ! {
34
+ impl Variant for #name {
35
+ fn tag_name( & self ) -> & ' static str {
36
+ match self {
37
+ #(
38
+ #name:: #with_field_tags( _) => stringify!( #with_field_tags)
39
+ ) , * ,
40
+ #(
41
+ #name:: #no_field_tags => stringify!( #no_field_tags)
42
+ ) , *
43
+ }
44
+ }
45
+ }
46
+ } ;
47
+ gen. into ( )
48
+ }
49
+
50
+ #[ cfg( test) ]
51
+ mod tests {
52
+ #[ test]
53
+ fn it_works ( ) {
54
+ let result = 2 + 2 ;
55
+ assert_eq ! ( result, 4 ) ;
56
+ }
57
+ }
Original file line number Diff line number Diff line change
1
+ use tagname:: Variant ;
2
+
3
+ #[ derive( Variant ) ]
4
+ enum MyVariant {
5
+ Yes ,
6
+ No ,
7
+ Maybe ( usize ) ,
8
+ }
9
+
10
+ #[ test]
11
+ fn return_correct_tag_names ( ) {
12
+ let v1 = MyVariant :: Yes ;
13
+ let v2 = MyVariant :: No ;
14
+ let v3 = MyVariant :: Maybe ( 1 ) ;
15
+ assert_eq ! ( v1. tag_name( ) , "Yes" ) ;
16
+ assert_eq ! ( v2. tag_name( ) , "No" ) ;
17
+ assert_eq ! ( v3. tag_name( ) , "Maybe" ) ;
18
+ }
You can’t perform that action at this time.
0 commit comments