1
1
use proc_macro2:: { Ident , TokenStream } ;
2
2
use quote:: { quote, ToTokens } ;
3
- use syn:: { spanned:: Spanned , Error , FnArg , ImplItem , Item , Type , TypePath } ;
3
+ use syn:: { spanned:: Spanned , Error , FnArg , ImplItem , Item , Type , TypePath , Visibility } ;
4
4
5
5
pub fn expand_macro ( tokens : TokenStream ) -> syn:: Result < TokenStream > {
6
6
let item = syn:: parse2 :: < Item > ( tokens) ?;
@@ -20,24 +20,37 @@ pub fn expand_macro(tokens: TokenStream) -> syn::Result<TokenStream> {
20
20
let struct_name = imp. self_ty ;
21
21
let items = imp. items ;
22
22
let mut tokenized = vec ! [ ] ;
23
- let mut has_alarm = false ;
23
+
24
+ #[ derive( Default ) ]
25
+ struct OptionalMethods {
26
+ has_alarm : bool ,
27
+ has_websocket_message : bool ,
28
+ has_websocket_close : bool ,
29
+ has_websocket_error : bool ,
30
+ }
31
+
32
+ let mut optional_methods = OptionalMethods :: default ( ) ;
24
33
25
34
for item in items {
26
35
let impl_method = match item {
27
36
ImplItem :: Fn ( func) => func,
28
37
_ => return Err ( Error :: new_spanned ( item, "Impl block must only contain methods" ) )
29
38
} ;
30
39
40
+ let span = impl_method. sig . ident . span ( ) ;
41
+
31
42
let tokens = match impl_method. sig . ident . to_string ( ) . as_str ( ) {
32
43
"new" => {
33
44
let mut method = impl_method. clone ( ) ;
34
45
method. sig . ident = Ident :: new ( "_new" , method. sig . ident . span ( ) ) ;
46
+ method. vis = Visibility :: Inherited ;
47
+
35
48
36
49
// modify the `state` argument so it is type ObjectState
37
50
let arg_tokens = method. sig . inputs . first_mut ( ) . expect ( "DurableObject `new` method must have 2 arguments: state and env" ) . into_token_stream ( ) ;
38
51
match syn:: parse2 :: < FnArg > ( arg_tokens) ? {
39
52
FnArg :: Typed ( pat) => {
40
- let path = syn:: parse2 :: < TypePath > ( quote ! { worker_sys:: DurableObjectState } ) ?;
53
+ let path = syn:: parse2 :: < TypePath > ( quote ! { worker :: worker_sys:: DurableObjectState } ) ?;
41
54
let mut updated_pat = pat;
42
55
updated_pat. ty = Box :: new ( Type :: Path ( path) ) ;
43
56
@@ -57,17 +70,19 @@ pub fn expand_macro(tokens: TokenStream) -> syn::Result<TokenStream> {
57
70
prepended. extend ( method. block . stmts ) ;
58
71
method. block . stmts = prepended;
59
72
60
- quote ! {
73
+ Ok ( quote ! {
61
74
#pound[ wasm_bindgen:: prelude:: wasm_bindgen( constructor) ]
62
75
pub #method
63
- }
76
+ } )
64
77
} ,
65
78
"fetch" => {
66
79
let mut method = impl_method. clone ( ) ;
67
80
method. sig . ident = Ident :: new ( "_fetch_raw" , method. sig . ident . span ( ) ) ;
68
- quote ! {
81
+ method. vis = Visibility :: Inherited ;
82
+
83
+ Ok ( quote ! {
69
84
#pound[ wasm_bindgen:: prelude:: wasm_bindgen( js_name = fetch) ]
70
- pub fn _fetch( & mut self , req: worker_sys:: web_sys:: Request ) -> js_sys:: Promise {
85
+ pub fn _fetch( & mut self , req: worker :: worker_sys:: web_sys:: Request ) -> worker :: js_sys:: Promise {
71
86
// SAFETY:
72
87
// On the surface, this is unsound because the Durable Object could be dropped
73
88
// while JavaScript still has possession of the future. However,
@@ -77,22 +92,24 @@ pub fn expand_macro(tokens: TokenStream) -> syn::Result<TokenStream> {
77
92
let static_self: & ' static mut Self = unsafe { & mut * ( self as * mut _) } ;
78
93
79
94
wasm_bindgen_futures:: future_to_promise( async move {
80
- static_self. _fetch_raw( req. into( ) ) . await . map( worker_sys:: web_sys:: Response :: from) . map( wasm_bindgen:: JsValue :: from)
95
+ static_self. _fetch_raw( req. into( ) ) . await . map( worker :: worker_sys:: web_sys:: Response :: from) . map( wasm_bindgen:: JsValue :: from)
81
96
. map_err( wasm_bindgen:: JsValue :: from)
82
97
} )
83
98
}
84
99
85
100
#method
86
- }
101
+ } )
87
102
} ,
88
103
"alarm" => {
89
- has_alarm = true ;
104
+ optional_methods . has_alarm = true ;
90
105
91
106
let mut method = impl_method. clone ( ) ;
92
107
method. sig . ident = Ident :: new ( "_alarm_raw" , method. sig . ident . span ( ) ) ;
93
- quote ! {
108
+ method. vis = Visibility :: Inherited ;
109
+
110
+ Ok ( quote ! {
94
111
#pound[ wasm_bindgen:: prelude:: wasm_bindgen( js_name = alarm) ]
95
- pub fn _alarm( & mut self ) -> js_sys:: Promise {
112
+ pub fn _alarm( & mut self ) -> worker :: js_sys:: Promise {
96
113
// SAFETY:
97
114
// On the surface, this is unsound because the Durable Object could be dropped
98
115
// while JavaScript still has possession of the future. However,
@@ -102,24 +119,131 @@ pub fn expand_macro(tokens: TokenStream) -> syn::Result<TokenStream> {
102
119
let static_self: & ' static mut Self = unsafe { & mut * ( self as * mut _) } ;
103
120
104
121
wasm_bindgen_futures:: future_to_promise( async move {
105
- static_self. _alarm_raw( ) . await . map( worker_sys:: web_sys:: Response :: from) . map( wasm_bindgen:: JsValue :: from)
122
+ static_self. _alarm_raw( ) . await . map( worker :: worker_sys:: web_sys:: Response :: from) . map( wasm_bindgen:: JsValue :: from)
106
123
. map_err( wasm_bindgen:: JsValue :: from)
107
124
} )
108
125
}
109
126
110
127
#method
111
- }
112
- }
113
- _ => panic ! ( )
128
+ } )
129
+ } ,
130
+ "websocket_message" => {
131
+ optional_methods. has_websocket_message = true ;
132
+
133
+ let mut method = impl_method. clone ( ) ;
134
+ method. sig . ident = Ident :: new ( "_websocket_message_raw" , method. sig . ident . span ( ) ) ;
135
+ method. vis = Visibility :: Inherited ;
136
+
137
+ Ok ( quote ! {
138
+ #pound[ wasm_bindgen:: prelude:: wasm_bindgen( js_name = webSocketMessage) ]
139
+ pub fn _websocket_message( & mut self , ws: worker:: worker_sys:: web_sys:: WebSocket , message: wasm_bindgen:: JsValue ) -> worker:: js_sys:: Promise {
140
+ let ws_message = if let Some ( string_message) = message. as_string( ) {
141
+ worker:: WebSocketIncomingMessage :: String ( string_message)
142
+ } else {
143
+ let v = worker:: js_sys:: Uint8Array :: new( & message) . to_vec( ) ;
144
+ worker:: WebSocketIncomingMessage :: Binary ( v)
145
+ } ;
146
+
147
+ // SAFETY:
148
+ // On the surface, this is unsound because the Durable Object could be dropped
149
+ // while JavaScript still has possession of the future. However,
150
+ // we know something that Rust doesn't: that the Durable Object will never be destroyed
151
+ // while there is still a running promise inside of it, therefore we can let a reference
152
+ // to the durable object escape into a static-lifetime future.
153
+ let static_self: & ' static mut Self = unsafe { & mut * ( self as * mut _) } ;
154
+
155
+ wasm_bindgen_futures:: future_to_promise( async move {
156
+ static_self. _websocket_message_raw( ws. into( ) , ws_message) . await . map( |_| wasm_bindgen:: JsValue :: NULL )
157
+ . map_err( wasm_bindgen:: JsValue :: from)
158
+ } )
159
+ }
160
+
161
+ #method
162
+ } )
163
+ } ,
164
+ "websocket_close" => {
165
+ optional_methods. has_websocket_close = true ;
166
+
167
+ let mut method = impl_method. clone ( ) ;
168
+ method. sig . ident = Ident :: new ( "_websocket_close_raw" , method. sig . ident . span ( ) ) ;
169
+ method. vis = Visibility :: Inherited ;
170
+
171
+ Ok ( quote ! {
172
+ #pound[ wasm_bindgen:: prelude:: wasm_bindgen( js_name = webSocketClose) ]
173
+ pub fn _websocket_close( & mut self , ws: worker:: worker_sys:: web_sys:: WebSocket , code: usize , reason: String , was_clean: bool ) -> worker:: js_sys:: Promise {
174
+ // SAFETY:
175
+ // On the surface, this is unsound because the Durable Object could be dropped
176
+ // while JavaScript still has possession of the future. However,
177
+ // we know something that Rust doesn't: that the Durable Object will never be destroyed
178
+ // while there is still a running promise inside of it, therefore we can let a reference
179
+ // to the durable object escape into a static-lifetime future.
180
+ let static_self: & ' static mut Self = unsafe { & mut * ( self as * mut _) } ;
181
+
182
+ wasm_bindgen_futures:: future_to_promise( async move {
183
+ static_self. _websocket_close_raw( ws. into( ) , code, reason, was_clean) . await . map( |_| wasm_bindgen:: JsValue :: NULL )
184
+ . map_err( wasm_bindgen:: JsValue :: from)
185
+ } )
186
+ }
187
+
188
+ #method
189
+ } )
190
+ } ,
191
+ "websocket_error" => {
192
+ optional_methods. has_websocket_error = true ;
193
+
194
+ let mut method = impl_method. clone ( ) ;
195
+ method. sig . ident = Ident :: new ( "_websocket_error_raw" , method. sig . ident . span ( ) ) ;
196
+ method. vis = Visibility :: Inherited ;
197
+
198
+ Ok ( quote ! {
199
+ #pound[ wasm_bindgen:: prelude:: wasm_bindgen( js_name = webSocketError) ]
200
+ pub fn _websocket_error( & mut self , ws: worker:: worker_sys:: web_sys:: WebSocket , error: wasm_bindgen:: JsValue ) -> worker:: js_sys:: Promise {
201
+ // SAFETY:
202
+ // On the surface, this is unsound because the Durable Object could be dropped
203
+ // while JavaScript still has possession of the future. However,
204
+ // we know something that Rust doesn't: that the Durable Object will never be destroyed
205
+ // while there is still a running promise inside of it, therefore we can let a reference
206
+ // to the durable object escape into a static-lifetime future.
207
+ let static_self: & ' static mut Self = unsafe { & mut * ( self as * mut _) } ;
208
+
209
+ wasm_bindgen_futures:: future_to_promise( async move {
210
+ static_self. _websocket_error_raw( ws. into( ) , error. into( ) ) . await . map( |_| wasm_bindgen:: JsValue :: NULL )
211
+ . map_err( wasm_bindgen:: JsValue :: from)
212
+ } )
213
+ }
214
+
215
+ #method
216
+ } )
217
+ } ,
218
+ ident => Err ( Error :: new ( span, format ! ( "Unsupported method `{}`, please move extra impl methods to a separate impl definition" , ident) ) )
114
219
} ;
115
- tokenized. push ( tokens) ;
220
+ tokenized. push ( tokens? ) ;
116
221
}
117
222
118
- let alarm_tokens = has_alarm. then ( || quote ! {
223
+ let alarm_tokens = optional_methods . has_alarm . then ( || quote ! {
119
224
async fn alarm( & mut self ) -> :: worker:: Result <worker:: Response > {
120
225
self . _alarm_raw( ) . await
121
226
}
122
227
} ) ;
228
+
229
+ let websocket_message_tokens = optional_methods. has_websocket_message . then ( || quote ! {
230
+ async fn websocket_message( & mut self , ws: :: worker:: WebSocket , message: :: worker:: WebSocketIncomingMessage ) -> :: worker:: Result <( ) > {
231
+ self . _websocket_message_raw( ws, message) . await
232
+ }
233
+ } ) ;
234
+
235
+ let websocket_close_tokens = optional_methods. has_websocket_close . then ( || quote ! {
236
+ async fn websocket_close( & mut self , ws: :: worker:: WebSocket , code: usize , reason: String , was_clean: bool ) -> :: worker:: Result <( ) > {
237
+ self . _websocket_close_raw( ws, code, reason, was_clean) . await
238
+ }
239
+ } ) ;
240
+
241
+ let websocket_error_tokens = optional_methods. has_websocket_error . then ( || quote ! {
242
+ async fn websocket_error( & mut self , ws: :: worker:: WebSocket , error: :: worker:: Error ) -> :: worker:: Result <( ) > {
243
+ self . _websocket_error_raw( ws, error) . await
244
+ }
245
+ } ) ;
246
+
123
247
Ok ( quote ! {
124
248
#wasm_bindgen_attr
125
249
impl #struct_name {
@@ -137,6 +261,12 @@ pub fn expand_macro(tokens: TokenStream) -> syn::Result<TokenStream> {
137
261
}
138
262
139
263
#alarm_tokens
264
+
265
+ #websocket_message_tokens
266
+
267
+ #websocket_close_tokens
268
+
269
+ #websocket_error_tokens
140
270
}
141
271
142
272
trait __Need_Durable_Object_Trait_Impl_With_durable_object_Attribute { const MACROED : bool = true ; }
0 commit comments