1
1
use std:: ops:: Deref ;
2
2
3
3
use askama:: Template ;
4
+ use proc_macro2:: Span ;
4
5
use quote:: ToTokens ;
5
6
use syn:: spanned:: Spanned ;
6
7
@@ -65,11 +66,7 @@ impl TestTemplate {
65
66
ffi_items : & FfiItems ,
66
67
generator : & TestGenerator ,
67
68
) -> Result < Self , TranslationError > {
68
- let helper = TranslateHelper {
69
- ffi_items,
70
- generator,
71
- translator : Translator :: new ( ) ,
72
- } ;
69
+ let helper = TranslateHelper :: new ( ffi_items, generator) ;
73
70
74
71
let mut template = Self :: default ( ) ;
75
72
template. populate_const_and_cstr_tests ( & helper) ?;
@@ -87,7 +84,7 @@ impl TestTemplate {
87
84
& mut self ,
88
85
helper : & TranslateHelper ,
89
86
) -> Result < ( ) , TranslationError > {
90
- for constant in helper. ffi_items . constants ( ) {
87
+ for constant in helper. filtered_ffi_items . constants ( ) {
91
88
if let syn:: Type :: Ptr ( ptr) = & constant. ty
92
89
&& let syn:: Type :: Path ( path) = & * ptr. elem
93
90
&& path. path . segments . last ( ) . unwrap ( ) . ident == "c_char"
@@ -125,7 +122,7 @@ impl TestTemplate {
125
122
& mut self ,
126
123
helper : & TranslateHelper ,
127
124
) -> Result < ( ) , TranslationError > {
128
- for alias in helper. ffi_items . aliases ( ) {
125
+ for alias in helper. filtered_ffi_items . aliases ( ) {
129
126
let item = TestSizeAlign {
130
127
test_name : size_align_test_ident ( alias. ident ( ) ) ,
131
128
id : alias. ident ( ) . into ( ) ,
@@ -135,7 +132,7 @@ impl TestTemplate {
135
132
self . size_align_tests . push ( item. clone ( ) ) ;
136
133
self . test_idents . push ( item. test_name ) ;
137
134
}
138
- for struct_ in helper. ffi_items . structs ( ) {
135
+ for struct_ in helper. filtered_ffi_items . structs ( ) {
139
136
let item = TestSizeAlign {
140
137
test_name : size_align_test_ident ( struct_. ident ( ) ) ,
141
138
id : struct_. ident ( ) . into ( ) ,
@@ -145,7 +142,7 @@ impl TestTemplate {
145
142
self . size_align_tests . push ( item. clone ( ) ) ;
146
143
self . test_idents . push ( item. test_name ) ;
147
144
}
148
- for union_ in helper. ffi_items . unions ( ) {
145
+ for union_ in helper. filtered_ffi_items . unions ( ) {
149
146
let item = TestSizeAlign {
150
147
test_name : size_align_test_ident ( union_. ident ( ) ) ,
151
148
id : union_. ident ( ) . into ( ) ,
@@ -166,7 +163,7 @@ impl TestTemplate {
166
163
& mut self ,
167
164
helper : & TranslateHelper ,
168
165
) -> Result < ( ) , TranslationError > {
169
- for alias in helper. ffi_items . aliases ( ) {
166
+ for alias in helper. filtered_ffi_items . aliases ( ) {
170
167
let should_skip_signededness_test = helper
171
168
. generator
172
169
. skip_signededness
@@ -200,7 +197,7 @@ impl TestTemplate {
200
197
let should_skip = |map_input| helper. generator . skips . iter ( ) . any ( |f| f ( & map_input) ) ;
201
198
202
199
let struct_fields = helper
203
- . ffi_items
200
+ . filtered_ffi_items
204
201
. structs ( )
205
202
. iter ( )
206
203
. flat_map ( |struct_| struct_. fields . iter ( ) . map ( move |field| ( struct_, field) ) )
@@ -216,7 +213,7 @@ impl TestTemplate {
216
213
)
217
214
} ) ;
218
215
let union_fields = helper
219
- . ffi_items
216
+ . filtered_ffi_items
220
217
. unions ( )
221
218
. iter ( )
222
219
. flat_map ( |union_| union_. fields . iter ( ) . map ( move |field| ( union_, field) ) )
@@ -254,15 +251,15 @@ impl TestTemplate {
254
251
& mut self ,
255
252
helper : & TranslateHelper ,
256
253
) -> Result < ( ) , TranslationError > {
257
- for alias in helper. ffi_items . aliases ( ) {
254
+ for alias in helper. filtered_ffi_items . aliases ( ) {
258
255
let c_ty = helper. c_type ( alias) ?;
259
256
self . add_roundtrip_test ( helper, alias. ident ( ) , & [ ] , & c_ty, true ) ;
260
257
}
261
- for struct_ in helper. ffi_items . structs ( ) {
258
+ for struct_ in helper. filtered_ffi_items . structs ( ) {
262
259
let c_ty = helper. c_type ( struct_) ?;
263
260
self . add_roundtrip_test ( helper, struct_. ident ( ) , & struct_. fields , & c_ty, false ) ;
264
261
}
265
- for union_ in helper. ffi_items . unions ( ) {
262
+ for union_ in helper. filtered_ffi_items . unions ( ) {
266
263
let c_ty = helper. c_type ( union_) ?;
267
264
self . add_roundtrip_test ( helper, union_. ident ( ) , & union_. fields , & c_ty, false ) ;
268
265
}
@@ -306,14 +303,14 @@ impl TestTemplate {
306
303
let should_skip = |map_input| helper. generator . skips . iter ( ) . any ( |f| f ( & map_input) ) ;
307
304
308
305
let struct_fields = helper
309
- . ffi_items
306
+ . filtered_ffi_items
310
307
. structs ( )
311
308
. iter ( )
312
309
. flat_map ( |s| s. fields . iter ( ) . map ( move |f| ( s, f) ) )
313
310
. filter ( |( s, f) | {
314
- !should_skip ( MapInput :: StructField ( s, f) )
315
- && ! should_skip ( MapInput :: StructFieldType ( s, f) )
316
- && f. public
311
+ !( should_skip ( MapInput :: StructField ( s, f) )
312
+ || should_skip ( MapInput :: StructFieldType ( s, f) )
313
+ || ! f. public )
317
314
} )
318
315
. map ( |( s, f) | {
319
316
(
@@ -335,14 +332,14 @@ impl TestTemplate {
335
332
)
336
333
} ) ;
337
334
let union_fields = helper
338
- . ffi_items
335
+ . filtered_ffi_items
339
336
. unions ( )
340
337
. iter ( )
341
338
. flat_map ( |u| u. fields . iter ( ) . map ( move |f| ( u, f) ) )
342
339
. filter ( |( u, f) | {
343
- !should_skip ( MapInput :: UnionField ( u, f) )
344
- && ! should_skip ( MapInput :: UnionFieldType ( u, f) )
345
- && f. public
340
+ !( should_skip ( MapInput :: UnionField ( u, f) )
341
+ || should_skip ( MapInput :: UnionFieldType ( u, f) )
342
+ || ! f. public )
346
343
} )
347
344
. map ( |( u, f) | {
348
345
(
@@ -483,20 +480,61 @@ fn roundtrip_test_ident(ident: &str) -> BoxStr {
483
480
484
481
/// Wrap methods that depend on both ffi items and the generator.
485
482
pub ( crate ) struct TranslateHelper < ' a > {
483
+ filtered_ffi_items : FfiItems ,
486
484
ffi_items : & ' a FfiItems ,
487
485
generator : & ' a TestGenerator ,
488
486
translator : Translator ,
489
487
}
490
488
491
489
impl < ' a > TranslateHelper < ' a > {
492
490
/// Create a new translation helper.
493
- #[ cfg_attr( not( test) , expect( unused) ) ]
494
491
pub ( crate ) fn new ( ffi_items : & ' a FfiItems , generator : & ' a TestGenerator ) -> Self {
495
- Self {
492
+ let filtered_ffi_items = ffi_items. clone ( ) ;
493
+ let mut helper = Self {
494
+ filtered_ffi_items,
496
495
ffi_items,
497
496
generator,
498
497
translator : Translator :: new ( ) ,
498
+ } ;
499
+ helper. filter_ffi_items ( ) ;
500
+
501
+ helper
502
+ }
503
+
504
+ /// Skips entire items such as structs, constants, and aliases from being tested.
505
+ ///
506
+ /// Does not skip specific tests or specific fields. If `skip_private` is true,
507
+ /// it will skip tests for all private items.
508
+ fn filter_ffi_items ( & mut self ) {
509
+ let verbose = self . generator . verbose_skip ;
510
+
511
+ macro_rules! filter {
512
+ ( $field: ident, $variant: ident, $label: literal) => { {
513
+ let skipped: Vec <_> = self
514
+ . filtered_ffi_items
515
+ . $field
516
+ . extract_if( .., |item| {
517
+ self . generator
518
+ . skips
519
+ . iter( )
520
+ . any( |f| f( & MapInput :: $variant( item) ) )
521
+ || ( self . generator. skip_private && !item. public)
522
+ } )
523
+ . collect( ) ;
524
+ if verbose {
525
+ skipped
526
+ . iter( )
527
+ . for_each( |item| eprintln!( "Skipping {} \" {}\" " , $label, item. ident( ) ) ) ;
528
+ }
529
+ } } ;
499
530
}
531
+
532
+ filter ! ( aliases, Alias , "alias" ) ;
533
+ filter ! ( constants, Const , "const" ) ;
534
+ filter ! ( structs, Struct , "struct" ) ;
535
+ filter ! ( unions, Union , "union" ) ;
536
+ filter ! ( foreign_functions, Fn , "fn" ) ;
537
+ filter ! ( foreign_statics, Static , "static" ) ;
500
538
}
501
539
502
540
/// Returns the equivalent C/Cpp identifier of the Rust item.
@@ -517,7 +555,14 @@ impl<'a> TranslateHelper<'a> {
517
555
// inside of `Fn` when parsed.
518
556
MapInput :: Fn ( _) => unimplemented ! ( ) ,
519
557
// For structs/unions/aliases, their type is the same as their identifier.
520
- MapInput :: Alias ( a) => ( a. ident ( ) , a. ident ( ) . to_string ( ) ) ,
558
+ // FIXME(ctest): For some specific primitives such as c_uint, they don't exist on the
559
+ // C side and have to be manually translated. If they are removed to use `std::ffi`,
560
+ // then this becomes unneeded (although it won't break).
561
+ MapInput :: Alias ( a) => (
562
+ a. ident ( ) ,
563
+ self . translator
564
+ . translate_primitive_type ( & syn:: Ident :: new ( a. ident ( ) , Span :: call_site ( ) ) ) ,
565
+ ) ,
521
566
MapInput :: Struct ( s) => ( s. ident ( ) , s. ident ( ) . to_string ( ) ) ,
522
567
MapInput :: Union ( u) => ( u. ident ( ) , u. ident ( ) . to_string ( ) ) ,
523
568
@@ -528,7 +573,7 @@ impl<'a> TranslateHelper<'a> {
528
573
MapInput :: Type ( _) => panic ! ( "MapInput::Type is not allowed!" ) ,
529
574
} ;
530
575
531
- let item = if self . ffi_items . contains_struct ( ident ) {
576
+ let item = if self . ffi_items . contains_struct ( & ty ) {
532
577
MapInput :: StructType ( & ty)
533
578
} else if self . ffi_items . contains_union ( ident) {
534
579
MapInput :: UnionType ( & ty)
@@ -546,21 +591,30 @@ impl<'a> TranslateHelper<'a> {
546
591
fn basic_c_type ( & self , ty : & syn:: Type ) -> Result < String , TranslationError > {
547
592
let type_name = match ty {
548
593
syn:: Type :: Path ( p) => p. path . segments . last ( ) . unwrap ( ) . ident . to_string ( ) ,
549
- syn:: Type :: Ptr ( p) => self . basic_c_type ( & p. elem ) ?,
550
- syn:: Type :: Reference ( r) => self . basic_c_type ( & r. elem ) ?,
594
+ // Using recursion here causes breakage.
595
+ // FIXME(ctest): Might be possible to extract this part into a function.
596
+ syn:: Type :: Ptr ( p) => match p. elem . deref ( ) {
597
+ syn:: Type :: Path ( p) => p. path . segments . last ( ) . unwrap ( ) . ident . to_string ( ) ,
598
+ _ => p. to_token_stream ( ) . to_string ( ) ,
599
+ } ,
600
+ syn:: Type :: Reference ( r) => match r. elem . deref ( ) {
601
+ syn:: Type :: Path ( p) => p. path . segments . last ( ) . unwrap ( ) . ident . to_string ( ) ,
602
+ _ => r. to_token_stream ( ) . to_string ( ) ,
603
+ } ,
551
604
_ => ty. to_token_stream ( ) . to_string ( ) ,
552
605
} ;
553
606
554
607
let unmapped_c_type = self . translator . translate_type ( ty) ?;
555
608
let item = if self . ffi_items . contains_struct ( & type_name) {
556
- MapInput :: StructType ( & unmapped_c_type )
609
+ MapInput :: StructType ( & type_name )
557
610
} else if self . ffi_items . contains_union ( & type_name) {
558
- MapInput :: UnionType ( & unmapped_c_type )
611
+ MapInput :: UnionType ( & type_name )
559
612
} else {
560
- MapInput :: Type ( & unmapped_c_type )
613
+ MapInput :: Type ( & type_name )
561
614
} ;
562
615
563
- Ok ( self . generator . rty_to_cty ( item) )
616
+ let mapped_type = self . generator . rty_to_cty ( item. clone ( ) ) ;
617
+ Ok ( unmapped_c_type. replace ( & type_name, & mapped_type) )
564
618
}
565
619
566
620
/// Partially translate a Rust bare function type into its equivalent C type.
0 commit comments