1- use std:: collections:: { HashMap , HashSet } ;
2-
1+ use std:: collections:: {
2+ HashMap ,
3+ HashSet ,
4+ } ;
35use litrs:: StringLit ;
46use proc_macro2:: TokenStream ;
5- use quote:: { format_ident, quote, ToTokens } ;
7+ use quote:: {
8+ format_ident,
9+ quote,
10+ ToTokens ,
11+ } ;
612use regex_syntax:: hir:: Hir ;
7- use syn:: { self , parse_macro_input, DataStruct , Ident , Type } ;
13+ use syn:: {
14+ self ,
15+ parse_macro_input,
16+ DataStruct ,
17+ Ident ,
18+ Type ,
19+ } ;
820
921struct Data < ' a > {
1022 captures : Vec < & ' a Hir > ,
@@ -27,49 +39,45 @@ impl<'a> Data<'a> {
2739 panic ! ( "ASSERTION cap len {} but index {}" , self . captures. len( ) , i)
2840 }
2941 self . captures . push ( & g. hir ) ;
30- }
42+ } ,
3143 regex_syntax:: hir:: GroupKind :: CaptureName { name, index } => {
3244 let index = * index as usize - 1 ;
3345 if self . captures . len ( ) != index {
34- panic ! (
35- "ASSERTION cap len {} but index {}" ,
36- self . captures. len( ) ,
37- index
38- )
46+ panic ! ( "ASSERTION cap len {} but index {}" , self . captures. len( ) , index)
3947 }
4048 self . captures . push ( & g. hir ) ;
4149 self . named_captures . insert ( name. clone ( ) , index) ;
42- }
50+ } ,
4351 regex_syntax:: hir:: GroupKind :: NonCapturing => self . walk_re ( & g. hir ) ,
4452 } ,
4553 regex_syntax:: hir:: HirKind :: Concat ( c) => {
4654 for c in c {
4755 self . walk_re ( c) ;
4856 }
49- }
57+ } ,
5058 regex_syntax:: hir:: HirKind :: Alternation ( _) => ( ) ,
5159 }
5260 }
5361
54- fn gen_struct_tuple (
55- & self ,
56- i : & mut usize ,
57- fields : & mut dyn Iterator < Item = & Type > ,
58- ) -> Vec < TokenStream > {
62+ fn gen_struct_tuple ( & self , i : & mut usize , fields : & mut dyn Iterator < Item = & Type > ) -> Vec < TokenStream > {
5963 let mut out = vec ! [ ] ;
6064 for ty in fields {
6165 match ty {
6266 Type :: Tuple ( t) => {
6367 let child = self . gen_struct_tuple ( i, & mut t. elems . iter ( ) ) ;
64- out. push ( quote ! ( ( #( #child) , * ) ) ) ;
65- }
68+ out. push ( quote ! ( ( #( #child) , * ) ) ) ;
69+ } ,
6670 ty => {
67- let err_lit = format ! ( "Failed to parse field {}" , i) ;
71+ let err_lit = format ! ( "Failed to parse field {}: {{}} " , i) ;
6872 * i += 1 ;
6973 out. push (
70- quote ! ( #ty:: from_str( caps_. get( #i) . map( |m| m. as_str( ) ) . unwrap_or( "" ) ) . context( #err_lit) ?) ,
74+ quote ! (
75+ < #ty as std:: str :: FromStr >:: from_str(
76+ caps_. get( #i) . map( |m| m. as_str( ) ) . unwrap_or( "" )
77+ ) . map_err( |e| format!( #err_lit, e) ) ?
78+ ) ,
7179 ) ;
72- }
80+ } ,
7381 }
7482 }
7583 out
@@ -79,12 +87,8 @@ impl<'a> Data<'a> {
7987 match & d. fields {
8088 syn:: Fields :: Named ( n) => {
8189 let mut field_tokens = vec ! [ ] ;
82- let mut keys = self
83- . named_captures
84- . keys ( )
85- . into_iter ( )
86- . map ( & String :: to_string)
87- . collect :: < HashSet < String > > ( ) ;
90+ let mut keys =
91+ self . named_captures . keys ( ) . into_iter ( ) . map ( & String :: to_string) . collect :: < HashSet < String > > ( ) ;
8892 for field in & n. named {
8993 let name = field. ident . as_ref ( ) . unwrap ( ) ;
9094 let i = match self . named_captures . get ( & name. to_string ( ) ) {
@@ -93,10 +97,14 @@ impl<'a> Data<'a> {
9397 } ;
9498 keys. remove ( & name. to_string ( ) ) ;
9599 let ty = & field. ty ;
96- let err_lit = format ! ( "Failed to parse field {}" , name) ;
100+ let err_lit = format ! ( "Failed to parse field {}: {{}} " , name) ;
97101 let i = i + 1 ;
98102 field_tokens. push (
99- quote ! ( #name: #ty:: from_str( caps_. get( #i) . map( |m| m. as_str( ) ) . unwrap_or( "" ) ) . context( #err_lit) ?) ,
103+ quote ! (
104+ #name: < #ty as std:: str :: FromStr >:: from_str(
105+ caps_. get( #i) . map( |m| m. as_str( ) ) . unwrap_or( "" )
106+ ) . map_err( |e| format!( #err_lit, e) ) ?
107+ ) ,
100108 ) ;
101109 }
102110 if !keys. is_empty ( ) {
@@ -106,35 +114,27 @@ impl<'a> Data<'a> {
106114 panic ! ( "This is a struct with named fields but there are some unused unnamed captures" ) ;
107115 }
108116 quote ! ( Ok ( #ident {
109- #( #field_tokens) , *
117+ #( #field_tokens) ,
118+ *
110119 } ) )
111- }
120+ } ,
112121 syn:: Fields :: Unnamed ( u) => {
113122 if !self . named_captures . is_empty ( ) {
114- panic ! (
115- "Tuples must have only unnamed captures, but named captures are present"
116- ) ;
123+ panic ! ( "Tuples must have only unnamed captures, but named captures are present" ) ;
117124 }
118125 let mut i = 0usize ;
119- let field_tokens =
120- self . gen_struct_tuple ( & mut i, & mut u. unnamed . iter ( ) . map ( |e| & e. ty ) ) ;
126+ let field_tokens = self . gen_struct_tuple ( & mut i, & mut u. unnamed . iter ( ) . map ( |e| & e. ty ) ) ;
121127 if i != self . captures . len ( ) {
122- panic ! (
123- "Struct has {} fields but only {} captures" ,
124- u. unnamed. len( ) ,
125- self . captures. len( )
126- ) ;
128+ panic ! ( "Struct has {} fields but only {} captures" , u. unnamed. len( ) , self . captures. len( ) ) ;
127129 }
128- quote ! ( Ok ( #ident (
129- #( #field_tokens) , *
130- ) ) )
131- }
130+ quote ! ( Ok ( #ident( #( #field_tokens) , * ) ) )
131+ } ,
132132 syn:: Fields :: Unit => {
133133 if !self . captures . is_empty ( ) {
134134 panic ! ( "This is an empty struct but regex has captures" )
135135 }
136- quote ! ( Ok ( #ident ( ) ) )
137- }
136+ quote ! ( Ok ( #ident( ) ) )
137+ } ,
138138 }
139139 }
140140}
@@ -160,20 +160,15 @@ fn gen_impls(regex_raw: &str, ast: syn::DeriveInput) -> TokenStream {
160160 let name_parser = format_ident ! ( "{}FromRegex" , name) ;
161161 let mut out = vec ! [ ast. to_token_stream( ) ] ;
162162 #[ cfg( feature = "unicode" ) ]
163- out. push ( quote ! {
163+ out. push ( quote ! {
164164 #vis struct #name_parser( structre:: UnicodeRegex ) ;
165-
166165 impl #name_parser {
167166 #vis fn new( ) -> Self {
168- Self ( structre:: UnicodeRegex :: new( #regex_raw) . unwrap( ) )
167+ Self ( structre:: UnicodeRegex :: new( #regex_raw) . unwrap( ) )
169168 }
170-
171- #vis fn parse( & self , input: & str ) -> structre:: Result <#name> {
172- #[ allow( unused_imports) ]
173- use std:: str :: FromStr ;
174- #[ allow( unused_imports) ]
175- use structre:: Context ;
176- let caps_ = self . 0 . captures( input) . ok_or_else( || structre:: Error :: msg( "No match" ) ) ?;
169+ #vis fn parse( & self , input: & str ) -> Result < #name,
170+ String > {
171+ let caps_ = self . 0 . captures( input) . ok_or_else( || ToString :: to_string( "No match" ) ) ?;
177172 #value
178173 }
179174 }
@@ -182,10 +177,7 @@ fn gen_impls(regex_raw: &str, ast: syn::DeriveInput) -> TokenStream {
182177}
183178
184179#[ proc_macro_attribute]
185- pub fn structre (
186- args : proc_macro:: TokenStream ,
187- body : proc_macro:: TokenStream ,
188- ) -> proc_macro:: TokenStream {
180+ pub fn structre ( args : proc_macro:: TokenStream , body : proc_macro:: TokenStream ) -> proc_macro:: TokenStream {
189181 let mut args = proc_macro2:: TokenStream :: from ( args) . into_iter ( ) ;
190182 let regex_raw = match args. next ( ) . unwrap ( ) {
191183 proc_macro2:: TokenTree :: Literal ( l) => match StringLit :: try_from ( & l) {
@@ -204,9 +196,7 @@ pub fn structre(
204196#[ cfg( test) ]
205197mod tests {
206198 use std:: str:: FromStr ;
207-
208199 use proc_macro2:: TokenStream ;
209-
210200 use crate :: gen_value;
211201 use quote:: quote;
212202
@@ -216,13 +206,16 @@ mod tests {
216206 gen_value(
217207 "(a)" ,
218208 & syn:: parse2( TokenStream :: from_str( "struct Parsed(String);" ) . unwrap( ) ) . unwrap( ) ,
219- )
220- . to_string( ) ,
221- quote!( Ok ( Parsed (
222- String :: from_str( caps_. get( 1usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) )
223- . context( "Failed to parse field 0" ) ?
224- ) ) )
225- . to_string( )
209+ ) . to_string( ) ,
210+ quote!(
211+ Ok (
212+ Parsed (
213+ String :: from_str(
214+ caps_. get( 1usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) ,
215+ ) . context( "Failed to parse field 0" ) ?,
216+ ) ,
217+ )
218+ ) . to_string( )
226219 ) ;
227220 }
228221
@@ -231,17 +224,22 @@ mod tests {
231224 assert_eq ! (
232225 gen_value(
233226 "(a)(b)" ,
234- & syn:: parse2( TokenStream :: from_str( "struct Parsed((String, u32));" ) . unwrap( ) )
235- . unwrap( ) ,
236- )
237- . to_string( ) ,
238- quote!( Ok ( Parsed ( (
239- String :: from_str( caps_. get( 1usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) )
240- . context( "Failed to parse field 0" ) ?,
241- u32 :: from_str( caps_. get( 2usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) )
242- . context( "Failed to parse field 1" ) ?
243- ) ) ) )
244- . to_string( )
227+ & syn:: parse2( TokenStream :: from_str( "struct Parsed((String, u32));" ) . unwrap( ) ) . unwrap( ) ,
228+ ) . to_string( ) ,
229+ quote!(
230+ Ok (
231+ Parsed (
232+ (
233+ String :: from_str(
234+ caps_. get( 1usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) ,
235+ ) . context( "Failed to parse field 0" ) ?,
236+ u32 :: from_str(
237+ caps_. get( 2usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) ,
238+ ) . context( "Failed to parse field 1" ) ?,
239+ ) ,
240+ ) ,
241+ )
242+ ) . to_string( )
245243 ) ;
246244 }
247245
@@ -250,17 +248,16 @@ mod tests {
250248 assert_eq ! (
251249 gen_value(
252250 "(?P<a>a)(?P<b>b)" ,
253- & syn:: parse2( TokenStream :: from_str( "struct Parsed { b: u32, a: String }" ) . unwrap( ) )
254- . unwrap( ) ,
255- )
256- . to_string( ) ,
251+ & syn:: parse2( TokenStream :: from_str( "struct Parsed { b: u32, a: String }" ) . unwrap( ) ) . unwrap( ) ,
252+ ) . to_string( ) ,
257253 quote!( Ok ( Parsed {
258- b: u32 :: from_str( caps_. get( 2usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) )
259- . context( "Failed to parse field b" ) ?,
260- a: String :: from_str( caps_. get( 1usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) )
261- . context( "Failed to parse field a" ) ?
262- } ) )
263- . to_string( )
254+ b: u32 :: from_str(
255+ caps_. get( 2usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) ,
256+ ) . context( "Failed to parse field b" ) ?,
257+ a: String :: from_str(
258+ caps_. get( 1usize ) . map( |m| m. as_str( ) ) . unwrap_or( "" ) ,
259+ ) . context( "Failed to parse field a" ) ?,
260+ } ) ) . to_string( )
264261 ) ;
265262 }
266263}
0 commit comments