@@ -35,6 +35,16 @@ fn get_type_name(ty: &syn::Type) -> String {
35
35
}
36
36
}
37
37
38
+ fn variant_opcode_value ( v : & syn:: Variant ) -> u8 {
39
+ for attr in v. attrs . iter ( ) {
40
+ if attr. path ( ) . is_ident ( "opcode" ) {
41
+ return attr. parse_args :: < syn:: LitInt > ( ) . unwrap ( ) . base10_parse ( ) . unwrap ( ) ;
42
+ }
43
+ }
44
+
45
+ 0
46
+ }
47
+
38
48
fn impl_opcode_struct ( ast : & ItemEnum ) -> TokenStream {
39
49
let field_names: Vec < _ > = ast. variants . iter ( ) . map ( |x| & x. ident ) . collect ( ) ;
40
50
let field_values = ast. variants . iter ( ) . map ( |x| {
@@ -87,13 +97,94 @@ fn impl_opcode_struct(ast: &ItemEnum) -> TokenStream {
87
97
| ( ( * r2 as u16 ) & 0xf ) << 12
88
98
} ,
89
99
90
- [ "Register" , "u8" ] => quote ! {
91
- // reg as u16 | 8 BIT INT
92
- // req as u16 | (((*reg as u8) >> 4) | (*amount))
93
- // Self::#name(reg, amount) => OpCode::#name as u16 | ((((*reg as u8) >> 4) | (amount)) as u16 >> 8)
94
- Self :: #name( reg, amount) => ( ( ( ( * reg as u8 ) << 4 | amount) as u16 ) << 8 ) | ( OpCode :: #name as u16 )
95
- // ((*reg as u8) & 0xf) << 8
96
- // | ((*amount as u8) & 0xf) << 8
100
+ _ => panic ! ( "Invalid types {types:?}" ) ,
101
+ }
102
+ } else {
103
+ panic ! ( "Unknown fields type for ident {name}" ) ;
104
+ }
105
+ } )
106
+ . collect ( ) ;
107
+
108
+ let field_u16_decodings: Vec < _ > = ast
109
+ . variants
110
+ . iter ( )
111
+ . map ( |x| {
112
+ let value = variant_opcode_value ( x) ;
113
+ let name = & x. ident ;
114
+
115
+ if let syn:: Fields :: Unit = & x. fields {
116
+ return quote ! {
117
+ #value => Ok ( Self :: #name)
118
+ } ;
119
+ }
120
+
121
+ if let syn:: Fields :: Unnamed ( fields) = & x. fields {
122
+ let types: Vec < _ > = fields
123
+ . unnamed
124
+ . iter ( )
125
+ . map ( |f| get_type_name ( & f. ty ) )
126
+ . collect ( ) ;
127
+
128
+ let types: Vec < & str > = types. iter ( ) . map ( AsRef :: as_ref) . collect ( ) ;
129
+
130
+ match types[ ..] {
131
+ [ "u8" ] => quote ! {
132
+ #value => Ok ( Self :: #name( ( ( ins & 0xff00 ) >> 8 ) as u8 ) )
133
+ } ,
134
+
135
+ [ "Register" ] => quote ! {
136
+ #value => Ok ( Self :: #name( Register :: from( ( ( ins & 0xf00 ) >> 8 ) as u8 ) ) )
137
+ } ,
138
+
139
+ [ "Register" , "Register" ] => quote ! {
140
+ #value => {
141
+ let r1 = Register :: from( ( ( ins & 0xf00 ) >> 8 ) as u8 ) ;
142
+ let r2 = Register :: from( ( ( ins & 0xf000 ) >> 12 ) as u8 ) ;
143
+
144
+ Ok ( Self :: #name( r1, r2) )
145
+ }
146
+ } ,
147
+
148
+ _ => panic ! ( "Invalid types {types:?}" ) ,
149
+ }
150
+ } else {
151
+ panic ! ( "Unknown fields type for ident {name}" ) ;
152
+ }
153
+ } )
154
+ . collect ( ) ;
155
+
156
+ let field_to_string: Vec < _ > = ast
157
+ . variants
158
+ . iter ( )
159
+ . map ( |x| {
160
+ let name = & x. ident ;
161
+
162
+ if let syn:: Fields :: Unit = & x. fields {
163
+ return quote ! {
164
+ Self :: #name => write!( f, stringify!( #name) )
165
+ } ;
166
+ }
167
+
168
+ if let syn:: Fields :: Unnamed ( fields) = & x. fields {
169
+ let types: Vec < _ > = fields
170
+ . unnamed
171
+ . iter ( )
172
+ . map ( |f| get_type_name ( & f. ty ) )
173
+ . collect ( ) ;
174
+
175
+ let types: Vec < & str > = types. iter ( ) . map ( AsRef :: as_ref) . collect ( ) ;
176
+
177
+ match types[ ..] {
178
+ [ "u8" ] => quote ! {
179
+ Self :: #name( byte) => write!( f, "{} {}" , stringify!( #name) , byte)
180
+ } ,
181
+
182
+ [ "Register" ] => quote ! {
183
+ Self :: #name( r) => write!( f, "{} {}" , stringify!( #name) , r)
184
+ } ,
185
+
186
+ [ "Register" , "Register" ] => quote ! {
187
+ Self :: #name( r1, r2) => write!( f, "{} {} {}" , stringify!( #name) , r1, r2)
97
188
} ,
98
189
99
190
_ => panic ! ( "Invalid types {types:?}" ) ,
@@ -131,12 +222,32 @@ fn impl_opcode_struct(ast: &ItemEnum) -> TokenStream {
131
222
fn try_from( value: u8 ) -> Result <Self , Self :: Error > {
132
223
match value {
133
224
#( x if x == Self :: #field_names as u8 => Ok ( Self :: #field_names) , ) *
134
- // x if x == Self::AddReg as u8 => Ok(Self::AddReg),
135
225
_ => Err ( format!( "Unknown opcode 0x{value:X}" ) ) ,
136
226
}
137
227
}
138
228
}
139
229
230
+ impl TryFrom <u16 > for Instruction {
231
+ type Error = String ;
232
+
233
+ fn try_from( ins: u16 ) -> Result <Self , Self :: Error > {
234
+ let op = ( ins & 0xff ) as u8 ;
235
+
236
+ match op {
237
+ #( #field_u16_decodings, ) *
238
+ _ => panic!( "Invalid types" ) ,
239
+ }
240
+ }
241
+ }
242
+
243
+ impl std:: fmt:: Display for Instruction {
244
+ fn fmt( & self , f: & mut std:: fmt:: Formatter <' _>) -> std:: fmt:: Result {
245
+ match self {
246
+ #( #field_to_string, ) *
247
+ }
248
+ }
249
+ }
250
+
140
251
impl Instruction {
141
252
pub fn encode_u16( & self ) -> u16 {
142
253
match self {
@@ -176,3 +287,34 @@ pub fn derive_from_u8(input: proc_macro::TokenStream) -> proc_macro::TokenStream
176
287
177
288
proc_macro:: TokenStream :: from ( expanded)
178
289
}
290
+
291
+ /// Automatically implements the from display trait
292
+ /// for ease of use
293
+ #[ proc_macro_derive( Display ) ]
294
+ pub fn derive_display ( input : proc_macro:: TokenStream ) -> proc_macro:: TokenStream {
295
+ let input = parse_macro_input ! ( input as DeriveInput ) ;
296
+ let name = input. ident ;
297
+
298
+ let variants = if let syn:: Data :: Enum ( data) = input. data {
299
+ data. variants
300
+ } else {
301
+ panic ! ( "Display can only be derived for enums" ) ;
302
+ } ;
303
+
304
+ let variant_names: Vec < _ > = variants. iter ( ) . map ( |v| & v. ident ) . collect ( ) ;
305
+
306
+ let expanded = quote ! {
307
+ impl std:: fmt:: Display for #name {
308
+ fn fmt( & self , f: & mut std:: fmt:: Formatter <' _>) -> std:: fmt:: Result {
309
+ let string = match self {
310
+ #( Self :: #variant_names => stringify!( #variant_names) , ) *
311
+ _ => panic!( "Invalid value" ) ,
312
+ } ;
313
+
314
+ write!( f, "{string}" )
315
+ }
316
+ }
317
+ } ;
318
+
319
+ proc_macro:: TokenStream :: from ( expanded)
320
+ }
0 commit comments