1
1
extern crate proc_macro;
2
2
3
- use proc_macro2:: Span ;
4
3
use quote:: { quote, ToTokens } ;
5
4
use syn:: {
6
5
braced,
@@ -10,17 +9,20 @@ use syn::{
10
9
parse_quote,
11
10
parse_quote_spanned,
12
11
spanned:: Spanned ,
13
- visit_mut :: VisitMut ,
12
+ Attribute ,
14
13
Block ,
15
14
Error ,
16
15
Expr ,
16
+ GenericArgument ,
17
17
Generics ,
18
18
Ident ,
19
19
ImplItemFn ,
20
20
Lifetime ,
21
21
Lit ,
22
22
Meta ,
23
+ Path ,
23
24
PathArguments ,
25
+ PathSegment ,
24
26
Token ,
25
27
Type ,
26
28
} ;
@@ -55,23 +57,10 @@ pub fn action_impl(
55
57
}
56
58
57
59
let sync_run = if let Some ( sync_type) = sync_type {
58
- // In expression position, the type needs to be of the form Foo::<Bar>, not Foo<Bar>
59
- let mut formal = sync_type. clone ( ) ;
60
- struct Visitor ;
61
- impl VisitMut for Visitor {
62
- fn visit_path_segment_mut ( & mut self , segment : & mut syn:: PathSegment ) {
63
- if let PathArguments :: AngleBracketed ( args) = & mut segment. arguments {
64
- if args. colon2_token . is_none ( ) {
65
- args. colon2_token = Some ( Token ! [ :: ] ( Span :: call_site ( ) ) ) ;
66
- }
67
- }
68
- }
69
- }
70
- syn:: visit_mut:: visit_type_mut ( & mut Visitor , & mut formal) ;
71
60
quote ! {
72
61
/// Synchronously execute this action.
73
62
pub fn run( self ) -> Result <#sync_type> {
74
- crate :: sync:: TOKIO_RUNTIME . block_on( std:: future:: IntoFuture :: into_future( self ) ) . map( #formal :: new)
63
+ crate :: sync:: TOKIO_RUNTIME . block_on( std:: future:: IntoFuture :: into_future( self ) ) . map( <#sync_type> :: new)
75
64
}
76
65
}
77
66
} else {
@@ -324,3 +313,148 @@ fn text_link(text: &str) -> String {
324
313
}
325
314
out. concat ( )
326
315
}
316
+
317
+ #[ proc_macro]
318
+ pub fn option_setters ( input : proc_macro:: TokenStream ) -> proc_macro:: TokenStream {
319
+ let OptionSettersList {
320
+ opt_field_name,
321
+ opt_field_type,
322
+ setters,
323
+ } = parse_macro_input ! ( input as OptionSettersList ) ;
324
+
325
+ let extras = opt_field_name. map ( |name| {
326
+ quote ! {
327
+ #[ allow( unused) ]
328
+ fn options( & mut self ) -> & mut #opt_field_type {
329
+ self . #name. get_or_insert_with( <#opt_field_type>:: default )
330
+ }
331
+
332
+ /// Set all options. Note that this will replace all previous values set.
333
+ pub fn with_options( mut self , value: impl Into <Option <#opt_field_type>>) -> Self {
334
+ self . #name = value. into( ) ;
335
+ self
336
+ }
337
+ }
338
+ } ) ;
339
+
340
+ let setters: Vec < _ > = setters
341
+ . into_iter ( )
342
+ . map ( |OptionSetter { attrs, name, type_ } | {
343
+ let docstr = format ! (
344
+ "Set the [`{}::{}`] option." ,
345
+ opt_field_type. to_token_stream( ) ,
346
+ name
347
+ ) ;
348
+ let ( accept, value) = if type_. is_ident ( "String" )
349
+ || type_. is_ident ( "Bson" )
350
+ || path_eq ( & type_, & [ "bson" , "Bson" ] )
351
+ {
352
+ ( quote ! { impl Into <#type_> } , quote ! { value. into( ) } )
353
+ } else if let Some ( t) = vec_arg ( & type_) {
354
+ (
355
+ quote ! { impl IntoIterator <Item = #t> } ,
356
+ quote ! { value. into_iter( ) . collect( ) } ,
357
+ )
358
+ } else {
359
+ ( quote ! { #type_ } , quote ! { value } )
360
+ } ;
361
+ quote ! {
362
+ #[ doc = #docstr]
363
+ #( #attrs) *
364
+ pub fn #name( mut self , value: #accept) -> Self {
365
+ self . options( ) . #name = Some ( #value) ;
366
+ self
367
+ }
368
+ }
369
+ } )
370
+ . collect ( ) ;
371
+
372
+ quote ! {
373
+ #extras
374
+ #( #setters) *
375
+ }
376
+ . into ( )
377
+ }
378
+
379
+ fn vec_arg ( path : & Path ) -> Option < & Type > {
380
+ if path. segments . len ( ) != 1 {
381
+ return None ;
382
+ }
383
+ let PathSegment { ident, arguments } = path. segments . first ( ) ?;
384
+ if ident != "Vec" {
385
+ return None ;
386
+ }
387
+ let args = if let PathArguments :: AngleBracketed ( angle) = arguments {
388
+ & angle. args
389
+ } else {
390
+ return None ;
391
+ } ;
392
+ if args. len ( ) != 1 {
393
+ return None ;
394
+ }
395
+ if let GenericArgument :: Type ( t) = args. first ( ) ? {
396
+ return Some ( t) ;
397
+ }
398
+
399
+ None
400
+ }
401
+
402
+ fn path_eq ( path : & Path , segments : & [ & str ] ) -> bool {
403
+ if path. segments . len ( ) != segments. len ( ) {
404
+ return false ;
405
+ }
406
+ for ( actual, expected) in path. segments . iter ( ) . zip ( segments. into_iter ( ) ) {
407
+ if actual. ident != expected {
408
+ return false ;
409
+ }
410
+ if !actual. arguments . is_empty ( ) {
411
+ return false ;
412
+ }
413
+ }
414
+ true
415
+ }
416
+
417
+ struct OptionSettersList {
418
+ opt_field_name : Option < Ident > ,
419
+ opt_field_type : Type ,
420
+ setters : Vec < OptionSetter > ,
421
+ }
422
+
423
+ impl Parse for OptionSettersList {
424
+ fn parse ( input : ParseStream ) -> syn:: Result < Self > {
425
+ let opt_field_name = if input. peek2 ( Token ! [ : ] ) {
426
+ let val = input. parse ( ) ?;
427
+ input. parse :: < Token ! [ : ] > ( ) ?;
428
+ Some ( val)
429
+ } else {
430
+ None
431
+ } ;
432
+ let opt_field_type = input. parse ( ) ?;
433
+ input. parse :: < Token ! [ ; ] > ( ) ?;
434
+ let setters = input
435
+ . parse_terminated ( OptionSetter :: parse, Token ! [ , ] ) ?
436
+ . into_iter ( )
437
+ . collect ( ) ;
438
+ Ok ( Self {
439
+ opt_field_name,
440
+ opt_field_type,
441
+ setters,
442
+ } )
443
+ }
444
+ }
445
+
446
+ struct OptionSetter {
447
+ attrs : Vec < Attribute > ,
448
+ name : Ident ,
449
+ type_ : Path ,
450
+ }
451
+
452
+ impl Parse for OptionSetter {
453
+ fn parse ( input : ParseStream ) -> syn:: Result < Self > {
454
+ let attrs = input. call ( Attribute :: parse_outer) ?;
455
+ let name = input. parse ( ) ?;
456
+ input. parse :: < Token ! [ : ] > ( ) ?;
457
+ let type_ = input. parse ( ) ?;
458
+ Ok ( Self { attrs, name, type_ } )
459
+ }
460
+ }
0 commit comments