1+ use anyhow:: { Result , bail} ;
2+ use std:: collections:: HashSet ;
13use std:: fmt;
2- use std:: fmt:: Write ;
34use wit_parser:: { Function , FunctionKind , Resolve , WorldKey } ;
45
5- use crate :: define_filter_set;
6- use crate :: filter:: { FilterMode , FilterRule , FilterTarget } ;
7-
8- define_filter_set ! {
9- /// Structure used to parse the command line argument `--async` consistently
10- /// across guest generators.
11- pub struct AsyncFilterSet ,
6+ /// Structure used to parse the command line argument `--async` consistently
7+ /// across guest generators.
8+ #[ cfg_attr( feature = "clap" , derive( clap:: Parser ) ) ]
9+ #[ cfg_attr( feature = "serde" , derive( serde:: Deserialize ) ) ]
10+ #[ derive( Clone , Default , Debug ) ]
11+ pub struct AsyncFilterSet {
1212 /// Determines which functions to lift or lower `async`, if any.
1313 ///
1414 /// This option can be passed multiple times and additionally accepts
1515 /// comma-separated values for each option passed. Each individual argument
1616 /// passed here can be one of:
1717 ///
1818 /// - `all` - all imports and exports will be async
19- ///
2019 /// - `-all` - force all imports and exports to be sync
21- ///
2220 /// - `foo:bar/baz#method` - force this method to be async
23- ///
2421 /// - `import:foo:bar/baz#method` - force this method to be async, but only
2522 /// as an import
26- ///
2723 /// - `-export:foo:bar/baz#method` - force this export to be sync
2824 ///
29- ///
3025 /// If a method is not listed in this option then the WIT's default bindings
3126 /// mode will be used. If the WIT function is defined as `async` then async
3227 /// bindings will be generated, otherwise sync bindings will be generated.
3328 ///
3429 /// Options are processed in the order they are passed here, so if a method
3530 /// matches two directives passed the least-specific one should be last.
36- bool , AsyncFilter ,
37- "async"
31+ #[ cfg_attr(
32+ feature = "clap" ,
33+ arg(
34+ long = "async" ,
35+ value_parser = parse_async,
36+ value_delimiter =',' ,
37+ value_name = "FILTER" ,
38+ ) ,
39+ ) ]
40+ #[ cfg_attr( feature = "serde" , serde( rename = "async" ) ) ]
41+ async_ : Vec < Async > ,
42+
43+ #[ cfg_attr( feature = "clap" , arg( skip) ) ]
44+ #[ cfg_attr( feature = "serde" , serde( skip) ) ]
45+ used_options : HashSet < usize > ,
46+ }
47+
48+ #[ cfg( feature = "clap" ) ]
49+ fn parse_async ( s : & str ) -> Result < Async , String > {
50+ Ok ( Async :: parse ( s) )
3851}
3952
4053impl AsyncFilterSet {
41- pub fn any_enabled ( & self ) -> bool {
42- self . rules . iter ( ) . any ( |o| o. mode )
54+ /// Returns a set where all functions should be async or not depending on
55+ /// `async_` provided.
56+ pub fn all ( async_ : bool ) -> AsyncFilterSet {
57+ AsyncFilterSet {
58+ async_ : vec ! [ Async {
59+ enabled: async_,
60+ filter: AsyncFilter :: All ,
61+ } ] ,
62+ used_options : HashSet :: new ( ) ,
63+ }
4364 }
4465
45- fn apply_rules (
66+ /// Returns whether the `func` provided is to be bound `async` or not.
67+ pub fn is_async (
4668 & mut self ,
4769 resolve : & Resolve ,
4870 interface : Option < & WorldKey > ,
@@ -53,12 +75,11 @@ impl AsyncFilterSet {
5375 Some ( key) => format ! ( "{}#{}" , resolve. name_world_key( key) , func. name) ,
5476 None => func. name . clone ( ) ,
5577 } ;
56-
57- for ( i, opt) in self . rules . iter ( ) . enumerate ( ) {
78+ for ( i, opt) in self . async_ . iter ( ) . enumerate ( ) {
5879 let name = match & opt. filter {
5980 AsyncFilter :: All => {
6081 self . used_options . insert ( i) ;
61- return opt. mode ;
82+ return opt. enabled ;
6283 }
6384 AsyncFilter :: Function ( s) => s,
6485 AsyncFilter :: Import ( s) => {
@@ -76,62 +97,97 @@ impl AsyncFilterSet {
7697 } ;
7798 if * name == name_to_test {
7899 self . used_options . insert ( i) ;
79- return opt. mode ;
100+ return opt. enabled ;
80101 }
81102 }
82103
83- matches ! (
84- func. kind,
104+ match & func. kind {
105+ FunctionKind :: Freestanding
106+ | FunctionKind :: Method ( _)
107+ | FunctionKind :: Static ( _)
108+ | FunctionKind :: Constructor ( _) => false ,
85109 FunctionKind :: AsyncFreestanding
86- | FunctionKind :: AsyncMethod ( _)
87- | FunctionKind :: AsyncStatic ( _)
88- )
110+ | FunctionKind :: AsyncMethod ( _)
111+ | FunctionKind :: AsyncStatic ( _) => true ,
112+ }
89113 }
90- }
91114
92- impl FilterMode for bool {
93- fn parse ( s : & str ) -> ( Self , & str ) {
94- match s. strip_prefix ( '-' ) {
95- Some ( rest) => ( false , rest) ,
96- None => ( true , s) ,
97- }
115+ /// Intended to be used in the header comment of generated code to help
116+ /// indicate what options were specified.
117+ pub fn debug_opts ( & self ) -> impl Iterator < Item = String > + ' _ {
118+ self . async_ . iter ( ) . map ( |opt| opt. to_string ( ) )
98119 }
99- fn fmt_prefix ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
100- if !* self {
101- f. write_char ( '-' ) ?;
120+
121+ /// Tests whether all `--async` options were used throughout bindings
122+ /// generation, returning an error if any were unused.
123+ pub fn ensure_all_used ( & self ) -> Result < ( ) > {
124+ for ( i, opt) in self . async_ . iter ( ) . enumerate ( ) {
125+ if self . used_options . contains ( & i) {
126+ continue ;
127+ }
128+ if !matches ! ( opt. filter, AsyncFilter :: All ) {
129+ bail ! ( "unused async option: {opt}" ) ;
130+ }
102131 }
103132 Ok ( ( ) )
104133 }
134+
135+ /// Returns whether any option explicitly requests that async is enabled.
136+ pub fn any_enabled ( & self ) -> bool {
137+ self . async_ . iter ( ) . any ( |o| o. enabled )
138+ }
139+
140+ /// Pushes a new option into this set.
141+ pub fn push ( & mut self , directive : & str ) {
142+ self . async_ . push ( Async :: parse ( directive) ) ;
143+ }
105144}
106145
107- #[ derive( Debug , Clone , PartialEq ) ]
146+ #[ derive( Debug , Clone ) ]
108147#[ cfg_attr( feature = "serde" , derive( serde:: Deserialize ) ) ]
109- pub enum AsyncFilter {
110- All ,
111- Function ( String ) ,
112- Import ( String ) ,
113- Export ( String ) ,
148+ struct Async {
149+ enabled : bool ,
150+ filter : AsyncFilter ,
114151}
115152
116- impl FilterTarget for AsyncFilter {
117- fn parse ( s : & str ) -> Self {
118- match s {
153+ impl Async {
154+ fn parse ( s : & str ) -> Async {
155+ let ( s, enabled) = match s. strip_prefix ( '-' ) {
156+ Some ( s) => ( s, false ) ,
157+ None => ( s, true ) ,
158+ } ;
159+ let filter = match s {
119160 "all" => AsyncFilter :: All ,
120161 other => match other. strip_prefix ( "import:" ) {
121- Some ( sub ) => AsyncFilter :: Import ( sub . to_string ( ) ) ,
162+ Some ( s ) => AsyncFilter :: Import ( s . to_string ( ) ) ,
122163 None => match other. strip_prefix ( "export:" ) {
123- Some ( sub ) => AsyncFilter :: Export ( sub . to_string ( ) ) ,
124- None => AsyncFilter :: Function ( other . to_string ( ) ) ,
164+ Some ( s ) => AsyncFilter :: Export ( s . to_string ( ) ) ,
165+ None => AsyncFilter :: Function ( s . to_string ( ) ) ,
125166 } ,
126167 } ,
127- }
168+ } ;
169+ Async { enabled, filter }
128170 }
171+ }
129172
130- fn all ( ) -> AsyncFilter {
131- AsyncFilter :: All
173+ impl fmt:: Display for Async {
174+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
175+ if !self . enabled {
176+ write ! ( f, "-" ) ?;
177+ }
178+ self . filter . fmt ( f)
132179 }
133180}
134181
182+ #[ derive( Debug , Clone ) ]
183+ #[ cfg_attr( feature = "serde" , derive( serde:: Deserialize ) ) ]
184+ enum AsyncFilter {
185+ All ,
186+ Function ( String ) ,
187+ Import ( String ) ,
188+ Export ( String ) ,
189+ }
190+
135191impl fmt:: Display for AsyncFilter {
136192 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
137193 match self {
0 commit comments