From dddef6a84f8923c455ee30ae8d700cc2f84bcc05 Mon Sep 17 00:00:00 2001 From: AlseinX Date: Thu, 30 Nov 2023 14:20:45 +0800 Subject: [PATCH] feat: make arg by ref & add arg support for mapper --- macros/src/exprs/fn.rs | 134 ++++++++++++++++++++++++++++++++--------- macros/src/parser.rs | 24 +++----- src/json.rs | 2 +- src/ops.rs | 122 +++++++++++++++++++++++-------------- src/parse.rs | 12 ++-- 5 files changed, 197 insertions(+), 97 deletions(-) diff --git a/macros/src/exprs/fn.rs b/macros/src/exprs/fn.rs index ace389f..42acf04 100644 --- a/macros/src/exprs/fn.rs +++ b/macros/src/exprs/fn.rs @@ -1,9 +1,9 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{ - spanned::Spanned, token::Paren, Error, FnArg, Generics, Ident, ItemFn, Pat, PatIdent, PatType, - Result, ReturnType, Signature, Token, Type, TypeParam, TypePath, TypeReference, TypeTuple, - Visibility, + punctuated::Pair, spanned::Spanned, token::Paren, Error, FnArg, Generics, Ident, ItemFn, Pat, + PatIdent, PatType, Result, ReturnType, Signature, Token, Type, TypeParam, TypePath, + TypeReference, TypeTuple, Visibility, }; pub fn handle_fn(f: &mut ItemFn, ty_id: &Ident) -> Result { @@ -30,40 +30,70 @@ pub fn handle_fn(f: &mut ItemFn, ty_id: &Ident) -> Result { } } +macro_rules! extract_ref { + ($t:expr) => { + if let Type::Reference(TypeReference { + mutability: None, + elem, + .. + }) = $t + { + elem + } else { + return Err(Error::new($t.span(), "require an immutable reference")); + } + }; +} + fn handle_map( ItemFn { - attrs, - sig: - Signature { - unsafety, - fn_token, - generics: - Generics { - lt_token, - params, - gt_token, - where_clause, - }, - inputs, - output: rtn_ty, - .. - }, - block, - .. - }: &ItemFn, + attrs, sig, block, .. + }: &mut ItemFn, ty_id: &Ident, ) -> Result { + let span = sig.span().resolved_at(Span::mixed_site()); + let Signature { + unsafety, + fn_token, + generics, + inputs, + output: rtn_ty, + .. + } = sig; let mut pt = Vec::with_capacity(inputs.len()); let mut pv = Vec::with_capacity(inputs.len()); + let mut arg = None; - for input in inputs { - let FnArg::Typed(PatType { attrs, pat, ty, .. }) = input else { + while let Some(Pair::Punctuated(input, _) | Pair::End(input)) = inputs.pop() { + let FnArg::Typed(PatType { + mut attrs, pat, ty, .. + }) = input + else { return Err(Error::new( input.span(), "self receievers are not supposed to be here", )); }; + if arg.is_none() { + if let Some(i) = attrs.iter().enumerate().find_map(|(i, a)| { + if let Ok(path) = a.meta.require_path_only() { + if path.is_ident("arg") { + Some(i) + } else { + None + } + } else { + None + } + }) { + attrs.remove(i); + + arg = Some((pat, extract_ref!(*ty))); + continue; + } + } + if let Some(f) = attrs.first() { return Err(Error::new(f.span(), "attributes are not supported here")); } @@ -72,6 +102,45 @@ fn handle_map( pv.push(pat); } + pt.reverse(); + pv.reverse(); + + let (av, a) = if let Some((p, t)) = arg { + (p, *t) + } else { + let ident = Ident::new("__Arg", span); + generics.lt_token = Some(Token![<](span)); + generics.params.push(syn::GenericParam::Type(TypeParam { + attrs: Default::default(), + ident: ident.clone(), + colon_token: None, + bounds: Default::default(), + eq_token: None, + default: None, + })); + generics.gt_token = Some(Token![>](span)); + ( + Box::new(Pat::Ident(PatIdent { + attrs: Default::default(), + by_ref: None, + mutability: None, + ident: Ident::new("_", span), + subpat: None, + })), + Type::Path(TypePath { + qself: None, + path: ident.into(), + }), + ) + }; + + let Generics { + lt_token, + params, + gt_token, + where_clause, + } = generics; + let rtn_ty = if let ReturnType::Type(_, rtn_ty) = rtn_ty { rtn_ty.as_ref().clone() } else { @@ -82,11 +151,11 @@ fn handle_map( }; Ok(quote! { - impl #lt_token #params #gt_token ::xparse::ops::Mapper<(#(#pt,)*)> for #ty_id #where_clause { + impl #lt_token #params #gt_token ::xparse::ops::Mapper<(#(#pt,)*), #a> for #ty_id #where_clause { type Output = #rtn_ty; #(#attrs)* #[inline] - #unsafety #fn_token map((#(#pv,)*): (#(#pt,)*)) -> Self::Output #block + #unsafety #fn_token map((#(#pv,)*): (#(#pt,)*), #av: &#a) -> Self::Output #block } }) } @@ -105,7 +174,7 @@ fn handle_is(f: &mut ItemFn, ty_id: &Ident) -> Result { } let a = if let Some(FnArg::Typed(PatType { ty: i, .. })) = inputs.iter().nth(1) { - i + extract_ref!(i.as_ref()) } else { let ident = Ident::new("__Arg", span); generics.lt_token = Some(Token![<](span)); @@ -128,9 +197,14 @@ fn handle_is(f: &mut ItemFn, ty_id: &Ident) -> Result { subpat: None, })), colon_token: Token![:](span), - ty: Box::new(Type::Path(TypePath { - qself: None, - path: ident.into(), + ty: Box::new(Type::Reference(TypeReference { + and_token: Token![&](span), + lifetime: None, + mutability: None, + elem: Box::new(Type::Path(TypePath { + qself: None, + path: ident.into(), + })), })), })); let Some(FnArg::Typed(PatType { ty, .. })) = inputs.iter().nth(1) else { diff --git a/macros/src/parser.rs b/macros/src/parser.rs index d8fb2b4..4c944de 100644 --- a/macros/src/parser.rs +++ b/macros/src/parser.rs @@ -156,12 +156,7 @@ pub fn handle( attrs: Default::default(), ident: arg, colon_token: Some(Token![:](span)), - bounds: Punctuated::from_iter([TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: TraitBoundModifier::None, - lifetimes: None, - path: Ident::new("Clone", span).into(), - })]), + bounds: Default::default(), eq_token: Default::default(), default: Default::default(), })); @@ -205,7 +200,7 @@ pub fn handle( let f = quote! { #[inline(always)] - fn parse<#s: ::xparse::Source>(input: &mut #s, arg: #arg) -> Result { + fn parse<#s: ::xparse::Source>(input: &mut #s, arg: &#arg) -> Result { <#ty as ::xparse::parse::ParseImpl<#input, #arg>>::parse(input, arg) } }; @@ -214,7 +209,7 @@ pub fn handle( let f = quote! { #f #[inline(always)] - async fn parse_async>(input: &mut S, arg: #arg) -> Result { + async fn parse_async>(input: &mut S, arg: &#arg) -> Result { Box::pin(<#ty as ::xparse::parse::ParseImpl<#input, #arg>>::parse_async(input, arg)).await } }; @@ -226,24 +221,25 @@ pub fn handle( type Output = #output; #f } + impl<#i, #a> ::xparse::ops::Predicate<#i, #a> for #ident where #ty: ::xparse::ops::Predicate<#i, #a> { #[inline(always)] - fn is(v: &#i, arg: #a) -> bool { + fn is(v: &#i, arg: &#a) -> bool { <#ty as ::xparse::ops::Predicate<#i, #a>>::is(v, arg) } } - impl<#i> ::xparse::ops::Mapper<#i> for #ident + impl<#i, #a> ::xparse::ops::Mapper<#i, #a> for #ident where - #ty: ::xparse::ops::Mapper<#i> + #ty: ::xparse::ops::Mapper<#i, #a> { - type Output = <#ty as ::xparse::ops::Mapper<#i>>::Output; + type Output = <#ty as ::xparse::ops::Mapper<#i, #a>>::Output; #[inline(always)] - fn map(v: #i) -> Self::Output { - <#ty as ::xparse::ops::Mapper<#i>>::map(v) + fn map(v: #i, a: &#a) -> Self::Output { + <#ty as ::xparse::ops::Mapper<#i, #a>>::map(v, a) } } }) diff --git a/src/json.rs b/src/json.rs index 0a871ad..539373f 100644 --- a/src/json.rs +++ b/src/json.rs @@ -129,7 +129,7 @@ type Object = Map< Map< And, PValue>, { - fn map(k: String, v: Value) -> (String, Value) { + fn map(k: K, v: V) -> (K, V) { (k, v) } }, diff --git a/src/ops.rs b/src/ops.rs index a225500..96a6952 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -3,7 +3,7 @@ use crate::{ Concat, Error, HardError, Result, SourceBase, }; use alloc::vec::Vec; -use core::{borrow::Borrow, marker::PhantomData}; +use core::{borrow::Borrow, marker::PhantomData, ops::Range}; pub trait Const { type Type; @@ -11,27 +11,27 @@ pub trait Const { } pub trait Predicate { - fn is(v: &T, a: A) -> bool; + fn is(v: &T, a: &A) -> bool; } -pub trait Mapper { +pub trait Mapper { type Output; - fn map(v: T) -> Self::Output; + fn map(v: T, a: &A) -> Self::Output; } pub struct Define(PhantomData); -impl> Mapper for Define { +impl, A> Mapper for Define { type Output = U::Output; #[inline(always)] - fn map(v: T) -> Self::Output { - U::map(v) + fn map(v: T, a: &A) -> Self::Output { + U::map(v, a) } } impl, A> Predicate for Define { #[inline(always)] - fn is(v: &T, arg: A) -> bool { + fn is(v: &T, arg: &A) -> bool { U::is(v, arg) } } @@ -45,7 +45,7 @@ impl, A> ParseImpl for Define { type Output = U::Output; #[inline(always)] - fn parse>(input: &mut S, arg: A) -> Result { + fn parse>(input: &mut S, arg: &A) -> Result { U::parse(input, arg) } @@ -53,7 +53,7 @@ impl, A> ParseImpl for Define { #[inline(always)] async fn parse_async>( input: &mut S, - arg: A, + arg: &A, ) -> Result { U::parse_async(input, arg).await } @@ -78,7 +78,7 @@ impl, A> ParseImpl for Is

{ impl, A> Predicate for Is

{ #[inline(always)] - fn is(v: &I, arg: A) -> bool { + fn is(v: &I, arg: &A) -> bool { P::is(v, arg) } } @@ -89,7 +89,7 @@ pub struct Not(PhantomData); impl, A> Predicate for Not { #[inline(always)] - fn is(v: &I, arg: A) -> bool { + fn is(v: &I, arg: &A) -> bool { !T::is(v, arg) } } @@ -130,7 +130,7 @@ impl, G: IntoIterator, T: Borrow, U: PartialEq, for AnyOf { #[inline(always)] - fn is(v: &U, _: A) -> bool { + fn is(v: &U, _: &A) -> bool { C::VALUE.into_iter().any(|x| v == x.borrow()) } } @@ -142,7 +142,7 @@ impl, G: IntoIterator, T: Borrow, U: PartialEq + impl_parse!(parse, _await, |input: U, _arg: A| parse!( Is::, input, - () + &() )); } @@ -188,10 +188,10 @@ impl ParseImpl for NoOp { impl_parse!(parse, _await, |__: I, _arg: A| Ok(T::default())); } -impl Mapper<(T,)> for NoOp { +impl Mapper<(T,), A> for NoOp { type Output = T; #[inline(always)] - fn map((v,): (T,)) -> Self::Output { + fn map((v,): (T,), _: &A) -> Self::Output { v } } @@ -274,16 +274,16 @@ impl< C13: Concat, C14: Concat, C15, - A: Clone, + A, > ParseImpl for And { type Output = C15; impl_parse!(parse, _await, |input: I, arg: A| { - let r = parse!(T0, input, arg.clone())?; + let r = parse!(T0, input, arg)?; macro_rules! impl_concat { ($r:ident, $($t:ty),*$(,)?) => {$( - let $r = $r.concat(parse!($t, input, arg.clone())?); + let $r = $r.concat(parse!($t, input, arg)?); )*}; } impl_concat!(r, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); @@ -350,7 +350,7 @@ impl< T15: ParseImpl, I, O, - A: Clone, + A, > ParseImpl for Or { type Output = O; @@ -358,7 +358,7 @@ impl< macro_rules! impl_or { ($i:expr, $($t:ty),*$(,)?) => {$( let mut fork = $i.fork(); - match parse!($t, &mut fork, arg.clone()) { + match parse!($t, &mut fork, arg) { Ok(item) => { fork.join(); return Ok(item); @@ -392,15 +392,15 @@ impl< pub struct Repeat(PhantomData); -impl, O, A: Clone, const MIN: usize, const MAX: usize> - ParseImpl for Repeat +impl, O, A, const MIN: usize, const MAX: usize> ParseImpl + for Repeat { type Output = (Vec,); impl_parse!(parse, _await, |input: I, arg: A| { let mut result = Vec::new(); let mut le = None; for _ in 0..MAX { - match parse!(T, input, arg.clone()) { + match parse!(T, input, arg) { Ok((item,)) => result.push(item), Err(e @ Error::Hard(_)) => { return Err(e); @@ -441,7 +441,7 @@ impl< O, P: ParseImpl, PO, - A: Clone, + A, const MIN: usize, const MAX: usize, > ParseImpl for Punctuated @@ -453,7 +453,7 @@ impl< let mut le = None; 'matching: { - match parse!(T, input, arg.clone()) { + match parse!(T, input, arg) { Ok((item,)) => result.push(item), Err(e @ Error::Hard(_)) => { return Err(e); @@ -466,7 +466,7 @@ impl< for _ in 1..MAX { let mut input = input.fork(); - match parse!(P, &mut input, arg.clone()) { + match parse!(P, &mut input, arg) { Ok((item,)) => puncts.push(item), Err(e @ Error::Hard(_)) => { return Err(e); @@ -477,7 +477,7 @@ impl< } } - match parse!(T, &mut input, arg.clone()) { + match parse!(T, &mut input, arg) { Ok((item,)) => { result.push(item); input.join(); @@ -506,31 +506,34 @@ pub struct TryMap(PhantomData<(P, M)>); pub struct IsMap(PhantomData<(P, M)>); -impl, M: Mapper, T, U, A> ParseImpl +impl, M: Mapper, T, U, A> ParseImpl for Map { type Output = (U,); - impl_parse!(parse, _await, |input: I, arg: A| Ok((M::map(parse!( - P, input, arg - )?),))); + impl_parse!(parse, _await, |input: I, arg: A| Ok((M::map( + parse!(P, input, arg)?, + arg + ),))); } -impl, M: Mapper>, T, U, A> ParseImpl - for TryMap +impl, M: Mapper>, T, U, A> + ParseImpl for TryMap { type Output = (U,); - impl_parse!(parse, _await, |input: I, arg: A| Ok((M::map(parse!( - P, input, arg - )?)?,))); + impl_parse!(parse, _await, |input: I, arg: A| Ok((M::map( + parse!(P, input, arg)?, + arg + )?,))); } -impl, M: Mapper>, T, U, A> ParseImpl - for IsMap +impl, M: Mapper>, T, U, A> + ParseImpl for IsMap { type Output = (U,); - impl_parse!(parse, _await, |input: I, arg: A| Ok((M::map(parse!( - P, input, arg - )?) + impl_parse!(parse, _await, |input: I, arg: A| Ok((M::map( + parse!(P, input, arg)?, + arg + ) .ok_or(Error::Mismatch)?,))); } @@ -573,9 +576,12 @@ impl, N: Const, A> ParseImpl fo pub struct ArgOut(PhantomData); -impl, O> ParseImpl for ArgOut { +impl, O> ParseImpl for ArgOut { type Output = (O,); - impl_parse!(parse, _await, |_input: I, arg: A| Ok((M::map((arg,)),))); + impl_parse!(parse, _await, |_input: I, arg: A| Ok((M::map( + (arg.clone(),), + &() + ),))); } #[allow(clippy::type_complexity)] @@ -659,7 +665,7 @@ impl< impl_parse!(parse, _await, |input: I, arg: A0| { macro_rules! impl_chain { ($r:ident,$($t:ty),*$(,)?) => {$( - let ($r,) = parse!($t, input, $r)?; + let ($r,) = parse!($t, input, &$r)?; )*}; } let r = arg; @@ -690,6 +696,30 @@ where impl_parse!(parse, _await, |input: I, arg: A0| { let r = parse!(T0, input, arg)?; - Ok(r.clone().concat(parse!(T1, input, r.0)?)) + Ok(r.clone().concat(parse!(T1, input, &r.0)?)) + }); +} + +pub struct MapRange(PhantomData<(T, M)>); + +impl, M: Mapper>> ParseImpl + for MapRange +{ + type Output = (M::Output,); + impl_parse!(parse, _await, |input: I, arg: A| { + let start = input.position(); + let result = parse!(T, input, arg)?; + let end = input.position(); + Ok((M::map(result, &(start..end)),)) }); } + +pub struct ConcatArg; + +impl, A: Clone> Mapper for ConcatArg { + type Output = T::Output; + #[inline(always)] + fn map(v: T, a: &A) -> Self::Output { + v.concat((a.clone(),)) + } +} diff --git a/src/parse.rs b/src/parse.rs index 5719528..87eaa1b 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -16,12 +16,12 @@ pub trait Parse { pub trait ParseImpl { type Output; - fn parse>(input: &mut S, arg: A) -> Result; + fn parse>(input: &mut S, arg: &A) -> Result; #[cfg(feature = "async")] fn parse_async>( input: &mut S, - arg: A, + arg: &A, ) -> impl Future>; } @@ -32,13 +32,13 @@ where type Output = O; #[inline(always)] fn parse>(input: &mut S) -> Result { - Ok(>::parse(input, ())?.into_item()) + Ok(>::parse(input, &())?.into_item()) } #[cfg(feature = "async")] #[inline(always)] async fn parse_async>(input: &mut S) -> Result { - Ok(>::parse_async(input, ()) + Ok(>::parse_async(input, &()) .await? .into_item()) } @@ -61,7 +61,7 @@ pub(crate) mod macros { macro_rules! impl_parse { ($pa:ident,$aw:ident,|$s:ident:$i:ty,$av:ident:$at:ty|$b:expr) => { #[inline(always)] - fn parse>($s: &mut S, $av: $at) -> Result { + fn parse>($s: &mut S, $av: &$at) -> Result { #[allow(unused_imports)] use $crate::parse::macros::no_await as $aw; #[allow(unused_imports)] @@ -73,7 +73,7 @@ pub(crate) mod macros { #[inline(always)] async fn parse_async>( $s: &mut S, - $av: $at, + $av: &$at, ) -> Result { #[allow(unused_imports)] use $crate::parse::macros::has_await as $aw;