11use proc_macro:: TokenStream ;
22
33use quote:: { quote, ToTokens } ;
4+ use syn:: parse:: { Parse , ParseStream } ;
45use syn:: * ;
56
67#[ proc_macro_derive( NonExhaustivePartialDebug ) ]
@@ -49,13 +50,20 @@ pub fn derive_non_exhaustive(input: TokenStream) -> TokenStream {
4950 TokenStream :: from ( expanded)
5051}
5152
52- #[ proc_macro_derive( TypeInfoPartialDebug ) ]
53- pub fn derive_type_info ( input : TokenStream ) -> TokenStream {
53+ #[ proc_macro_derive( PlaceholderPartialDebug , attributes ( placeholder ) ) ]
54+ pub fn derive_placeholder ( input : TokenStream ) -> TokenStream {
5455 let input = parse_macro_input ! ( input as ItemStruct ) ;
55- let name = input. ident ;
56+ let placeholder = match get_placeholder ( & input) {
57+ Ok ( placeholder) => placeholder,
58+ Err ( err) => {
59+ return err. to_compile_error ( ) . into ( ) ;
60+ }
61+ } ;
62+
63+ let name = & input. ident ;
5664 let ( impl_generics, ty_generics, where_clause) = input. generics . split_for_impl ( ) ;
5765
58- let fields = match input. fields {
66+ let fields = match & input. fields {
5967 Fields :: Named ( FieldsNamed { named, .. } ) => named,
6068 Fields :: Unnamed ( _) => unimplemented ! ( ) ,
6169 Fields :: Unit => unimplemented ! ( ) ,
@@ -66,11 +74,14 @@ pub fn derive_type_info(input: TokenStream) -> TokenStream {
6674 let mut type_name = field. ty . to_token_stream ( ) . to_string ( ) ;
6775 type_name. retain ( |c| !c. is_whitespace ( ) ) ; // remove whitespace
6876
77+ // type name or given placeholder string
78+ let placeholder_string = placeholder. as_ref ( ) . unwrap_or ( & type_name) ;
79+
6980 quote ! {
7081 . field(
7182 stringify!( #name) ,
7283 match :: partialdebug:: AsDebug :: as_debug( & self . #name) {
73- None => & :: partialdebug:: Placeholder ( #type_name ) ,
84+ None => & :: partialdebug:: Placeholder ( #placeholder_string ) ,
7485 Some ( field) => field,
7586 } ,
7687 )
@@ -91,3 +102,35 @@ pub fn derive_type_info(input: TokenStream) -> TokenStream {
91102
92103 TokenStream :: from ( expanded)
93104}
105+
106+ struct Placeholder ( String ) ;
107+
108+ impl Parse for Placeholder {
109+ fn parse ( input : ParseStream ) -> Result < Self > {
110+ input. parse :: < Token ! [ =] > ( ) ?;
111+ Ok ( Placeholder ( input. parse :: < LitStr > ( ) ?. value ( ) ) )
112+ }
113+ }
114+
115+ /// Tries to parse a placeholder string if there is one
116+ fn get_placeholder ( input : & ItemStruct ) -> Result < Option < String > > {
117+ let placeholders: Vec < _ > = input
118+ . attrs
119+ . iter ( )
120+ . filter ( |attribute| attribute. path . is_ident ( "placeholder" ) )
121+ . collect ( ) ;
122+
123+ if placeholders. len ( ) > 1 {
124+ return Err ( Error :: new_spanned (
125+ placeholders[ 1 ] ,
126+ "More than one placeholder attribute" ,
127+ ) ) ;
128+ }
129+
130+ placeholders
131+ . first ( )
132+ . map ( |attribute| {
133+ parse2 :: < Placeholder > ( attribute. tokens . clone ( ) ) . map ( |placeholder| placeholder. 0 )
134+ } )
135+ . transpose ( )
136+ }
0 commit comments