@@ -13,8 +13,7 @@ use crate::{
13
13
expand,
14
14
ffi_items:: FfiItems ,
15
15
template:: { CTestTemplate , RustTestTemplate } ,
16
- Const , Field , Language , MapInput , Parameter , Result , Static , Struct , TyKind , Type ,
17
- VolatileItemKind ,
16
+ Const , Field , MapInput , Parameter , Result , Static , Struct , Type , VolatileItemKind ,
18
17
} ;
19
18
20
19
/// A function that takes a mappable input and returns its mapping as Some, otherwise
@@ -35,14 +34,12 @@ pub struct TestGenerator {
35
34
pub ( crate ) target : Option < String > ,
36
35
pub ( crate ) includes : Vec < PathBuf > ,
37
36
out_dir : Option < PathBuf > ,
38
- /// The language chosen for testing bindings.
39
- pub language : Language ,
40
37
flags : Vec < String > ,
41
38
defines : Vec < ( String , Option < String > ) > ,
42
39
mapped_names : Vec < MappedName > ,
43
40
skips : Vec < Skip > ,
44
41
verbose_skip : bool ,
45
- volatile_item : Option < VolatileItem > ,
42
+ volatile_items : Vec < VolatileItem > ,
46
43
array_arg : Option < ArrayArg > ,
47
44
}
48
45
@@ -156,37 +153,116 @@ impl TestGenerator {
156
153
self
157
154
}
158
155
159
- /// Is volatile?
156
+ /// Is field volatile?
160
157
///
161
- /// The closure given takes a `VolatileKind` denoting a particular item that
162
- /// could be volatile, and returns whether this is the case. This is used to
163
- /// make sure that the generated test code also has the volatile keyword.
158
+ /// This is used to make sure that the generated test code also has the volatile keyword.
164
159
///
165
160
/// # Examples
166
161
///
167
162
/// ```no_run
168
163
/// use ctest_next::{TestGenerator, VolatileItemKind};
169
164
///
170
165
/// let mut cfg = TestGenerator::new();
171
- /// cfg.volatile_item(|item| {
172
- /// match item {
173
- /// VolatileItemKind::StructField(s, f)
174
- /// if s.ident() == "foo_struct" && f.ident() == "foo_field"
175
- /// => true,
176
- /// _ => false,
177
- /// }});
166
+ /// cfg.volatile_field(|s, f| {
167
+ /// s.ident() == "foo_t" && f.ident() == "inner_t"
168
+ /// });
169
+ /// ```
170
+ pub fn volatile_field ( & mut self , f : impl Fn ( Struct , Field ) -> bool + ' static ) -> & mut Self {
171
+ self . volatile_items . push ( Box :: new ( move |item| {
172
+ if let VolatileItemKind :: StructField ( s, f_) = item {
173
+ f ( s, f_)
174
+ } else {
175
+ false
176
+ }
177
+ } ) ) ;
178
+ self
179
+ }
180
+
181
+ /// Is static variable volatile?
182
+ ///
183
+ /// This is used to make sure that the generated test code also has the volatile keyword.
184
+ ///
185
+ /// # Examples
186
+ ///
187
+ /// ```no_run
188
+ /// use ctest_next::{TestGenerator, VolatileItemKind};
189
+ ///
190
+ /// let mut cfg = TestGenerator::new();
191
+ /// cfg.volatile_static(|s| {
192
+ /// s.ident() == "foo_t"
193
+ /// });
194
+ /// ```
195
+ pub fn volatile_static ( & mut self , f : impl Fn ( Static ) -> bool + ' static ) -> & mut Self {
196
+ self . volatile_items . push ( Box :: new ( move |item| {
197
+ if let VolatileItemKind :: Static ( s) = item {
198
+ f ( s)
199
+ } else {
200
+ false
201
+ }
202
+ } ) ) ;
203
+ self
204
+ }
205
+
206
+ /// Is function argument volatile?
207
+ ///
208
+ /// This is used to make sure that the generated test code also has the volatile keyword.
209
+ ///
210
+ /// # Examples
211
+ ///
212
+ /// ```no_run
213
+ /// use ctest_next::{TestGenerator, VolatileItemKind};
214
+ ///
215
+ /// let mut cfg = TestGenerator::new();
216
+ /// cfg.volatile_fn_arg(|f, _p| {
217
+ /// f.ident() == "size_of_T"
218
+ /// });
178
219
/// ```
179
- pub fn volatile_item ( & mut self , f : impl Fn ( VolatileItemKind ) -> bool + ' static ) -> & mut Self {
180
- self . volatile_item = Some ( Box :: new ( f) ) ;
220
+ pub fn volatile_fn_arg (
221
+ & mut self ,
222
+ f : impl Fn ( crate :: Fn , Box < Parameter > ) -> bool + ' static ,
223
+ ) -> & mut Self {
224
+ self . volatile_items . push ( Box :: new ( move |item| {
225
+ if let VolatileItemKind :: FnArgument ( func, param) = item {
226
+ f ( func, param)
227
+ } else {
228
+ false
229
+ }
230
+ } ) ) ;
231
+ self
232
+ }
233
+
234
+ /// Is function return type volatile?
235
+ ///
236
+ /// This is used to make sure that the generated test code also has the volatile keyword.
237
+ ///
238
+ /// # Examples
239
+ ///
240
+ /// ```no_run
241
+ /// use ctest_next::{TestGenerator, VolatileItemKind};
242
+ ///
243
+ /// let mut cfg = TestGenerator::new();
244
+ /// cfg.volatile_fn_return_type(|f| {
245
+ /// f.ident() == "size_of_T"
246
+ /// });
247
+ /// ```
248
+ pub fn volatile_fn_return_type (
249
+ & mut self ,
250
+ f : impl Fn ( crate :: Fn ) -> bool + ' static ,
251
+ ) -> & mut Self {
252
+ self . volatile_items . push ( Box :: new ( move |item| {
253
+ if let VolatileItemKind :: FnReturnType ( func) = item {
254
+ f ( func)
255
+ } else {
256
+ false
257
+ }
258
+ } ) ) ;
181
259
self
182
260
}
183
261
184
262
/// Is argument of function an array?
185
263
///
186
- /// The closure denotes whether particular argument of a function is an array.
187
- /// This is used to figure out which pointer argument is actually an array. For
188
- /// example, `uint8_t*` could be a pointer to an integer or pointer to the start
189
- /// of an array.
264
+ /// This closure should return true if a pointer argument to a function should be generated
265
+ /// with `T foo[]` syntax rather than `T *foo`.
190
266
///
191
267
/// # Examples
192
268
///
@@ -343,27 +419,6 @@ impl TestGenerator {
343
419
self
344
420
}
345
421
346
- /// Sets the programming language.
347
- ///
348
- /// This is used to generate C++ versions of the test that can be compiled
349
- /// and ran in the same way as C.
350
- ///
351
- /// # Examples
352
- ///
353
- /// ```no_run
354
- /// use std::env;
355
- /// use std::path::PathBuf;
356
- ///
357
- /// use ctest_next::{TestGenerator, Language};
358
- ///
359
- /// let mut cfg = TestGenerator::new();
360
- /// cfg.language(Language::CXX);
361
- /// ```
362
- pub fn language ( & mut self , language : Language ) -> & mut Self {
363
- self . language = language;
364
- self
365
- }
366
-
367
422
/// Add a flag to the C compiler invocation.
368
423
///
369
424
/// # Examples
@@ -466,24 +521,63 @@ impl TestGenerator {
466
521
/// # Examples
467
522
///
468
523
/// ```no_run
469
- /// use ctest_next::{ TestGenerator, TyKind} ;
524
+ /// use ctest_next::TestGenerator;
470
525
///
471
526
/// let mut cfg = TestGenerator::new();
472
- /// cfg.rename_type(|ty, kind| {
473
- /// if kind == TyKind::Struct {
474
- /// Some(format!("{}_t", ty))
475
- /// } else {
476
- /// None
477
- /// }
527
+ /// cfg.rename_type(|ty| {
528
+ /// Some(format!("{}_t", ty))
478
529
/// });
479
530
/// ```
480
- pub fn rename_type (
481
- & mut self ,
482
- f : impl Fn ( & str , TyKind ) -> Option < String > + ' static ,
483
- ) -> & mut Self {
531
+ pub fn rename_type ( & mut self , f : impl Fn ( & str ) -> Option < String > + ' static ) -> & mut Self {
532
+ self . mapped_names . push ( Box :: new ( move |item| {
533
+ if let MapInput :: Type ( ty) = item {
534
+ f ( ty)
535
+ } else {
536
+ None
537
+ }
538
+ } ) ) ;
539
+ self
540
+ }
541
+
542
+ /// Configures how a Rust struct type is translated to a C struct type.
543
+ ///
544
+ /// # Examples
545
+ ///
546
+ /// ```no_run
547
+ /// use ctest_next::TestGenerator;
548
+ ///
549
+ /// let mut cfg = TestGenerator::new();
550
+ /// cfg.rename_struct_ty(|ty| {
551
+ /// (ty == "timeval").then(|| format!("{ty}_t"))
552
+ /// });
553
+ /// ```
554
+ pub fn rename_struct_ty ( & mut self , f : impl Fn ( & str ) -> Option < String > + ' static ) -> & mut Self {
484
555
self . mapped_names . push ( Box :: new ( move |item| {
485
- if let MapInput :: Type ( ty, kind) = item {
486
- f ( ty, * kind)
556
+ if let MapInput :: StructType ( ty) = item {
557
+ f ( ty)
558
+ } else {
559
+ None
560
+ }
561
+ } ) ) ;
562
+ self
563
+ }
564
+
565
+ /// Configures how a Rust union type is translated to a C union type.
566
+ ///
567
+ /// # Examples
568
+ ///
569
+ /// ```no_run
570
+ /// use ctest_next::TestGenerator;
571
+ ///
572
+ /// let mut cfg = TestGenerator::new();
573
+ /// cfg.rename_struct_ty(|ty| {
574
+ /// (ty == "T1Union").then(|| format!("__{ty}"))
575
+ /// });
576
+ /// ```
577
+ pub fn rename_union_ty ( & mut self , f : impl Fn ( & str ) -> Option < String > + ' static ) -> & mut Self {
578
+ self . mapped_names . push ( Box :: new ( move |item| {
579
+ if let MapInput :: UnionType ( ty) = item {
580
+ f ( ty)
487
581
} else {
488
582
None
489
583
}
@@ -531,18 +625,13 @@ impl TestGenerator {
531
625
. map_err ( GenerationError :: OsError ) ?;
532
626
533
627
// Generate the C/Cxx side of the tests.
534
- let c_output_path = output_file_path. with_extension ( self . language . extension ( ) ) ;
628
+ let c_output_path = output_file_path. with_extension ( "c" ) ;
535
629
File :: create ( & c_output_path)
536
630
. map_err ( GenerationError :: OsError ) ?
537
631
. write_all (
538
632
CTestTemplate :: new ( & ffi_items, self )
539
633
. render ( )
540
- . map_err ( |e| {
541
- GenerationError :: TemplateRender (
542
- self . language . display_name ( ) . to_string ( ) ,
543
- e. to_string ( ) ,
544
- )
545
- } ) ?
634
+ . map_err ( |e| GenerationError :: TemplateRender ( "C" . to_string ( ) , e. to_string ( ) ) ) ?
546
635
. as_bytes ( ) ,
547
636
)
548
637
. map_err ( GenerationError :: OsError ) ?;
@@ -557,11 +646,12 @@ impl TestGenerator {
557
646
558
647
macro_rules! filter {
559
648
( $field: ident, $variant: ident, $label: literal) => { {
560
- let ( retained , skipped) : ( Vec <_>, Vec <_> ) = ffi_items
649
+ let skipped: Vec <_> = ffi_items
561
650
. $field
562
- . drain( ..)
563
- . partition( |item| !self . skips. iter( ) . any( |f| f( & MapInput :: $variant( item) ) ) ) ;
564
- ffi_items. $field = retained;
651
+ . extract_if( .., |item| {
652
+ self . skips. iter( ) . any( |f| f( & MapInput :: $variant( item) ) )
653
+ } )
654
+ . collect( ) ;
565
655
if verbose {
566
656
skipped
567
657
. iter( )
@@ -590,9 +680,9 @@ impl TestGenerator {
590
680
MapInput :: Struct ( s) => s. ident ( ) . to_string ( ) ,
591
681
MapInput :: Alias ( t) => t. ident ( ) . to_string ( ) ,
592
682
MapInput :: Field ( _, f) => f. ident ( ) . to_string ( ) ,
593
- MapInput :: Type ( ty, TyKind :: Struct ) => format ! ( "struct {ty}" ) ,
594
- MapInput :: Type ( ty, TyKind :: Union ) => format ! ( "union {ty}" ) ,
595
- MapInput :: Type ( ty, TyKind :: Other ) => ty. to_string ( ) ,
683
+ MapInput :: StructType ( ty) => format ! ( "struct {ty}" ) ,
684
+ MapInput :: UnionType ( ty) => format ! ( "union {ty}" ) ,
685
+ MapInput :: Type ( ty) => ty. to_string ( ) ,
596
686
} )
597
687
}
598
688
}
0 commit comments