@@ -110,9 +110,15 @@ struct MetaProperty {
110
110
alias : Option < syn:: Ident > ,
111
111
}
112
112
113
+ #[ derive( Clone ) ]
114
+ struct MetaEnum {
115
+ name : syn:: Ident ,
116
+ variants : Vec < syn:: Ident > ,
117
+ }
118
+
113
119
#[ derive( Default ) ]
114
120
struct MetaObject {
115
- int_data : Vec < u32 > ,
121
+ int_data : Vec < proc_macro2 :: TokenStream > ,
116
122
string_data : Vec < String > ,
117
123
}
118
124
impl MetaObject {
@@ -144,58 +150,75 @@ impl MetaObject {
144
150
result
145
151
}
146
152
153
+ fn push_int ( & mut self , i : u32 ) {
154
+ self . int_data . push ( quote ! ( #i) ) ;
155
+ }
156
+
157
+ fn extend_from_int_slice ( & mut self , slice : & [ u32 ] ) {
158
+ for i in slice {
159
+ self . int_data . push ( quote ! ( #i) ) ;
160
+ }
161
+ }
162
+
147
163
fn compute_int_data (
148
164
& mut self ,
149
165
class_name : String ,
150
166
properties : & [ MetaProperty ] ,
151
167
methods : & [ MetaMethod ] ,
168
+ enums : & [ MetaEnum ] ,
152
169
signal_count : usize ,
153
170
) {
154
- let has_notify = properties. iter ( ) . any ( |p| p. notify_signal . is_some ( ) ) ;
155
-
171
+ let has_notify = properties. iter ( ) . any ( |p| p. notify_signal . is_some ( ) ) ;
156
172
self . add_string ( class_name) ;
157
173
self . add_string ( "" . to_owned ( ) ) ;
158
174
159
175
let mut offset = 14 ;
160
176
let property_offset = offset + methods. len ( ) as u32 * 5 ;
161
- //...
177
+ let enum_offset = property_offset + properties . len ( ) as u32 * ( if has_notify { 4 } else { 3 } ) ;
162
178
163
- self . int_data . extend_from_slice ( & [
164
- 7 , // revision
179
+ self . extend_from_int_slice ( & [
180
+ 8 , // revision
165
181
0 , // classname
166
182
0 ,
167
183
0 , // class info count and offset
168
184
methods. len ( ) as u32 ,
169
- offset, // method count and offset
185
+ if methods . len ( ) == 0 { 0 } else { offset } , // method count and offset
170
186
properties. len ( ) as u32 ,
171
- property_offset, // properties count and offset
172
- 0 ,
173
- 0 , // enum count and offset
187
+ if properties . len ( ) == 0 { 0 } else { property_offset } , // properties count and offset
188
+ enums . len ( ) as u32 ,
189
+ if enums . len ( ) == 0 { 0 } else { enum_offset } , // enum count and offset
174
190
0 ,
175
191
0 , // constructor count and offset
176
192
0x4 , // flags (PropertyAccessInStaticMetaCall)
177
193
signal_count as u32 , // signalCount
178
194
] ) ;
179
195
180
- offset = property_offset + properties . len ( ) as u32 * ( if has_notify { 4 } else { 3 } ) ;
196
+ offset = enum_offset + enums . len ( ) as u32 * 5 ;
181
197
182
198
for m in methods {
183
199
let n = self . add_string ( m. name . to_string ( ) ) ;
184
- self . int_data
185
- . extend_from_slice ( & [ n, m. args . len ( ) as u32 , offset, 1 , m. flags ] ) ;
200
+ self . extend_from_int_slice ( & [ n, m. args . len ( ) as u32 , offset, 1 , m. flags ] ) ;
186
201
offset += 1 + 2 * m. args . len ( ) as u32 ;
187
202
}
188
203
189
204
for p in properties {
190
205
let n = self . add_string ( p. alias . as_ref ( ) . unwrap_or ( & p. name ) . to_string ( ) ) ;
191
206
let type_id = self . add_type ( p. typ . clone ( ) ) ;
192
- self . int_data . extend_from_slice ( & [ n, type_id, p. flags ] ) ;
207
+ self . extend_from_int_slice ( & [ n, type_id, p. flags ] ) ;
193
208
}
209
+
210
+ for e in enums {
211
+ let n = self . add_string ( e. name . to_string ( ) ) ;
212
+ // name, alias, flag, count, data offset
213
+ self . extend_from_int_slice ( & [ n, n, 0x2 , e. variants . len ( ) as u32 , offset] ) ;
214
+ offset += 2 * e. variants . len ( ) as u32 ;
215
+ }
216
+
194
217
if has_notify {
195
218
for p in properties {
196
219
match p. notify_signal {
197
- None => self . int_data . push ( 0 as u32 ) ,
198
- Some ( ref signal) => self . int_data . push (
220
+ None => self . push_int ( 0 as u32 ) ,
221
+ Some ( ref signal) => self . push_int (
199
222
methods
200
223
. iter ( )
201
224
. position ( |x| x. name == * signal && ( x. flags & 0x4 ) != 0 )
@@ -208,16 +231,26 @@ impl MetaObject {
208
231
for m in methods {
209
232
// return type
210
233
let ret_type = self . add_type ( m. ret_type . clone ( ) ) ;
211
- self . int_data . push ( ret_type) ;
234
+ self . push_int ( ret_type) ;
212
235
// types
213
236
for a in m. args . iter ( ) {
214
237
let ty = self . add_type ( a. typ . clone ( ) ) ;
215
- self . int_data . push ( ty) ;
238
+ self . push_int ( ty) ;
216
239
}
217
240
// names
218
241
for a in m. args . iter ( ) {
219
242
let n = self . add_string ( a. name . clone ( ) . into_token_stream ( ) . to_string ( ) ) ;
220
- self . int_data . push ( n) ;
243
+ self . push_int ( n) ;
244
+ }
245
+ }
246
+
247
+ for e in enums {
248
+ for v in & e. variants {
249
+ let n = self . add_string ( v. to_string ( ) ) ;
250
+ // name, value
251
+ self . push_int ( n) ;
252
+ let e_name = & e. name ;
253
+ self . int_data . push ( quote ! { #e_name:: #v as u32 } ) ;
221
254
}
222
255
}
223
256
}
@@ -487,7 +520,7 @@ pub fn generate(input: TokenStream, is_qobject: bool) -> TokenStream {
487
520
let methods = methods2;
488
521
489
522
let mut mo: MetaObject = Default :: default ( ) ;
490
- mo. compute_int_data ( name. to_string ( ) , & properties, & methods, signals. len ( ) ) ;
523
+ mo. compute_int_data ( name. to_string ( ) , & properties, & methods, & [ ] , signals. len ( ) ) ;
491
524
492
525
let str_data32 = mo. build_string_data ( 32 ) ;
493
526
let str_data64 = mo. build_string_data ( 64 ) ;
@@ -710,7 +743,7 @@ pub fn generate(input: TokenStream, is_qobject: bool) -> TokenStream {
710
743
superdata: #base_meta_object,
711
744
string_data: STRING_DATA . as_ptr( ) ,
712
745
data: INT_DATA . as_ptr( ) ,
713
- static_metacall: static_metacall,
746
+ static_metacall: Some ( static_metacall) ,
714
747
r: :: std:: ptr:: null( ) ,
715
748
e: :: std:: ptr:: null( ) ,
716
749
} ; } ;
@@ -739,7 +772,7 @@ pub fn generate(input: TokenStream, is_qobject: bool) -> TokenStream {
739
772
superdata: #base_meta_object,
740
773
string_data: STRING_DATA . as_ptr( ) ,
741
774
data: INT_DATA . as_ptr( ) ,
742
- static_metacall: static_metacall #turbo_generics,
775
+ static_metacall: Some ( static_metacall #turbo_generics) ,
743
776
r: :: std:: ptr:: null( ) ,
744
777
e: :: std:: ptr:: null( ) ,
745
778
} ) ) ;
@@ -885,3 +918,95 @@ pub fn generate(input: TokenStream, is_qobject: bool) -> TokenStream {
885
918
}
886
919
body. into ( )
887
920
}
921
+
922
+ fn is_valid_repr_attribute ( attribute : & syn:: Attribute ) -> bool {
923
+ match attribute. parse_meta ( ) {
924
+ Ok ( syn:: Meta :: List ( list) ) => {
925
+ if list. ident . to_string ( ) == "repr" && list. nested . len ( ) == 1 {
926
+ match & list. nested [ 0 ] {
927
+ syn:: NestedMeta :: Meta ( syn:: Meta :: Word ( word) ) => {
928
+ let acceptables = vec ! [ "u8" , "u16" , "u32" , "i8" , "i16" , "i32" ] ;
929
+ let word = word. to_string ( ) ;
930
+ acceptables. iter ( ) . any ( |x| * x == word. to_string ( ) )
931
+ }
932
+ _ => false ,
933
+ }
934
+ } else {
935
+ false
936
+ }
937
+ }
938
+ _ => false
939
+ }
940
+ }
941
+
942
+ pub fn generate_enum ( input : TokenStream ) -> TokenStream {
943
+ let ast = parse_macro_input ! ( input as syn:: DeriveInput ) ;
944
+
945
+ let name = & ast. ident ;
946
+
947
+ let mut is_repr_explicit = false ;
948
+ for attr in & ast. attrs {
949
+ is_repr_explicit |= is_valid_repr_attribute ( attr) ;
950
+ }
951
+ if !is_repr_explicit {
952
+ panic ! ( "#[derive(QEnum)] only support enum with explicit #[repr(*)], possible integer type are u8, u16, u32, i8, i16, i32." )
953
+ }
954
+
955
+ let crate_ = super :: get_crate ( & ast) ;
956
+ let mut meta_enum = MetaEnum {
957
+ name : name. clone ( ) ,
958
+ variants : Vec :: new ( )
959
+ } ;
960
+
961
+ if let syn:: Data :: Enum ( ref data) = ast. data {
962
+ for variant in data. variants . iter ( ) {
963
+ match & variant. fields {
964
+ syn:: Fields :: Unit => { }
965
+ // TODO report error with span
966
+ _ => panic ! ( "#[derive(QEnum)] only support field-less enum" )
967
+ }
968
+
969
+ let var_name = & variant. ident ;
970
+ meta_enum. variants . push ( var_name. clone ( ) ) ;
971
+ }
972
+ } else {
973
+ panic ! ( "#[derive(QEnum)] is only defined for enums, not for structs!" ) ;
974
+ }
975
+
976
+ let enums = vec ! [ meta_enum] ;
977
+ let mut mo: MetaObject = Default :: default ( ) ;
978
+ mo. compute_int_data ( name. to_string ( ) , & [ ] , & [ ] , & enums, 0 ) ;
979
+ let str_data32 = mo. build_string_data ( 32 ) ;
980
+ let str_data64 = mo. build_string_data ( 64 ) ;
981
+ let int_data = mo. int_data ;
982
+
983
+ let mo = if ast. generics . params . is_empty ( ) {
984
+ quote ! {
985
+ qmetaobject_lazy_static! { static ref MO : #crate_:: QMetaObject = #crate_:: QMetaObject {
986
+ superdata: :: std:: ptr:: null( ) ,
987
+ string_data: STRING_DATA . as_ptr( ) ,
988
+ data: INT_DATA . as_ptr( ) ,
989
+ static_metacall: None ,
990
+ r: :: std:: ptr:: null( ) ,
991
+ e: :: std:: ptr:: null( ) ,
992
+ } ; } ;
993
+ return & * MO ;
994
+ }
995
+ } else {
996
+ panic ! ( "#[derive(QEnum)] is only defined for C enums, doesn't support generics" ) ;
997
+ } ;
998
+
999
+ let body = quote ! {
1000
+ impl #crate_:: QEnum for #name {
1001
+ fn static_meta_object( ) ->* const #crate_:: QMetaObject {
1002
+ #[ cfg( target_pointer_width = "64" ) ]
1003
+ static STRING_DATA : & ' static [ u8 ] = & [ #( #str_data64) , * ] ;
1004
+ #[ cfg( target_pointer_width = "32" ) ]
1005
+ static STRING_DATA : & ' static [ u8 ] = & [ #( #str_data32) , * ] ;
1006
+ static INT_DATA : & ' static [ u32 ] = & [ #( #int_data) , * ] ;
1007
+ #mo
1008
+ }
1009
+ }
1010
+ } ;
1011
+ body. into ( )
1012
+ }
0 commit comments