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