11use anyhow:: { bail, Error } ;
22use proc_macro2:: TokenStream ;
33use quote:: quote;
4- use syn:: { Meta } ;
4+ use syn:: { Meta , Lit , MetaNameValue , Path , Expr , ExprLit } ;
55
66use crate :: field:: { set_bool, word_attr} ;
77
88#[ derive( Clone ) ]
9- pub struct Field ;
9+ pub struct Field {
10+ pub default_fn : Option < Path > ,
11+ }
1012
1113impl Field {
1214 pub fn new ( attrs : & [ Meta ] ) -> Result < Option < Field > , Error > {
1315 let mut skip = false ;
16+ let mut default_fn = None ;
1417 let mut unknown_attrs = Vec :: new ( ) ;
1518
1619 for attr in attrs {
1720 if word_attr ( "skip" , attr) {
18- set_bool ( & mut skip, "duplicate ignore attribute" ) ?;
21+ set_bool ( & mut skip, "duplicate skip attribute" ) ?;
22+ } else if let Meta :: NameValue ( MetaNameValue { path, value, .. } ) = attr {
23+ if path. is_ident ( "default" ) {
24+ let lit_str = match value {
25+ // There has to be a better way...
26+ Expr :: Lit ( ExprLit { lit : Lit :: Str ( lit) , .. } ) => Some ( lit) ,
27+ _ => None ,
28+ } ;
29+ if let Some ( lit) = lit_str {
30+ let fn_path: Path = syn:: parse_str ( & lit. value ( ) )
31+ . map_err ( |_| anyhow:: anyhow!( "invalid path for default function" ) ) ?;
32+ if default_fn. is_some ( ) {
33+ bail ! ( "duplicate default attribute for skipped field" ) ;
34+ }
35+ default_fn = Some ( fn_path) ;
36+ } else {
37+ bail ! ( "default attribute value must be a string literal" ) ;
38+ }
39+ } else {
40+ unknown_attrs. push ( attr) ;
41+ }
1942 } else {
2043 unknown_attrs. push ( attr) ;
2144 }
@@ -27,30 +50,24 @@ impl Field {
2750
2851 if !unknown_attrs. is_empty ( ) {
2952 bail ! (
30- "unknown attribute(s) for ignored field: #[prost({})]" ,
53+ "unknown attribute(s) for skipped field: #[prost({})]" ,
3154 quote!( #( #unknown_attrs) , * )
3255 ) ;
3356 }
3457
35- Ok ( Some ( Field ) )
58+ Ok ( Some ( Field { default_fn } ) )
3659 }
3760
38- /// Returns a statement which non-ops, since the field is ignored.
39- pub fn encode ( & self , _: TokenStream ) -> TokenStream {
40- quote ! ( )
41- }
42-
43- /// Returns an expression which evaluates to the default value of the ignored field.
44- pub fn merge ( & self , ident : TokenStream ) -> TokenStream {
45- quote ! ( #ident. get_or_insert_with( :: core:: default :: Default :: default ) )
46- }
47-
48- /// Returns an expression which evaluates to 0
49- pub fn encoded_len ( & self , _: TokenStream ) -> TokenStream {
50- quote ! ( 0 )
61+ pub fn clear ( & self , ident : TokenStream ) -> TokenStream {
62+ let default = self . default_value ( ) ;
63+ quote ! ( #ident = #default ; )
5164 }
5265
53- pub fn clear ( & self , ident : TokenStream ) -> TokenStream {
54- quote ! ( #ident = :: core:: default :: Default :: default )
66+ pub fn default_value ( & self ) -> TokenStream {
67+ if let Some ( ref path) = self . default_fn {
68+ quote ! { #path( ) }
69+ } else {
70+ quote ! { :: core:: default :: Default :: default ( ) }
71+ }
5572 }
5673}
0 commit comments