summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Tham <[email protected]>2023-04-09 00:37:40 +0800
committerGitHub <[email protected]>2023-04-09 00:37:40 +0800
commit461e7479de9753fc7e3410450b36b27dd7f2fd5b (patch)
tree54bee658e026289605d7868ea04fde25e8f5167c
parent11037e893c5b0f2d5db3edb074a6b7b21b983be9 (diff)
chore(deps): update syn requirement from 1.0 to 2.0 (#157)
-rw-r--r--monoio-macros/Cargo.toml2
-rw-r--r--monoio-macros/src/entry.rs202
-rw-r--r--monoio/src/lib.rs1
-rw-r--r--rust-toolchain2
4 files changed, 133 insertions, 74 deletions
diff --git a/monoio-macros/Cargo.toml b/monoio-macros/Cargo.toml
index 7cb6091..28c922c 100644
--- a/monoio-macros/Cargo.toml
+++ b/monoio-macros/Cargo.toml
@@ -16,4 +16,4 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1"
-syn = { version = "1.0", features = ["full"] }
+syn = { version = "2.0", features = ["full"] }
diff --git a/monoio-macros/src/entry.rs b/monoio-macros/src/entry.rs
index d481255..bd24ec6 100644
--- a/monoio-macros/src/entry.rs
+++ b/monoio-macros/src/entry.rs
@@ -4,7 +4,12 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{quote, quote_spanned, ToTokens};
+use syn::parse::Parser;
+// syn::AttributeArgs does not implement syn::Parse
+type AttributeArgs = syn::punctuated::Punctuated<syn::Meta, syn::Token![,]>;
+
+#[derive(Clone, Copy)]
struct FinalConfig {
entries: Option<u32>,
timer_enabled: Option<bool>,
@@ -12,6 +17,14 @@ struct FinalConfig {
driver: DriverType,
}
+/// Config used in case of the attribute not being able to build a valid config
+const DEFAULT_ERROR_CONFIG: FinalConfig = FinalConfig {
+ entries: None,
+ timer_enabled: None,
+ threads: None,
+ driver: DriverType::Fusion,
+};
+
struct Configuration {
entries: Option<(u32, Span)>,
timer_enabled: Option<(bool, Span)>,
@@ -146,20 +159,17 @@ fn parse_bool(bool: syn::Lit, span: Span, field: &str) -> Result<bool, syn::Erro
}
}
-fn parse_knobs(
- mut input: syn::ItemFn,
- args: syn::AttributeArgs,
- is_test: bool,
- mut config: Configuration,
-) -> Result<TokenStream, syn::Error> {
- if input.sig.asyncness.take().is_none() {
+fn build_config(input: syn::ItemFn, args: AttributeArgs) -> Result<FinalConfig, syn::Error> {
+ if input.sig.asyncness.is_none() {
let msg = "the `async` keyword is missing from the function declaration";
return Err(syn::Error::new_spanned(input.sig.fn_token, msg));
}
+ let mut config = Configuration::new();
+
for arg in args {
match arg {
- syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue)) => {
+ syn::Meta::NameValue(namevalue) => {
let ident = namevalue
.path
.get_ident()
@@ -168,23 +178,30 @@ fn parse_knobs(
})?
.to_string()
.to_lowercase();
+ let lit = match &namevalue.value {
+ syn::Expr::Lit(syn::ExprLit { lit, .. }) => lit,
+ expr => return Err(syn::Error::new_spanned(expr, "Must be a literal")),
+ };
match ident.as_str() {
- "entries" => config.set_entries(
- namevalue.lit.clone(),
- syn::spanned::Spanned::span(&namevalue.lit),
- )?,
- "timer_enabled" | "enable_timer" | "timer" => config.set_timer_enabled(
- namevalue.lit.clone(),
- syn::spanned::Spanned::span(&namevalue.lit),
- )?,
- "worker_threads" | "workers" | "threads" => config.set_threads(
- namevalue.lit.clone(),
- syn::spanned::Spanned::span(&namevalue.lit),
- )?,
- "driver" => config.set_driver(
- namevalue.lit.clone(),
- syn::spanned::Spanned::span(&namevalue.lit),
- )?,
+ "entries" => {
+ config.set_entries(lit.clone(), syn::spanned::Spanned::span(lit))?
+ }
+ "timer_enabled" | "enable_timer" | "timer" => {
+ config.set_timer_enabled(lit.clone(), syn::spanned::Spanned::span(lit))?
+ }
+ "worker_threads" | "workers" | "threads" => {
+ config.set_threads(lit.clone(), syn::spanned::Spanned::span(lit))?;
+ // Function must return `()` since it will be swallowed.
+ if !matches!(config.threads, None | Some((1, _)))
+ && !matches!(input.sig.output, syn::ReturnType::Default)
+ {
+ return Err(syn::Error::new(
+ syn::spanned::Spanned::span(lit),
+ "With multi-thread function can not have a return value",
+ ));
+ }
+ }
+ "driver" => config.set_driver(lit.clone(), syn::spanned::Spanned::span(lit))?,
name => {
let msg = format!(
"Unknown attribute {name} is specified; expected one of: \
@@ -194,7 +211,7 @@ fn parse_knobs(
}
}
}
- syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
+ syn::Meta::Path(path) => {
let name = path
.get_ident()
.ok_or_else(|| syn::Error::new_spanned(&path, "Must have specified ident"))?
@@ -215,7 +232,11 @@ fn parse_knobs(
}
}
- let config = config.build()?;
+ config.build()
+}
+
+fn parse_knobs(mut input: syn::ItemFn, is_test: bool, config: FinalConfig) -> TokenStream {
+ input.sig.asyncness = None;
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, last_stmt_end_span) = {
@@ -257,7 +278,7 @@ fn parse_knobs(
let body = &input.block;
let brace_token = input.block.brace_token;
let (tail_return, tail_semicolon) = match body.stmts.last() {
- Some(syn::Stmt::Semi(expr, _)) => (
+ Some(syn::Stmt::Expr(expr, Some(_))) => (
match expr {
syn::Expr::Return(_) => quote! { return },
_ => quote! {},
@@ -282,13 +303,8 @@ fn parse_knobs(
})
.expect("Parsing failure");
} else {
- // Function must return `()` since it will be swallowed.
- if !matches!(input.sig.output, syn::ReturnType::Default) {
- return Err(syn::Error::new(
- last_stmt_end_span,
- "With multi-thread function can not have a return value",
- ));
- }
+ // Check covered when building config.
+ debug_assert!(matches!(input.sig.output, syn::ReturnType::Default));
let threads = config.threads.unwrap() - 1;
input.block = syn::parse2(quote_spanned! {last_stmt_end_span=>
@@ -340,69 +356,111 @@ fn parse_knobs(
#cfg_attr
#input
};
- Ok(result.into())
+ result.into()
+}
+
+fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
+ tokens.extend(TokenStream::from(error.into_compile_error()));
+ tokens
}
pub(crate) fn main(args: TokenStream, item: TokenStream) -> TokenStream {
- let input = syn::parse_macro_input!(item as syn::ItemFn);
- let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+ // If any of the steps for this macro fail, we still want to expand to an item that is as close
+ // to the expected output as possible. This helps out IDEs such that completions and other
+ // related features keep working.
+ let input: syn::ItemFn = match syn::parse(item.clone()) {
+ Ok(it) => it,
+ Err(e) => return token_stream_with_error(item, e),
+ };
- if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
+ let config = if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
let msg = "the main function cannot accept arguments";
- return syn::Error::new_spanned(&input.sig.ident, msg)
- .to_compile_error()
- .into();
- }
+ Err(syn::Error::new_spanned(&input.sig.ident, msg))
+ } else {
+ AttributeArgs::parse_terminated
+ .parse(args)
+ .and_then(|args| build_config(input.clone(), args))
+ };
- parse_knobs(input, args, false, Configuration::new())
- .unwrap_or_else(|e| e.to_compile_error().into())
+ match config {
+ Ok(config) => parse_knobs(input, false, config),
+ Err(e) => token_stream_with_error(parse_knobs(input, false, DEFAULT_ERROR_CONFIG), e),
+ }
}
pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
- let input = syn::parse_macro_input!(item as syn::ItemFn);
- let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+ // If any of the steps for this macro fail, we still want to expand to an item that is as close
+ // to the expected output as possible. This helps out IDEs such that completions and other
+ // related features keep working.
+ let input: syn::ItemFn = match syn::parse(item.clone()) {
+ Ok(it) => it,
+ Err(e) => return token_stream_with_error(item, e),
+ };
+ let config = if let Some(attr) = input
+ .attrs
+ .iter()
+ .find(|attr| attr.meta.path().is_ident("test"))
+ {
+ let msg = "second test attribute is supplied";
+ Err(syn::Error::new_spanned(attr, msg))
+ } else {
+ AttributeArgs::parse_terminated
+ .parse(args)
+ .and_then(|args| build_config(input.clone(), args))
+ };
- for attr in &input.attrs {
- if attr.path.is_ident("test") {
- let msg = "second test attribute is supplied";
- return syn::Error::new_spanned(attr, msg).to_compile_error().into();
- }
+ match config {
+ Ok(config) => parse_knobs(input, true, config),
+ Err(e) => token_stream_with_error(parse_knobs(input, true, DEFAULT_ERROR_CONFIG), e),
}
-
- parse_knobs(input, args, true, Configuration::new())
- .unwrap_or_else(|e| e.to_compile_error().into())
}
pub(crate) fn test_all(args: TokenStream, item: TokenStream) -> TokenStream {
- let input = syn::parse_macro_input!(item as syn::ItemFn);
- let args = syn::parse_macro_input!(args as syn::AttributeArgs);
-
- for attr in &input.attrs {
- if attr.path.is_ident("test") {
- let msg = "second test attribute is supplied";
- return syn::Error::new_spanned(attr, msg).to_compile_error().into();
+ // If any of the steps for this macro fail, we still want to expand to an item that is as close
+ // to the expected output as possible. This helps out IDEs such that completions and other
+ // related features keep working.
+ let input: syn::ItemFn = match syn::parse(item.clone()) {
+ Ok(it) => it,
+ Err(e) => return token_stream_with_error(item, e),
+ };
+ let config = if let Some(attr) = input
+ .attrs
+ .iter()
+ .find(|attr| attr.meta.path().is_ident("test"))
+ {
+ let msg = "second test attribute is supplied";
+ Err(syn::Error::new_spanned(attr, msg))
+ } else {
+ AttributeArgs::parse_terminated
+ .parse(args)
+ .and_then(|args| build_config(input.clone(), args))
+ };
+ let mut config = match config {
+ Ok(config) => config,
+ Err(e) => {
+ return token_stream_with_error(parse_knobs(input, true, DEFAULT_ERROR_CONFIG), e)
}
- }
+ };
+
+ let mut output = TokenStream::new();
let mut input_uring = input.clone();
input_uring.sig.ident = proc_macro2::Ident::new(
&format!("uring_{}", input_uring.sig.ident),
input_uring.sig.ident.span(),
);
- let mut config = Configuration::new();
- config.driver = Some((DriverType::Uring, Span::call_site()));
- let mut token_uring = parse_knobs(input_uring, args.clone(), true, config)
- .unwrap_or_else(|e| e.to_compile_error().into());
+ config.driver = DriverType::Uring;
+ let token_uring = parse_knobs(input_uring, true, config);
+ output.extend(token_uring);
let mut input_legacy = input;
input_legacy.sig.ident = proc_macro2::Ident::new(
&format!("legacy_{}", input_legacy.sig.ident),
input_legacy.sig.ident.span(),
);
- let mut config = Configuration::new();
- config.driver = Some((DriverType::Legacy, Span::call_site()));
- let token_legacy = parse_knobs(input_legacy, args, true, config)
- .unwrap_or_else(|e| e.to_compile_error().into());
- token_uring.extend(token_legacy);
- token_uring
+ config.driver = DriverType::Uring;
+ let token_legacy = parse_knobs(input_legacy, true, config);
+ output.extend(token_legacy);
+
+ output
}
diff --git a/monoio/src/lib.rs b/monoio/src/lib.rs
index 760d26a..7e54ce4 100644
--- a/monoio/src/lib.rs
+++ b/monoio/src/lib.rs
@@ -17,6 +17,7 @@
#![feature(stmt_expr_attributes)]
#![feature(unboxed_closures)]
#![feature(once_cell)]
+#![feature(lazy_cell)]
#[macro_use]
pub mod macros;
diff --git a/rust-toolchain b/rust-toolchain
index 07ade69..bf867e0 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-nightly \ No newline at end of file
+nightly