1#![cfg_attr(feature = "nightly", feature(proc_macro))]
13#![recursion_limit = "128"]
14
15
16macro_rules! if_nightly {
17 ($($i:item)*) => ($(
18 #[cfg(feature = "nightly")]
19 $i
20 )*)
21}
22
23if_nightly! {
24 extern crate proc_macro2;
25 extern crate proc_macro;
26 #[macro_use]
27 extern crate quote;
28 #[macro_use]
29 extern crate syn;
30
31 use proc_macro2::Span;
32 use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
33 use quote::{Tokens, ToTokens};
34 use syn::*;
35 use syn::punctuated::Punctuated;
36 use syn::fold::Fold;
37
38 mod attribute;
39 mod elision;
40
41 use attribute::Attribute;
42
43 macro_rules! quote_cs {
44 ($($t:tt)*) => (quote_spanned!(Span::call_site() => $($t)*))
45 }
46
47 fn async_inner<F>(
48 attribute: Attribute,
49 function: TokenStream,
50 gen_function: Tokens,
51 return_ty: F,
52 ) -> TokenStream
53 where F: FnOnce(&Type, &[&Lifetime]) -> proc_macro2::TokenStream
54 {
55 let ItemFn {
59 ident,
60 vis,
61 unsafety,
62 constness,
63 abi,
64 block,
65 decl,
66 attrs,
67 ..
68 } = match syn::parse(function).expect("failed to parse tokens as a function") {
69 Item::Fn(item) => item,
70 _ => panic!("#[async] can only be applied to functions"),
71 };
72 let FnDecl {
73 inputs,
74 output,
75 variadic,
76 mut generics,
77 fn_token,
78 ..
79 } = { *decl };
80 let where_clause = &generics.where_clause;
81 assert!(variadic.is_none(), "variadic functions cannot be async");
82 let (output, rarrow_token) = match output {
83 ReturnType::Type(rarrow_token, t) => (*t, rarrow_token),
84 ReturnType::Default => {
85 (TypeTuple {
86 elems: Default::default(),
87 paren_token: Default::default(),
88 }.into(), Default::default())
89 }
90 };
91
92 let mut inputs_no_patterns = Vec::new();
116 let mut patterns = Vec::new();
117 let mut temp_bindings = Vec::new();
118 for (i, input) in inputs.into_iter().enumerate() {
119 let mut is_input_no_pattern = false;
121 if let FnArg::Captured(ref arg) = input {
122 if let Pat::Ident(PatIdent { ref ident, ..}) = arg.pat {
123 if ident == "self" {
124 is_input_no_pattern = true;
125 }
126 }
127 }
128 if is_input_no_pattern {
129 inputs_no_patterns.push(input);
130 continue
131 }
132
133 match input {
134 FnArg::Captured(ArgCaptured {
135 pat: syn::Pat::Ident(syn::PatIdent {
136 by_ref: None,
137 ..
138 }),
139 ..
140 }) => {
141 inputs_no_patterns.push(input);
142 }
143
144 FnArg::Captured(ArgCaptured { pat, ty, colon_token }) => {
146 patterns.push(pat);
147 let ident = Ident::from(format!("__arg_{}", i));
148 temp_bindings.push(ident.clone());
149 let pat = PatIdent {
150 by_ref: None,
151 mutability: None,
152 ident: ident,
153 subpat: None,
154 };
155 inputs_no_patterns.push(ArgCaptured {
156 pat: pat.into(),
157 ty,
158 colon_token,
159 }.into());
160 }
161
162 _ => {
164 inputs_no_patterns.push(input);
165 }
166 }
167 }
168
169
170 let block = ExpandAsyncFor.fold_block(*block);
178
179
180 let inputs_no_patterns = elision::unelide_lifetimes(&mut generics.params, inputs_no_patterns);
181 let lifetimes: Vec<_> = generics.lifetimes().map(|l| &l.lifetime).collect();
182
183 let return_ty = return_ty(&output, &lifetimes);
184
185
186 let block_inner = quote_cs! {
187 #( let #patterns = #temp_bindings; )*
188 #block
189 };
190 let mut result = Tokens::new();
191 block.brace_token.surround(&mut result, |tokens| {
192 block_inner.to_tokens(tokens);
193 });
194 syn::token::Semi([block.brace_token.0]).to_tokens(&mut result);
195
196 let gen_body_inner = quote_cs! {
197 let __e: #output = #result
198
199 #[allow(unreachable_code)]
202 {
203 return __e;
204 loop { yield ::futures::__rt::Async::Pending }
205 }
206 };
207 let mut gen_body = Tokens::new();
208 block.brace_token.surround(&mut gen_body, |tokens| {
209 gen_body_inner.to_tokens(tokens);
210 });
211
212 let output_span = first_last(&output);
216 let gen_function = respan(gen_function.into(), &output_span);
217 let body_inner = quote_cs! {
218 #gen_function (static move || -> #output #gen_body)
219 };
220
221 let body_inner = if attribute.boxed {
222 respan(if attribute.send {
223 quote_cs! { (#body_inner).pin() }
224 } else {
225 quote_cs! { (#body_inner).pin_local() }
226 }.into(), &output_span)
227 } else {
228 body_inner.into()
229 };
230
231 let mut body = Tokens::new();
232 block.brace_token.surround(&mut body, |tokens| {
233 body_inner.to_tokens(tokens);
234 });
235
236 let output = quote_cs! {
237 #(#attrs)*
238 #vis #unsafety #abi #constness
239 #fn_token #ident #generics(#(#inputs_no_patterns),*)
240 #rarrow_token #return_ty
241 #where_clause
242 #body
243 };
244
245 output.into()
247 }
248
249 #[proc_macro_attribute]
250 pub fn async(attribute: TokenStream, function: TokenStream) -> TokenStream {
251 let attr = attribute.to_string();
252 let args = syn::parse::<AsyncArgs>(attribute)
254 .expect(&format!("failed to parse attribute arguments: {}", attr));
255
256 let attribute = Attribute::from(args.0.into_iter().map(|arg| arg.0));
257
258 async_inner(attribute, function, quote_cs! { ::futures::__rt::gen_future }, |output, lifetimes| {
259 let output_span = first_last(&output);
262 let return_ty = match attribute {
263 Attribute::NONE => quote_cs! {
264 impl ::futures::__rt::MyStableFuture<!> + #(#lifetimes +)*
265 },
266 Attribute::SEND => quote_cs! {
267 impl ::futures::__rt::MyStableFuture<!> + Send + #(#lifetimes +)*
268 },
269 Attribute::BOXED => quote_cs! {
270 ::futures::__rt::std::boxed::PinBox<::futures::__rt::Future<
271 Item = <! as ::futures::__rt::IsResult>::Ok,
272 Error = <! as ::futures::__rt::IsResult>::Err,
273 > + #(#lifetimes +)*>
274 },
275 Attribute::BOXED_SEND => quote_cs! {
276 ::futures::__rt::std::boxed::PinBox<::futures::__rt::Future<
277 Item = <! as ::futures::__rt::IsResult>::Ok,
278 Error = <! as ::futures::__rt::IsResult>::Err,
279 > + Send + #(#lifetimes +)*>
280 },
281 };
282 let return_ty = respan(return_ty.into(), &output_span);
283 replace_bang(return_ty, &output)
284 })
285 }
286
287 #[proc_macro_attribute]
288 pub fn async_stream(attribute: TokenStream, function: TokenStream) -> TokenStream {
289 let args = syn::parse::<AsyncStreamArgs>(attribute)
291 .expect("failed to parse attribute arguments");
292
293 let (args, valued_args): (Vec<_>, Vec<_>) = args.0.into_iter().partition(|arg| arg.1.is_none());
294 let args = args.into_iter().map(|arg| arg.0);
295 let valued_args = valued_args.into_iter().map(|arg| (arg.0, arg.1.unwrap()));
296
297 let mut item_ty = None;
298
299 for (term, ty) in valued_args {
300 match term.as_ref() {
301 "item" => {
302 if item_ty.is_some() {
303 panic!("duplicate 'item' argument");
304 }
305 item_ty = Some(ty);
306 }
307 _ => {
308 panic!("unexpected macro argument '{}'", quote_cs!(#term = #ty));
309 }
310 }
311 }
312
313 let item_ty = item_ty.expect("#[async_stream] requires item type to be specified");
314 let attribute = Attribute::from(args);
315
316 async_inner(attribute, function, quote_cs! { ::futures::__rt::gen_stream }, |output, lifetimes| {
317 let return_ty = match attribute {
318 Attribute::NONE => quote_cs! {
319 impl ::futures::__rt::MyStableStream<!, !> + #(#lifetimes +)*
320 },
321 Attribute::SEND => quote_cs! {
322 impl ::futures::__rt::MyStableStream<!, !> + Send + #(#lifetimes +)*
323 },
324 Attribute::BOXED => quote_cs! {
325 ::futures::__rt::std::boxed::PinBox<::futures::__rt::Stream<
326 Item = !,
327 Error = <! as ::futures::__rt::IsResult>::Err,
328 > + #(#lifetimes +)*>
329 },
330 Attribute::BOXED_SEND => quote_cs! {
331 ::futures::__rt::std::boxed::PinBox<::futures::__rt::Stream<
332 Item = !,
333 Error = <! as ::futures::__rt::IsResult>::Err,
334 > + Send + #(#lifetimes +)*>
335 },
336 };
337 let output_span = first_last(&output);
338 let return_ty = respan(return_ty.into(), &output_span);
339 replace_bangs(return_ty, &[&item_ty, &output])
340 })
341 }
342
343 #[proc_macro]
344 pub fn async_block(input: TokenStream) -> TokenStream {
345 let input = TokenStream::from(TokenTree::Group(Group::new(Delimiter::Brace, input)));
346 let expr = syn::parse(input)
347 .expect("failed to parse tokens as an expression");
348 let expr = ExpandAsyncFor.fold_expr(expr);
349
350 let mut tokens = quote_cs! {
351 ::futures::__rt::gen_future
352 };
353
354 let span = Span::call_site();
357 syn::token::Paren(span).surround(&mut tokens, |tokens| {
358 syn::token::Static(span).to_tokens(tokens);
359 syn::token::Move(span).to_tokens(tokens);
360 syn::token::OrOr([span, span]).to_tokens(tokens);
361 syn::token::Brace(span).surround(tokens, |tokens| {
362 (quote_cs! {
363 if false { yield ::futures::__rt::Async::Pending }
364 }).to_tokens(tokens);
365 expr.to_tokens(tokens);
366 });
367 });
368
369 tokens.into()
370 }
371
372 #[proc_macro]
373 pub fn async_stream_block(input: TokenStream) -> TokenStream {
374 let input = TokenStream::from(TokenTree::Group(Group::new(Delimiter::Brace, input)));
375 let expr = syn::parse(input)
376 .expect("failed to parse tokens as an expression");
377 let expr = ExpandAsyncFor.fold_expr(expr);
378
379 let mut tokens = quote_cs! {
380 ::futures::__rt::gen_stream
381 };
382
383 let span = Span::call_site();
386 syn::token::Paren(span).surround(&mut tokens, |tokens| {
387 syn::token::Static(span).to_tokens(tokens);
388 syn::token::Move(span).to_tokens(tokens);
389 syn::token::OrOr([span, span]).to_tokens(tokens);
390 syn::token::Brace(span).surround(tokens, |tokens| {
391 (quote_cs! {
392 if false { yield ::futures::__rt::Async::Pending }
393 }).to_tokens(tokens);
394 expr.to_tokens(tokens);
395 });
396 });
397
398 tokens.into()
399 }
400
401 struct ExpandAsyncFor;
402
403 impl Fold for ExpandAsyncFor {
404 fn fold_expr(&mut self, expr: Expr) -> Expr {
405 let expr = fold::fold_expr(self, expr);
406 let mut async = false;
407 {
408 let attrs = match expr {
409 Expr::ForLoop(syn::ExprForLoop { ref attrs, .. }) => attrs,
410 _ => return expr,
411 };
412 if attrs.len() == 1 {
413 if attrs[0].path.segments.first().unwrap().value().ident == "async" {
415 async = true;
416 }
417 }
418 }
419 if !async {
420 return expr
421 }
422 let all = match expr {
423 Expr::ForLoop(item) => item,
424 _ => panic!("only for expressions can have #[async]"),
425 };
426 let ExprForLoop { pat, expr, body, label, .. } = all;
427
428 let tokens = quote_cs! {{
430 let mut __stream = #expr;
431 #label
432 loop {
433 let #pat = {
434 let r = {
435 let pin = unsafe {
436 ::futures::__rt::std::mem::Pin::new_unchecked(&mut __stream)
437 };
438 ::futures::__rt::in_ctx(|ctx| ::futures::__rt::StableStream::poll_next(pin, ctx))
439 };
440 match r? {
441 ::futures::__rt::Async::Ready(e) => {
442 match e {
443 ::futures::__rt::std::option::Option::Some(e) => e,
444 ::futures::__rt::std::option::Option::None => break,
445 }
446 }
447 ::futures::__rt::Async::Pending => {
448 yield ::futures::__rt::Async::Pending;
449 continue
450 }
451 }
452 };
453
454 #body
455 }
456 }};
457 syn::parse(tokens.into()).unwrap()
458 }
459
460 fn fold_item(&mut self, item: Item) -> Item {
462 item
463 }
464 }
465
466 fn first_last(tokens: &ToTokens) -> (Span, Span) {
467 let mut spans = Tokens::new();
468 tokens.to_tokens(&mut spans);
469 let good_tokens = proc_macro2::TokenStream::from(spans).into_iter().collect::<Vec<_>>();
470 let first_span = good_tokens.first().map(|t| t.span()).unwrap_or(Span::call_site());
471 let last_span = good_tokens.last().map(|t| t.span()).unwrap_or(first_span);
472 (first_span, last_span)
473 }
474
475 fn respan(input: proc_macro2::TokenStream,
476 &(first_span, last_span): &(Span, Span)) -> proc_macro2::TokenStream {
477 let mut new_tokens = input.into_iter().collect::<Vec<_>>();
478 if let Some(token) = new_tokens.first_mut() {
479 token.set_span(first_span);
480 }
481 for token in new_tokens.iter_mut().skip(1) {
482 token.set_span(last_span);
483 }
484 new_tokens.into_iter().collect()
485 }
486
487 fn replace_bang(input: proc_macro2::TokenStream, tokens: &ToTokens)
488 -> proc_macro2::TokenStream
489 {
490 let mut new_tokens = Tokens::new();
491 for token in input.into_iter() {
492 match token {
493 proc_macro2::TokenTree::Op(op) if op.op() == '!' => tokens.to_tokens(&mut new_tokens),
494 _ => token.to_tokens(&mut new_tokens),
495 }
496 }
497 new_tokens.into()
498 }
499
500 fn replace_bangs(input: proc_macro2::TokenStream, replacements: &[&ToTokens])
501 -> proc_macro2::TokenStream
502 {
503 let mut replacements = replacements.iter().cycle();
504 let mut new_tokens = Tokens::new();
505 for token in input.into_iter() {
506 match token {
507 proc_macro2::TokenTree::Op(op) if op.op() == '!' => {
508 replacements.next().unwrap().to_tokens(&mut new_tokens);
509 }
510 _ => token.to_tokens(&mut new_tokens),
511 }
512 }
513 new_tokens.into()
514 }
515
516 struct AsyncArg(syn::Ident);
517
518 impl synom::Synom for AsyncArg {
519 named!(parse -> Self, do_parse!(
520 i: syn!(syn::Ident) >>
521 (AsyncArg(i))));
522 }
523
524 struct AsyncArgs(Vec<AsyncArg>);
525
526 impl synom::Synom for AsyncArgs {
527 named!(parse -> Self, map!(
528 option!(parens!(call!(Punctuated::<AsyncArg, syn::token::Comma>::parse_separated_nonempty))),
529 |p| AsyncArgs(p.map(|d| d.1.into_iter().collect()).unwrap_or_default())
530 ));
531 }
532
533 struct AsyncStreamArg(syn::Ident, Option<syn::Type>);
534
535 impl synom::Synom for AsyncStreamArg {
536 named!(parse -> Self, do_parse!(
537 i: syn!(syn::Ident) >>
538 p: option!(do_parse!(
539 syn!(syn::token::Eq) >>
540 p: syn!(syn::Type) >>
541 (p))) >>
542 (AsyncStreamArg(i, p))));
543 }
544
545 struct AsyncStreamArgs(Vec<AsyncStreamArg>);
546
547 impl synom::Synom for AsyncStreamArgs {
548 named!(parse -> Self, map!(
549 option!(parens!(call!(Punctuated::<AsyncStreamArg, syn::token::Comma>::parse_separated_nonempty))),
550 |p| AsyncStreamArgs(p.map(|d| d.1.into_iter().collect()).unwrap_or_default())
551 ));
552 }
553}