constant macro arrays
allow function passing
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/lib.rs | 67 |
2 files changed, 41 insertions, 28 deletions
@@ -1,6 +1,6 @@ [package] name = "car" -version = "0.1.2" +version = "0.1.3" authors = ["bend-n <[email protected]>"] description = "std::array::{map, from_fn, try_from_fn} in const" edition = "2021" @@ -57,13 +57,15 @@ pub fn from_fn(input: proc_macro::TokenStream) -> proc_macro::TokenStream { /// [Map](array::map) in const. /// ``` /// assert_eq!(car::map!([1, 2, 3], |x| x * 2), [2, 4, 6]); +/// assert_eq!(car::map!([1, 2, 3], std::convert::identity), [1, 2, 3]); /// ``` #[proc_macro] pub fn map(input: proc_macro::TokenStream) -> proc_macro::TokenStream { struct Args { array: Expr, - f: ExprClosure, + f: Expr, } + impl Parse for Args { fn parse(input: parse::ParseStream) -> Result<Self> { let mut args = Punctuated::<Expr, Token![,]>::parse_terminated(input)?; @@ -73,30 +75,49 @@ pub fn map(input: proc_macro::TokenStream) -> proc_macro::TokenStream { args.len() ))); } - let f = match args.pop().unwrap().into_value() { - Expr::Closure(x) => x, - x => return Err(Error::new_spanned(x, "mismatched types: expected closure")), - }; + let f = args.pop().unwrap().into_value(); let array = args.pop().unwrap().into_value(); Ok(Self { array, f }) } } - let Args { - array, - f: ExprClosure { body, inputs, .. }, - } = parse_macro_input!(input as Args); - let n = inputs.len(); - let ns = inputs.span(); - let mut inputs = inputs.into_iter(); - let Some(binding) = inputs.next() else { - return Error::new(ns, format!("expected one (or 2) inputs, found {n} inputs")) - .into_compile_error() - .into(); - }; - let index = inputs.next().into_iter(); + let Args { array, f } = parse_macro_input!(input as Args); let lib = lib(); + let b = match f { + Expr::Closure(ExprClosure { body, inputs, .. }) => { + let n = inputs.len(); + let ns = inputs.span(); + let mut inputs = inputs.into_iter(); + let Some(binding) = inputs.next() else { + return Error::new(ns, format!("expected one (or 2) inputs, found {n} inputs")) + .into_compile_error() + .into(); + }; + + let index = inputs.next().into_iter(); + quote! { + let i = i; + let #binding = unsafe { __ap.add(i).read() }; + let __out = (); + let __arr = (); + #(let #index = i;)* + + #body + } + } + Expr::Path(e) => quote! { + let i = i; + let __out = (); + let __arr = (); + #e(unsafe { __ap.add(i).read() }) + }, + e => { + return Error::new(e.span(), format!("mismatched types: expected function")) + .into_compile_error() + .into() + } + }; quote! { { #lib @@ -107,15 +128,7 @@ pub fn map(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let __arr = ::core::mem::ManuallyDrop::new(__arr); let mut i = 0usize; while i < size { - __out[i] = ::core::mem::MaybeUninit::new({ - let i = i; - let #binding = unsafe { __ap.add(i).read() }; - let __out = (); - let __arr = (); - #(let #index = i;)* - - #body - }); + __out[i] = ::core::mem::MaybeUninit::new({ #b }); i += 1; } unsafe { aai(__out) } |