@@ -34,9 +34,11 @@ mod utc_datetime;
34
34
#[ cfg( any( feature = "formatting" , feature = "parsing" ) ) ]
35
35
use std:: iter:: Peekable ;
36
36
37
+ #[ cfg( all( feature = "serde" , any( feature = "formatting" , feature = "parsing" ) ) ) ]
38
+ use proc_macro:: Delimiter ;
37
39
use proc_macro:: TokenStream ;
38
40
#[ cfg( any( feature = "formatting" , feature = "parsing" ) ) ]
39
- use proc_macro:: { Ident , TokenTree } ;
41
+ use proc_macro:: TokenTree ;
40
42
41
43
use self :: error:: Error ;
42
44
@@ -60,34 +62,38 @@ macro_rules! impl_macros {
60
62
61
63
impl_macros ! [ date datetime utc_datetime offset time] ;
62
64
65
+ #[ cfg( any( feature = "formatting" , feature = "parsing" ) ) ]
66
+ type PeekableTokenStreamIter = Peekable < proc_macro:: token_stream:: IntoIter > ;
67
+
63
68
#[ cfg( any( feature = "formatting" , feature = "parsing" ) ) ]
64
69
enum FormatDescriptionVersion {
65
70
V1 ,
66
71
V2 ,
67
72
}
68
73
69
- #[ cfg( any( feature = "formatting" , feature = "parsing" ) ) ]
70
- enum VersionOrModuleName {
71
- Version ( FormatDescriptionVersion ) ,
72
- #[ cfg_attr( not( feature = "serde" ) , allow( dead_code) ) ]
73
- ModuleName ( Ident ) ,
74
- }
75
-
76
74
#[ cfg( any( feature = "formatting" , feature = "parsing" ) ) ]
77
75
fn parse_format_description_version < const NO_EQUALS_IS_MOD_NAME : bool > (
78
- iter : & mut Peekable < proc_macro:: token_stream:: IntoIter > ,
79
- ) -> Result < Option < VersionOrModuleName > , Error > {
80
- let version_ident = match iter. peek ( ) {
81
- Some ( TokenTree :: Ident ( ident) ) if ident. to_string ( ) == "version" => match iter. next ( ) {
82
- Some ( TokenTree :: Ident ( ident) ) => ident,
83
- _ => unreachable ! ( ) ,
84
- } ,
76
+ iter : & mut PeekableTokenStreamIter ,
77
+ ) -> Result < Option < FormatDescriptionVersion > , Error > {
78
+ let version_ident = match iter. peek ( ) . ok_or ( Error :: UnexpectedEndOfInput ) ? {
79
+ version @ TokenTree :: Ident ( ident) if ident. to_string ( ) == "version" => {
80
+ let version_ident = version. clone ( ) ;
81
+ iter. next ( ) ; // consume `version`
82
+ version_ident
83
+ }
85
84
_ => return Ok ( None ) ,
86
85
} ;
86
+
87
87
match iter. peek ( ) {
88
88
Some ( TokenTree :: Punct ( punct) ) if punct. as_char ( ) == '=' => iter. next ( ) ,
89
89
_ if NO_EQUALS_IS_MOD_NAME => {
90
- return Ok ( Some ( VersionOrModuleName :: ModuleName ( version_ident) ) ) ;
90
+ // Push the `version` ident to the front of the iterator.
91
+ * iter = std:: iter:: once ( version_ident)
92
+ . chain ( iter. clone ( ) )
93
+ . collect :: < TokenStream > ( )
94
+ . into_iter ( )
95
+ . peekable ( ) ;
96
+ return Ok ( None ) ;
91
97
}
92
98
Some ( token) => {
93
99
return Err ( Error :: Custom {
@@ -134,20 +140,37 @@ fn parse_format_description_version<const NO_EQUALS_IS_MOD_NAME: bool>(
134
140
} ;
135
141
helpers:: consume_punct ( ',' , iter) ?;
136
142
137
- Ok ( Some ( VersionOrModuleName :: Version ( version) ) )
143
+ Ok ( Some ( version) )
144
+ }
145
+
146
+ #[ cfg( all( feature = "serde" , any( feature = "formatting" , feature = "parsing" ) ) ) ]
147
+ fn parse_visibility ( iter : & mut PeekableTokenStreamIter ) -> Result < TokenStream , Error > {
148
+ let mut visibility = match iter. peek ( ) . ok_or ( Error :: UnexpectedEndOfInput ) ? {
149
+ pub_ident @ TokenTree :: Ident ( ident) if ident. to_string ( ) == "pub" => {
150
+ let visibility = quote ! { #( pub_ident. clone( ) ) } ;
151
+ iter. next ( ) ; // consume `pub`
152
+ visibility
153
+ }
154
+ _ => return Ok ( quote ! { } ) ,
155
+ } ;
156
+
157
+ match iter. peek ( ) . ok_or ( Error :: UnexpectedEndOfInput ) ? {
158
+ group @ TokenTree :: Group ( path) if path. delimiter ( ) == Delimiter :: Parenthesis => {
159
+ visibility. extend ( std:: iter:: once ( group. clone ( ) ) ) ;
160
+ iter. next ( ) ; // consume parentheses and path
161
+ }
162
+ _ => { }
163
+ }
164
+
165
+ Ok ( visibility)
138
166
}
139
167
140
168
#[ cfg( any( feature = "formatting" , feature = "parsing" ) ) ]
141
169
#[ proc_macro]
142
170
pub fn format_description ( input : TokenStream ) -> TokenStream {
143
171
( || {
144
172
let mut input = input. into_iter ( ) . peekable ( ) ;
145
- let version = match parse_format_description_version :: < false > ( & mut input) ? {
146
- Some ( VersionOrModuleName :: Version ( version) ) => Some ( version) ,
147
- None => None ,
148
- // This branch should never occur here, as `false` is the provided as a const parameter.
149
- Some ( VersionOrModuleName :: ModuleName ( _) ) => bug ! ( "branch should never occur" ) ,
150
- } ;
173
+ let version = parse_format_description_version :: < false > ( & mut input) ?;
151
174
let ( span, string) = helpers:: get_string_literal ( input) ?;
152
175
let items = format_description:: parse_with_version ( version, & string, span) ?;
153
176
@@ -172,22 +195,16 @@ pub fn serde_format_description(input: TokenStream) -> TokenStream {
172
195
173
196
// First, the optional format description version.
174
197
let version = parse_format_description_version :: < true > ( & mut tokens) ?;
175
- let ( version, mod_name) = match version {
176
- Some ( VersionOrModuleName :: ModuleName ( module_name) ) => ( None , Some ( module_name) ) ,
177
- Some ( VersionOrModuleName :: Version ( version) ) => ( Some ( version) , None ) ,
178
- None => ( None , None ) ,
179
- } ;
198
+
199
+ // Then, the visibility of the module.
200
+ let visibility = parse_visibility ( & mut tokens) ?;
180
201
181
202
// Next, an identifier (the desired module name)
182
- // Only parse this if it wasn't parsed when attempting to get the version.
183
- let mod_name = match mod_name {
184
- Some ( mod_name) => mod_name,
185
- None => match tokens. next ( ) {
186
- Some ( TokenTree :: Ident ( ident) ) => Ok ( ident) ,
187
- Some ( tree) => Err ( Error :: UnexpectedToken { tree } ) ,
188
- None => Err ( Error :: UnexpectedEndOfInput ) ,
189
- } ?,
190
- } ;
203
+ let mod_name = match tokens. next ( ) {
204
+ Some ( TokenTree :: Ident ( ident) ) => Ok ( ident) ,
205
+ Some ( tree) => Err ( Error :: UnexpectedToken { tree } ) ,
206
+ None => Err ( Error :: UnexpectedEndOfInput ) ,
207
+ } ?;
191
208
192
209
// Followed by a comma
193
210
helpers:: consume_punct ( ',' , & mut tokens) ?;
@@ -230,6 +247,7 @@ pub fn serde_format_description(input: TokenStream) -> TokenStream {
230
247
} ;
231
248
232
249
Ok ( serde_format_description:: build (
250
+ visibility,
233
251
mod_name,
234
252
formattable,
235
253
format,
0 commit comments