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/func.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/func.rs (limited to 'src/func.rs') diff --git a/src/func.rs b/src/func.rs new file mode 100644 index 0000000..5557992 --- /dev/null +++ b/src/func.rs @@ -0,0 +1,81 @@ +use crate::SynResult; +use crate::config::default_feature_name; +use proc_macro::TokenStream; +use quote::quote; +use syn::{ + ItemFn, LitStr, + parse::{Parse, ParseStream}, + parse_macro_input, +}; + +#[doc = include_str!("../doc/args/func.md")] +pub struct FuncArgs { + pub feature_name: String, +} + +impl Default for FuncArgs { + fn default() -> Self { + FuncArgs { + feature_name: default_feature_name().to_string(), + } + } +} + +impl Parse for FuncArgs { + fn parse(input: ParseStream) -> SynResult { + if input.is_empty() { + return Ok(FuncArgs::default()); + } + + // Parse: "feature_name" + let feat_lit: LitStr = input.parse()?; + let feature_name = feat_lit.value(); + + Ok(FuncArgs { feature_name }) + } +} + +pub(crate) fn func(attr: TokenStream, item: TokenStream) -> TokenStream { + let args = parse_macro_input!(attr as FuncArgs); + let feature_name = &args.feature_name; + + let input_fn = parse_macro_input!(item as ItemFn); + let attrs = &input_fn.attrs; + let vis = &input_fn.vis; + let sig = &input_fn.sig; + let block = &input_fn.block; + + let expanded = quote! { + #(#attrs)* + #[cfg(not(feature = #feature_name))] + #vis #sig #block + + #(#attrs)* + #[cfg(feature = #feature_name)] + #vis async #sig #block + }; + + TokenStream::from(expanded) +} + +/// Test module for `FuncArgs` parsing. +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn empty_input_defaults_to_async() { + // Input: empty → defaults to "foo_async" + let input = proc_macro2::TokenStream::new(); + let args: FuncArgs = syn::parse2(input).unwrap(); + assert_eq!(args.feature_name, "foo_async"); + } + + #[test] + fn custom_feature_name_parsed() { + // Input: "custom_name" + let input: proc_macro2::TokenStream = "\"custom_name\"".parse().unwrap(); + let args: FuncArgs = syn::parse2(input).unwrap(); + assert_eq!(args.feature_name, "custom_name"); + } +} -- cgit