@@ -9,7 +9,8 @@ use nom::{
99#[ derive( Clone , Default , Debug , PartialEq ) ]
1010pub struct RuleMetadata {
1111 pub name : Option < String > ,
12- pub is_newtype : bool ,
12+ /// None = not newtype, Some(Some) = generate getter, Some(None) = no getter
13+ pub newtype : Option < Option < String > > ,
1314 pub no_alias : bool ,
1415 pub used_as_key : bool ,
1516 pub custom_json : bool ,
@@ -18,56 +19,46 @@ pub struct RuleMetadata {
1819 pub comment : Option < String > ,
1920}
2021
21- pub fn merge_metadata ( r1 : & RuleMetadata , r2 : & RuleMetadata ) -> RuleMetadata {
22- let merged = RuleMetadata {
23- name : match ( r1. name . as_ref ( ) , r2. name . as_ref ( ) ) {
24- ( Some ( val1) , Some ( val2) ) => {
25- panic ! ( "Key \" name\" specified twice: {:?} {:?}" , val1, val2)
26- }
27- ( val @ Some ( _) , _) => val. cloned ( ) ,
28- ( _, val) => val. cloned ( ) ,
29- } ,
30- is_newtype : r1. is_newtype || r2. is_newtype ,
31- no_alias : r1. no_alias || r2. no_alias ,
32- used_as_key : r1. used_as_key || r2. used_as_key ,
33- custom_json : r1. custom_json || r2. custom_json ,
34- custom_serialize : match ( r1. custom_serialize . as_ref ( ) , r2. custom_serialize . as_ref ( ) ) {
22+ macro_rules! merge_metadata_fields {
23+ ( $lhs: expr, $rhs: expr, $field_name: literal) => {
24+ match ( $lhs. as_ref( ) , $rhs. as_ref( ) ) {
3525 ( Some ( val1) , Some ( val2) ) => {
3626 panic!(
37- "Key \" custom_serialize \" specified twice: {:?} {:?}" ,
27+ concat! ( "Key \" " , $field_name , " \" specified twice: {:?} {:?}") ,
3828 val1, val2
3929 )
4030 }
4131 ( val @ Some ( _) , _) => val. cloned( ) ,
4232 ( _, val) => val. cloned( ) ,
43- } ,
44- custom_deserialize : match (
45- r1. custom_deserialize . as_ref ( ) ,
46- r2. custom_deserialize . as_ref ( ) ,
47- ) {
48- ( Some ( val1) , Some ( val2) ) => {
49- panic ! (
50- "Key \" custom_deserialize\" specified twice: {:?} {:?}" ,
51- val1, val2
52- )
53- }
54- ( val @ Some ( _) , _) => val. cloned ( ) ,
55- ( _, val) => val. cloned ( ) ,
56- } ,
57- comment : match ( r1. comment . as_ref ( ) , r2. comment . as_ref ( ) ) {
58- ( Some ( val1) , Some ( val2) ) => {
59- panic ! ( "Key \" comment\" specified twice: {:?} {:?}" , val1, val2)
60- }
61- ( val @ Some ( _) , _) => val. cloned ( ) ,
62- ( _, val) => val. cloned ( ) ,
63- } ,
33+ }
34+ } ;
35+ }
36+
37+ pub fn merge_metadata ( r1 : & RuleMetadata , r2 : & RuleMetadata ) -> RuleMetadata {
38+ let merged = RuleMetadata {
39+ name : merge_metadata_fields ! ( r1. name, r2. name, "name" ) ,
40+ newtype : merge_metadata_fields ! ( r1. newtype, r2. newtype, "newtype" ) ,
41+ no_alias : r1. no_alias || r2. no_alias ,
42+ used_as_key : r1. used_as_key || r2. used_as_key ,
43+ custom_json : r1. custom_json || r2. custom_json ,
44+ custom_serialize : merge_metadata_fields ! (
45+ r1. custom_serialize,
46+ r2. custom_serialize,
47+ "custom_serialize"
48+ ) ,
49+ custom_deserialize : merge_metadata_fields ! (
50+ r1. custom_deserialize,
51+ r2. custom_deserialize,
52+ "custom_deserialize"
53+ ) ,
54+ comment : merge_metadata_fields ! ( r1. comment, r2. comment, "comment" ) ,
6455 } ;
6556 merged. verify ( ) ;
6657 merged
6758}
6859
6960enum ParseResult {
70- NewType ,
61+ NewType ( Option < String > ) ,
7162 Name ( String ) ,
7263 DontGenAlias ,
7364 UsedAsKey ,
@@ -77,21 +68,30 @@ enum ParseResult {
7768 Comment ( String ) ,
7869}
7970
71+ macro_rules! merge_parse_fields {
72+ ( $base: expr, $new: expr, $field_name: literal) => {
73+ match $base. as_ref( ) {
74+ Some ( old) => {
75+ panic!(
76+ concat!( "Key \" " , $field_name, "\" specified twice: {:?} {:?}" ) ,
77+ old, $new
78+ )
79+ }
80+ None => {
81+ $base = Some ( $new. to_owned( ) ) ;
82+ }
83+ }
84+ } ;
85+ }
86+
8087impl RuleMetadata {
8188 fn from_parse_results ( results : & [ ParseResult ] ) -> RuleMetadata {
8289 let mut base = RuleMetadata :: default ( ) ;
8390 for result in results {
8491 match result {
85- ParseResult :: Name ( name) => match base. name . as_ref ( ) {
86- Some ( old_name) => {
87- panic ! ( "Key \" name\" specified twice: {:?} {:?}" , old_name, name)
88- }
89- None => {
90- base. name = Some ( name. to_string ( ) ) ;
91- }
92- } ,
93- ParseResult :: NewType => {
94- base. is_newtype = true ;
92+ ParseResult :: Name ( name) => merge_parse_fields ! ( base. name, name, "name" ) ,
93+ ParseResult :: NewType ( newtype) => {
94+ merge_parse_fields ! ( base. newtype, newtype, "newtype" )
9595 }
9696 ParseResult :: DontGenAlias => {
9797 base. no_alias = true ;
@@ -104,47 +104,24 @@ impl RuleMetadata {
104104 base. custom_json = true ;
105105 }
106106 ParseResult :: CustomSerialize ( custom_serialize) => {
107- match base. custom_serialize . as_ref ( ) {
108- Some ( old) => {
109- panic ! (
110- "Key \" custom_serialize\" specified twice: {:?} {:?}" ,
111- old, custom_serialize
112- )
113- }
114- None => {
115- base. custom_serialize = Some ( custom_serialize. to_string ( ) ) ;
116- }
117- }
107+ merge_parse_fields ! ( base. custom_serialize, custom_serialize, "custom_serialize" )
118108 }
119- ParseResult :: CustomDeserialize ( custom_deserialize) => {
120- match base. custom_deserialize . as_ref ( ) {
121- Some ( old) => {
122- panic ! (
123- "Key \" custom_deserialize\" specified twice: {:?} {:?}" ,
124- old, custom_deserialize
125- )
126- }
127- None => {
128- base. custom_deserialize = Some ( custom_deserialize. to_string ( ) ) ;
129- }
130- }
109+ ParseResult :: CustomDeserialize ( custom_deserialize) => merge_parse_fields ! (
110+ base. custom_deserialize,
111+ custom_deserialize,
112+ "custom_deserialize"
113+ ) ,
114+ ParseResult :: Comment ( comment) => {
115+ merge_parse_fields ! ( base. comment, comment, "comment" )
131116 }
132- ParseResult :: Comment ( comment) => match base. comment . as_ref ( ) {
133- Some ( old) => {
134- panic ! ( "Key \" comment\" specified twice: {:?} {:?}" , old, comment)
135- }
136- None => {
137- base. comment = Some ( comment. to_string ( ) ) ;
138- }
139- } ,
140117 }
141118 }
142119 base. verify ( ) ;
143120 base
144121 }
145122
146123 fn verify ( & self ) {
147- if self . is_newtype && self . no_alias {
124+ if self . newtype . is_some ( ) && self . no_alias {
148125 // this would make no sense anyway as with newtype we're already not making an alias
149126 panic ! ( "cannot use both @newtype and @no_alias on the same alias" ) ;
150127 }
@@ -161,8 +138,16 @@ fn tag_name(input: &str) -> IResult<&str, ParseResult> {
161138
162139fn tag_newtype ( input : & str ) -> IResult < & str , ParseResult > {
163140 let ( input, _) = tag ( "@newtype" ) ( input) ?;
164-
165- Ok ( ( input, ParseResult :: NewType ) )
141+ // to get around type annotations
142+ fn parse_newtype ( input : & str ) -> IResult < & str , ParseResult > {
143+ let ( input, _) = take_while ( char:: is_whitespace) ( input) ?;
144+ let ( input, getter) = take_while1 ( |ch| !char:: is_whitespace ( ch) && ch != '@' ) ( input) ?;
145+ Ok ( ( input, ParseResult :: NewType ( Some ( getter. trim ( ) . to_owned ( ) ) ) ) )
146+ }
147+ match parse_newtype ( input) {
148+ Ok ( ret) => Ok ( ret) ,
149+ Err ( _) => Ok ( ( input. trim_start ( ) , ParseResult :: NewType ( None ) ) ) ,
150+ }
166151}
167152
168153fn tag_no_alias ( input : & str ) -> IResult < & str , ParseResult > {
@@ -261,7 +246,7 @@ fn parse_comment_name() {
261246 "" ,
262247 RuleMetadata {
263248 name: Some ( "foo" . to_string( ) ) ,
264- is_newtype : false ,
249+ newtype : None ,
265250 no_alias: false ,
266251 used_as_key: false ,
267252 custom_json: false ,
@@ -281,7 +266,7 @@ fn parse_comment_newtype() {
281266 "" ,
282267 RuleMetadata {
283268 name: None ,
284- is_newtype : true ,
269+ newtype : Some ( None ) ,
285270 no_alias: false ,
286271 used_as_key: false ,
287272 custom_json: false ,
@@ -293,6 +278,46 @@ fn parse_comment_newtype() {
293278 ) ;
294279}
295280
281+ #[ test]
282+ fn parse_comment_newtype_getter_before ( ) {
283+ assert_eq ! (
284+ rule_metadata( "@newtype custom_getter @used_as_key" ) ,
285+ Ok ( (
286+ "" ,
287+ RuleMetadata {
288+ name: None ,
289+ newtype: Some ( Some ( "custom_getter" . to_owned( ) ) ) ,
290+ no_alias: false ,
291+ used_as_key: true ,
292+ custom_json: false ,
293+ custom_serialize: None ,
294+ custom_deserialize: None ,
295+ comment: None ,
296+ }
297+ ) )
298+ ) ;
299+ }
300+
301+ #[ test]
302+ fn parse_comment_newtype_getter_after ( ) {
303+ assert_eq ! (
304+ rule_metadata( "@used_as_key @newtype custom_getter" ) ,
305+ Ok ( (
306+ "" ,
307+ RuleMetadata {
308+ name: None ,
309+ newtype: Some ( Some ( "custom_getter" . to_owned( ) ) ) ,
310+ no_alias: false ,
311+ used_as_key: true ,
312+ custom_json: false ,
313+ custom_serialize: None ,
314+ custom_deserialize: None ,
315+ comment: None ,
316+ }
317+ ) )
318+ ) ;
319+ }
320+
296321#[ test]
297322fn parse_comment_newtype_and_name ( ) {
298323 assert_eq ! (
@@ -301,7 +326,7 @@ fn parse_comment_newtype_and_name() {
301326 "" ,
302327 RuleMetadata {
303328 name: Some ( "foo" . to_string( ) ) ,
304- is_newtype : true ,
329+ newtype : Some ( None ) ,
305330 no_alias: false ,
306331 used_as_key: false ,
307332 custom_json: false ,
@@ -321,7 +346,7 @@ fn parse_comment_newtype_and_name_and_used_as_key() {
321346 "" ,
322347 RuleMetadata {
323348 name: Some ( "foo" . to_string( ) ) ,
324- is_newtype : true ,
349+ newtype : Some ( None ) ,
325350 no_alias: false ,
326351 used_as_key: true ,
327352 custom_json: false ,
@@ -341,7 +366,7 @@ fn parse_comment_used_as_key() {
341366 "" ,
342367 RuleMetadata {
343368 name: None ,
344- is_newtype : false ,
369+ newtype : None ,
345370 no_alias: false ,
346371 used_as_key: true ,
347372 custom_json: false ,
@@ -361,7 +386,7 @@ fn parse_comment_newtype_and_name_inverse() {
361386 "" ,
362387 RuleMetadata {
363388 name: Some ( "foo" . to_string( ) ) ,
364- is_newtype : true ,
389+ newtype : Some ( None ) ,
365390 no_alias: false ,
366391 used_as_key: false ,
367392 custom_json: false ,
@@ -381,7 +406,7 @@ fn parse_comment_name_noalias() {
381406 "" ,
382407 RuleMetadata {
383408 name: Some ( "foo" . to_string( ) ) ,
384- is_newtype : false ,
409+ newtype : None ,
385410 no_alias: true ,
386411 used_as_key: false ,
387412 custom_json: false ,
@@ -401,7 +426,7 @@ fn parse_comment_newtype_and_custom_json() {
401426 "" ,
402427 RuleMetadata {
403428 name: None ,
404- is_newtype : true ,
429+ newtype : Some ( None ) ,
405430 no_alias: false ,
406431 used_as_key: false ,
407432 custom_json: true ,
@@ -427,7 +452,7 @@ fn parse_comment_custom_serialize_deserialize() {
427452 "" ,
428453 RuleMetadata {
429454 name: None ,
430- is_newtype : false ,
455+ newtype : None ,
431456 no_alias: false ,
432457 used_as_key: false ,
433458 custom_json: false ,
@@ -448,7 +473,7 @@ fn parse_comment_all_except_no_alias() {
448473 "" ,
449474 RuleMetadata {
450475 name: Some ( "baz" . to_string( ) ) ,
451- is_newtype : true ,
476+ newtype : Some ( None ) ,
452477 no_alias: false ,
453478 used_as_key: true ,
454479 custom_json: true ,
0 commit comments