@@ -4,11 +4,56 @@ use quote::quote;
4
4
use syn:: spanned:: Spanned ;
5
5
use syn:: {
6
6
parenthesized, parse_macro_input, token, Attribute , Data , DeriveInput , Field , Fields ,
7
- FieldsNamed , Ident , LitInt , Path , Variant ,
7
+ FieldsNamed , Ident , LitInt , Path , Type , Variant ,
8
8
} ;
9
9
10
10
type Result < T > = std:: result:: Result < T , Diagnostic > ;
11
11
12
+ struct AbstractField {
13
+ ty : Type ,
14
+ ident : Ident ,
15
+ named : bool ,
16
+ pointer : bool ,
17
+ }
18
+
19
+ impl AbstractField {
20
+ fn from_field ( field : Field ) -> Result < Self > {
21
+ let Some ( ident) = field. ident else {
22
+ return Err ( field. span ( ) . error ( "field must be named" ) ) ;
23
+ } ;
24
+ let named = field. attrs . iter ( ) . any ( |attr| attr. path ( ) . is_ident ( "named" ) ) ;
25
+ let ( ty, pointer) = match field. ty {
26
+ Type :: Ptr ( ty) => ( * ty. elem , true ) ,
27
+ _ => ( field. ty , false ) ,
28
+ } ;
29
+ Ok ( Self {
30
+ ty,
31
+ ident,
32
+ named,
33
+ pointer,
34
+ } )
35
+ }
36
+
37
+ fn resolved_ty ( & self ) -> TokenStream {
38
+ let ty = & self . ty ;
39
+ let mut resolved = quote ! { <#ty as :: binaryninja:: types:: AbstractType >:: resolve_type( ) } ;
40
+ if self . named {
41
+ resolved = quote ! {
42
+ :: binaryninja:: types:: Type :: named_type_from_type(
43
+ stringify!( #ty) ,
44
+ & #resolved
45
+ )
46
+ } ;
47
+ }
48
+ if self . pointer {
49
+ resolved = quote ! {
50
+ :: binaryninja:: types:: Type :: pointer_of_width( & #resolved, 8 , false , false , None )
51
+ }
52
+ }
53
+ resolved
54
+ }
55
+ }
56
+
12
57
struct Repr {
13
58
c : bool ,
14
59
packed : Option < usize > ,
@@ -109,28 +154,12 @@ fn impl_abstract_type(ast: DeriveInput) -> Result<TokenStream> {
109
154
}
110
155
}
111
156
112
- fn field_resolved_type ( field : & Field ) -> TokenStream {
113
- let ty = & field. ty ;
114
- let resolved_ty = quote ! { <#ty as :: binaryninja:: types:: AbstractType >:: resolve_type( ) } ;
115
- if field. attrs . iter ( ) . any ( |attr| attr. path ( ) . is_ident ( "named" ) ) {
116
- quote ! {
117
- :: binaryninja:: types:: Type :: named_type_from_type(
118
- stringify!( #ty) ,
119
- & #resolved_ty
120
- )
121
- }
122
- } else {
123
- resolved_ty
124
- }
125
- }
126
-
127
- fn field_arguments ( name : & Ident , fields : FieldsNamed ) -> Vec < TokenStream > {
157
+ fn field_arguments ( name : & Ident , fields : & [ AbstractField ] ) -> Vec < TokenStream > {
128
158
fields
129
- . named
130
159
. iter ( )
131
160
. map ( |field| {
132
- let ident = field. ident . as_ref ( ) . unwrap ( ) ;
133
- let resolved_ty = field_resolved_type ( field) ;
161
+ let ident = & field. ident ;
162
+ let resolved_ty = field. resolved_ty ( ) ;
134
163
quote ! {
135
164
& #resolved_ty,
136
165
stringify!( #ident) ,
@@ -148,7 +177,12 @@ fn impl_abstract_struct_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Re
148
177
return Err ( name. span ( ) . error ( "struct must be `repr(C)`" ) ) ;
149
178
}
150
179
151
- let args = field_arguments ( & name, fields) ;
180
+ let fields = fields
181
+ . named
182
+ . into_iter ( )
183
+ . map ( AbstractField :: from_field)
184
+ . collect :: < Result < Vec < _ > > > ( ) ?;
185
+ let args = field_arguments ( & name, & fields) ;
152
186
let packed = repr. packed . is_some ( ) ;
153
187
let alignment = repr. align . map ( |align| quote ! { . set_alignment( #align) } ) ;
154
188
Ok ( quote ! {
@@ -172,7 +206,12 @@ fn impl_abstract_union_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Res
172
206
return Err ( name. span ( ) . error ( "union must be `repr(C)`" ) ) ;
173
207
}
174
208
175
- let args = field_arguments ( & name, fields) ;
209
+ let fields = fields
210
+ . named
211
+ . into_iter ( )
212
+ . map ( AbstractField :: from_field)
213
+ . collect :: < Result < Vec < _ > > > ( ) ?;
214
+ let args = field_arguments ( & name, & fields) ;
176
215
let packed = repr. packed . is_some ( ) ;
177
216
let alignment = repr. align . map ( |align| quote ! { . set_alignment( #align) } ) ;
178
217
Ok ( quote ! {
0 commit comments