summaryrefslogtreecommitdiffstats
path: root/tokio-macros
diff options
context:
space:
mode:
Diffstat (limited to 'tokio-macros')
-rw-r--r--tokio-macros/Cargo.toml1
-rw-r--r--tokio-macros/src/lib.rs13
-rw-r--r--tokio-macros/src/select.rs43
3 files changed, 55 insertions, 2 deletions
diff --git a/tokio-macros/Cargo.toml b/tokio-macros/Cargo.toml
index d69d48d6..3cc3a3e4 100644
--- a/tokio-macros/Cargo.toml
+++ b/tokio-macros/Cargo.toml
@@ -25,6 +25,7 @@ proc-macro = true
[features]
[dependencies]
+proc-macro2 = "1.0.7"
quote = "1"
syn = { version = "1.0.3", features = ["full"] }
diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs
index 09b8b093..17554470 100644
--- a/tokio-macros/src/lib.rs
+++ b/tokio-macros/src/lib.rs
@@ -14,10 +14,11 @@
//! Macros for use with Tokio
-mod entry;
-
extern crate proc_macro;
+mod entry;
+mod select;
+
use proc_macro::TokenStream;
/// Marks async function to be executed by selected runtime.
@@ -198,3 +199,11 @@ pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
pub fn test_basic(args: TokenStream, item: TokenStream) -> TokenStream {
entry::test(args, item, false)
}
+
+/// Implementation detail of the `select!` macro. This macro is **not** intended
+/// to be used as part of the public API and is permitted to change.
+#[proc_macro]
+#[doc(hidden)]
+pub fn select_priv_declare_output_enum(input: TokenStream) -> TokenStream {
+ select::declare_output_enum(input)
+}
diff --git a/tokio-macros/src/select.rs b/tokio-macros/src/select.rs
new file mode 100644
index 00000000..ddb2e6a0
--- /dev/null
+++ b/tokio-macros/src/select.rs
@@ -0,0 +1,43 @@
+use proc_macro::{TokenStream, TokenTree};
+use proc_macro2::Span;
+use quote::quote;
+use syn::Ident;
+
+pub(crate) fn declare_output_enum(input: TokenStream) -> TokenStream {
+ // passed in is: `(_ _ _)` with one `_` per branch
+ let branches = match input.into_iter().next() {
+ Some(TokenTree::Group(group)) => group.stream().into_iter().count(),
+ _ => panic!("unexpected macro input"),
+ };
+
+ let variants = (0..branches)
+ .map(|num| Ident::new(&format!("_{}", num), Span::call_site()))
+ .collect::<Vec<_>>();
+
+ // Use a bitfield to track which futures completed
+ let mask = Ident::new(
+ if branches <= 8 {
+ "u8"
+ } else if branches <= 16 {
+ "u16"
+ } else if branches <= 32 {
+ "u32"
+ } else if branches <= 64 {
+ "u64"
+ } else {
+ panic!("up to 64 branches supported");
+ },
+ Span::call_site(),
+ );
+
+ TokenStream::from(quote! {
+ pub(super) enum Out<#( #variants ),*> {
+ #( #variants(#variants), )*
+ // Include a `Disabled` variant signifying that all select branches
+ // failed to resolve.
+ Disabled,
+ }
+
+ pub(super) type Mask = #mask;
+ })
+}