rayon_attr/lib.rs
1#![feature(proc_macro)]
2
3extern crate proc_macro;
4
5#[feature(full)]
6extern crate syn;
7
8#[macro_use]
9extern crate quote;
10
11use proc_macro::TokenStream;
12use quote::ToTokens;
13use syn::ExprForLoop;
14
15/// Converts a for-loop to rayon parallel for_each.
16///
17/// Only valid on when applied to a for statement, with #![feature(stmt_expr_attributes)] present.
18#[proc_macro_attribute]
19pub fn parallel(_args: TokenStream, input: TokenStream) -> TokenStream {
20 // Return the input unchanged if it failed to parse. The compiler will show
21 // the right diagnostics.
22 let input: ExprForLoop =
23 syn::parse(input.clone()).expect("parallel attribute may only be applied to for loops.");
24
25 // TODO support input.label
26 // TODO support input.attrs
27 let expr = input.expr.clone().into_tokens();
28 let body = input.body.clone().into_tokens();
29 let pat = input.pat.clone().into_tokens();
30
31 // TODO check for early returns in the for loop, they would be errors in the parallel version.
32 let parallelized = quote!((#expr).into_par_iter().for_each(|#pat| #body));
33
34 parallelized.to_string().parse().unwrap()
35}
36
37/*
38Unit test panics, possibly because we are a proc-macro crate:
39
40---- tests::for_loop stdout ----
41 thread 'tests::for_loop' panicked at 'proc_macro::__internal::with_sess() called before set_parse_sess()!', libproc_macro\lib.rs:898:9
42stack backtrace:
43 0: std::rt::lang_start_internal
44 1: std::sys::windows::c::TryAcquireSRWLockShared
45 2: std::panicking::take_hook
46 3: std::panicking::take_hook
47 4: std::panicking::rust_panic_with_hook
48 5: proc_macro::__internal::CURRENT_SESS::__getit
49 6: proc_macro::__internal::in_sess
50 7: <proc_macro::TokenStream as core::str::FromStr>::from_str
51 8: core::str::{{impl}}::parse<proc_macro::TokenStream>
52 at C:\projects\rust\src\libcore\str\mod.rs:2534
53 9: alloc::str::{{impl}}::parse<proc_macro::TokenStream>
54 at C:\projects\rust\src\liballoc\str.rs:1798
55 10: rayon_attr::tests::for_loop
56 at .\src\lib.rs:44
57 11: rayon_attr::__test::TESTS::{{closure}}
58 at .\src\lib.rs:43
59 12: core::ops::function::FnOnce::call_once<closure,()>
60 at C:\projects\rust\src\libcore\ops\function.rs:223
61 13: <unknown>
62 14: _rust_maybe_catch_panic
63 15: test::stats::winsorize
64 16: <test::TestOpts as core::fmt::Debug>::fmt
65 17: _rust_maybe_catch_panic
66 18: test::stats::winsorize
67 19: std::sync::mpsc::blocking::WaitToken::wait_max_until
68 20: std::sys::windows::thread::Thread::new
69 21: BaseThreadInitThunk
70 22: RtlUserThreadStart
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use proc_macro::TokenStream;
76
77 #[test]
78 fn for_loop() {
79 let input = quote!{
80 for x in 0..100 {
81 println!("{}", x);
82 }
83 }.to_string().parse().unwrap();
84
85 let transformed = parallel(TokenStream::empty(), input);
86
87 let output = format!("{}", transformed);
88
89 assert_eq!(output, "");
90 }
91}
92*/