@@ -2,6 +2,8 @@ use crate::format::{self, Format};
22
33use proc_macro2:: { Span , TokenStream } ;
44use syn;
5+ use syn:: { ExprPath , ExprBinary , ExprUnary , Expr } ;
6+ use quote:: ToTokens ;
57
68#[ derive( Debug ) ]
79pub enum Protocol {
@@ -13,6 +15,35 @@ pub enum Protocol {
1315 prefix_subfield_names : Vec < syn:: Ident > ,
1416 } ,
1517 FixedLength ( usize ) ,
18+ SkipIf ( SkipExpression ) ,
19+ }
20+
21+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
22+ pub enum SkipExpression {
23+ PathExp ( ExprPath ) ,
24+ BinaryExp ( ExprBinary ) ,
25+ UnaryExp ( ExprUnary ) ,
26+ }
27+
28+ impl SkipExpression {
29+ pub fn parse_from ( exp : & str ) -> SkipExpression {
30+ let expr = syn:: parse_str :: < Expr > ( exp) . unwrap ( ) ;
31+
32+ match expr {
33+ Expr :: Binary ( e) => SkipExpression :: BinaryExp ( e) ,
34+ Expr :: Unary ( e) => SkipExpression :: UnaryExp ( e) ,
35+ Expr :: Path ( e) => SkipExpression :: PathExp ( e) ,
36+ _ => panic ! ( "Unexpected skip expression" )
37+ }
38+ }
39+
40+ pub fn to_token_stream ( & self ) -> TokenStream {
41+ match self {
42+ SkipExpression :: PathExp ( e) => e. to_token_stream ( ) ,
43+ SkipExpression :: BinaryExp ( e) => e. to_token_stream ( ) ,
44+ SkipExpression :: UnaryExp ( ref e) => e. to_token_stream ( )
45+ }
46+ }
1647}
1748
1849#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
@@ -37,7 +68,7 @@ pub fn repr(attrs: &[syn::Attribute]) -> Option<syn::Ident> {
3768}
3869
3970pub fn protocol ( attrs : & [ syn:: Attribute ] )
40- -> Option < Protocol > {
71+ -> Option < Protocol > {
4172 let meta_list = attrs. iter ( ) . filter_map ( |attr| match attr. parse_meta ( ) {
4273 Ok ( syn:: Meta :: List ( meta_list) ) => {
4374 if meta_list. path . get_ident ( ) == Some ( & syn:: Ident :: new ( "protocol" , proc_macro2:: Span :: call_site ( ) ) ) {
@@ -46,17 +77,31 @@ pub fn protocol(attrs: &[syn::Attribute])
4677 // Unrelated attribute.
4778 None
4879 }
49- } ,
80+ }
5081 _ => None ,
5182 } ) . next ( ) ;
5283
53- let meta_list: syn:: MetaList = if let Some ( meta_list) = meta_list { meta_list } else { return None } ;
84+ let meta_list: syn:: MetaList = if let Some ( meta_list) = meta_list { meta_list } else { return None ; } ;
5485 let mut nested_metas = meta_list. nested . into_iter ( ) ;
5586
5687 match nested_metas. next ( ) {
5788 Some ( syn:: NestedMeta :: Meta ( syn:: Meta :: List ( nested_list) ) ) => {
5889 match & nested_list. path . get_ident ( ) . expect ( "meta is not an ident" ) . to_string ( ) [ ..] {
5990 // #[protocol(length_prefix(<kind>(<prefix field name>)))]
91+ "skip_if" => {
92+ let expression = expect:: meta_list:: single_element ( nested_list) . unwrap ( ) ;
93+ let expression = match expression {
94+ syn:: NestedMeta :: Lit ( syn:: Lit :: Str ( s) ) => {
95+ SkipExpression :: parse_from ( & s. value ( ) )
96+ }
97+ syn:: NestedMeta :: Meta ( syn:: Meta :: Path ( path) ) => {
98+ todo ! ( "Path literal not implemented yet" )
99+ }
100+ _ => panic ! ( "OH no! ! " )
101+ } ;
102+
103+ Some ( Protocol :: SkipIf ( expression) )
104+ }
60105 "fixed_length" => {
61106 let nested_list = expect:: meta_list:: single_literal ( nested_list)
62107 . expect ( "expected a nested list" ) ;
@@ -71,7 +116,7 @@ pub fn protocol(attrs: &[syn::Attribute])
71116 }
72117 "length_prefix" => {
73118 let nested_list = expect:: meta_list:: nested_list ( nested_list)
74- . expect ( "expected a nested list" ) ;
119+ . expect ( "expected a nested list" ) ;
75120 let prefix_kind = match & nested_list. path . get_ident ( ) . expect ( "nested list is not an ident" ) . to_string ( ) [ ..] {
76121 "bytes" => LengthPrefixKind :: Bytes ,
77122 "elements" => LengthPrefixKind :: Elements ,
@@ -82,9 +127,9 @@ pub fn protocol(attrs: &[syn::Attribute])
82127 let ( prefix_field_name, prefix_subfield_names) = match length_prefix_expr {
83128 syn:: NestedMeta :: Lit ( syn:: Lit :: Str ( s) ) => {
84129 let mut parts: Vec < _ > = s. value ( )
85- . split ( "." )
86- . map ( |s| syn:: Ident :: new ( s, Span :: call_site ( ) ) )
87- . collect ( ) ;
130+ . split ( "." )
131+ . map ( |s| syn:: Ident :: new ( s, Span :: call_site ( ) ) )
132+ . collect ( ) ;
88133
89134 if parts. len ( ) < 1 {
90135 panic ! ( "there must be at least one field mentioned" ) ;
@@ -94,7 +139,7 @@ pub fn protocol(attrs: &[syn::Attribute])
94139 let subfield_idents = parts. into_iter ( ) . collect ( ) ;
95140
96141 ( field_ident, subfield_idents)
97- } ,
142+ }
98143 syn:: NestedMeta :: Meta ( syn:: Meta :: Path ( path) ) => match path. get_ident ( ) {
99144 Some ( field_ident) => ( field_ident. clone ( ) , Vec :: new ( ) ) ,
100145 None => panic ! ( "path is not an ident" ) ,
@@ -103,15 +148,15 @@ pub fn protocol(attrs: &[syn::Attribute])
103148 } ;
104149
105150 Some ( Protocol :: LengthPrefix { kind : prefix_kind, prefix_field_name, prefix_subfield_names } )
106- } ,
151+ }
107152 "discriminator" => {
108153 let literal = expect:: meta_list:: single_literal ( nested_list)
109- . expect ( "expected a single literal" ) ;
154+ . expect ( "expected a single literal" ) ;
110155 Some ( Protocol :: Discriminator ( literal) )
111- } ,
156+ }
112157 name => panic ! ( "#[protocol({})] is not valid" , name) ,
113158 }
114- } ,
159+ }
115160 Some ( syn:: NestedMeta :: Meta ( syn:: Meta :: NameValue ( name_value) ) ) => {
116161 match name_value. path . get_ident ( ) {
117162 Some ( ident) => {
@@ -198,3 +243,32 @@ mod attribute {
198243 }
199244}
200245
246+ #[ cfg( test) ]
247+ mod test {
248+ use crate :: attr:: SkipExpression ;
249+
250+ #[ test]
251+ fn should_parse_skip_expression ( ) {
252+ let binary = "a == b" ;
253+ let parse_result = SkipExpression :: parse_from ( binary) ;
254+ assert ! ( matches!( parse_result, SkipExpression :: BinaryExp ( _) ) ) ;
255+
256+ let unary = "!b" ;
257+ let parse_result = SkipExpression :: parse_from ( unary) ;
258+ assert ! ( matches!( parse_result, SkipExpression :: UnaryExp ( _) ) ) ;
259+
260+ let path = "hello" ;
261+ let parse_result = SkipExpression :: parse_from ( path) ;
262+ assert ! ( matches!( parse_result, SkipExpression :: PathExp ( _) ) ) ;
263+ }
264+
265+ #[ test]
266+ fn should_convert_expression_to_token ( ) {
267+ let binary = "a == b" ;
268+ let parse_result = SkipExpression :: parse_from ( binary) ;
269+ let tokens = parse_result. to_token_stream ( ) ;
270+ let expression = quote ! { #tokens } ;
271+ assert_eq ! ( expression. to_string( ) , "a == b" ) ;
272+ }
273+ }
274+
0 commit comments