From 68a652ed2f51d366bb8033497e6dfe545895410e Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Thu, 23 Jul 2026 08:08:33 +0800 Subject: feat: scaffold crate structure and implement core macros Add the project skeleton, LICENSE files, README, Makefile, doc examples, and the initial implementation of `#[func]`, `invoke!`, and `select!` procedural macros. --- src/invoke.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/invoke.rs (limited to 'src/invoke.rs') diff --git a/src/invoke.rs b/src/invoke.rs new file mode 100644 index 0000000..f7da20a --- /dev/null +++ b/src/invoke.rs @@ -0,0 +1,89 @@ +use crate::SynResult; +use crate::TokenStream2; +use crate::config::default_feature_name; +use proc_macro::TokenStream; +use quote::quote; +use syn::{ + LitStr, Token, + parse::{Parse, ParseStream}, + parse_macro_input, +}; + +#[doc = include_str!("../doc/args/invoke.md")] +pub enum InvokeArgs { + /// invoke!(expr) — feature name defaults to "async" + Default(TokenStream2), + + /// invoke!("feat" => expr) — explicit feature name + Explicit(LitStr, TokenStream2), +} + +impl Parse for InvokeArgs { + fn parse(input: ParseStream) -> SynResult { + if input.peek(LitStr) { + let feat: LitStr = input.parse()?; + input.parse::]>()?; + let expr: TokenStream2 = input.parse()?; + Ok(InvokeArgs::Explicit(feat, expr)) + } else { + let expr: TokenStream2 = input.parse()?; + Ok(InvokeArgs::Default(expr)) + } + } +} + +pub(crate) fn invoke(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as InvokeArgs); + + let expanded = match input { + InvokeArgs::Default(expr) => { + let feat = default_feature_name(); + quote! {{ + #[cfg(feature = #feat)] + { #expr.await } + #[cfg(not(feature = #feat))] + { #expr } + }} + } + InvokeArgs::Explicit(feat, expr) => { + let feat_name = &feat; + quote! {{ + #[cfg(feature = #feat_name)] + { #expr.await } + #[cfg(not(feature = #feat_name))] + { #expr } + }} + } + }; + + TokenStream::from(expanded) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_variant() { + // Input: an expression without feature name → Default variant + let input: proc_macro2::TokenStream = "compute(5)".parse().unwrap(); + let args: InvokeArgs = syn::parse2(input).unwrap(); + match args { + InvokeArgs::Default(_) => {} // expected + _ => panic!("expected Default variant"), + } + } + + #[test] + fn explicit_variant() { + // Input: "my_ft" => expr → Explicit variant with feature "my_ft" + let input: proc_macro2::TokenStream = "\"my_ft\" => compute(5)".parse().unwrap(); + let args: InvokeArgs = syn::parse2(input).unwrap(); + match args { + InvokeArgs::Explicit(feat, _) => { + assert_eq!(feat.value(), "my_ft"); + } + _ => panic!("expected Explicit variant"), + } + } +} -- cgit