1
1
use std:: borrow:: Cow ;
2
2
3
3
use proc_macro2:: { Ident , Span , TokenStream } ;
4
- use proc_macro_error:: { abort, abort_call_site} ;
5
4
use quote:: { quote, quote_spanned, ToTokens } ;
6
5
use syn:: spanned:: Spanned ;
7
6
use syn:: { Attribute , GenericArgument , Path , PathArguments , PathSegment , Type , TypePath } ;
8
7
9
8
use crate :: doc_comment:: CommentAttributes ;
10
9
use crate :: schema_type:: SchemaFormat ;
11
10
use crate :: { schema_type:: SchemaType , Deprecated } ;
11
+ use crate :: { Diagnostics , OptionExt } ;
12
12
13
13
use self :: features:: {
14
14
pop_feature, Feature , FeaturesExt , IsInline , Minimum , Nullable , ToTokensExt , Validatable ,
@@ -104,27 +104,31 @@ pub struct TypeTree<'t> {
104
104
}
105
105
106
106
impl < ' t > TypeTree < ' t > {
107
- pub fn from_type ( ty : & ' t Type ) -> TypeTree < ' t > {
108
- Self :: convert_types ( Self :: get_type_tree_values ( ty) )
109
- . next ( )
110
- . expect ( "TypeTree from type should have one TypeTree parent" )
107
+ pub fn from_type ( ty : & ' t Type ) -> Result < TypeTree < ' t > , Diagnostics > {
108
+ Self :: convert_types ( Self :: get_type_tree_values ( ty) ?) . map ( |mut type_tree| {
109
+ type_tree
110
+ . next ( )
111
+ . expect ( "TypeTree from type should have one TypeTree parent" )
112
+ } )
111
113
}
112
114
113
- fn get_type_tree_values ( ty : & ' t Type ) -> Vec < TypeTreeValue > {
114
- match ty {
115
+ fn get_type_tree_values ( ty : & ' t Type ) -> Result < Vec < TypeTreeValue > , Diagnostics > {
116
+ let type_tree_values = match ty {
115
117
Type :: Path ( path) => {
116
118
vec ! [ TypeTreeValue :: TypePath ( path) ]
117
119
} ,
118
- Type :: Reference ( reference) => Self :: get_type_tree_values ( reference. elem . as_ref ( ) ) ,
120
+ Type :: Reference ( reference) => Self :: get_type_tree_values ( reference. elem . as_ref ( ) ) ? ,
119
121
Type :: Tuple ( tuple) => {
120
122
// Detect unit type ()
121
- if tuple. elems . is_empty ( ) { return vec ! [ TypeTreeValue :: UnitType ] }
122
-
123
- vec ! [ TypeTreeValue :: Tuple ( tuple. elems. iter( ) . flat_map( Self :: get_type_tree_values) . collect( ) , tuple. span( ) ) ]
123
+ if tuple. elems . is_empty ( ) { return Ok ( vec ! [ TypeTreeValue :: UnitType ] ) }
124
+ vec ! [ TypeTreeValue :: Tuple (
125
+ tuple. elems. iter( ) . map( Self :: get_type_tree_values) . collect:: <Result <Vec <_>, Diagnostics >>( ) ?. into_iter( ) . flatten( ) . collect( ) ,
126
+ tuple. span( )
127
+ ) ]
124
128
} ,
125
- Type :: Group ( group) => Self :: get_type_tree_values ( group. elem . as_ref ( ) ) ,
126
- Type :: Slice ( slice) => vec ! [ TypeTreeValue :: Array ( Self :: get_type_tree_values( & slice. elem) , slice. bracket_token. span. join( ) ) ] ,
127
- Type :: Array ( array) => vec ! [ TypeTreeValue :: Array ( Self :: get_type_tree_values( & array. elem) , array. bracket_token. span. join( ) ) ] ,
129
+ Type :: Group ( group) => Self :: get_type_tree_values ( group. elem . as_ref ( ) ) ? ,
130
+ Type :: Slice ( slice) => vec ! [ TypeTreeValue :: Array ( Self :: get_type_tree_values( & slice. elem) ? , slice. bracket_token. span. join( ) ) ] ,
131
+ Type :: Array ( array) => vec ! [ TypeTreeValue :: Array ( Self :: get_type_tree_values( & array. elem) ? , array. bracket_token. span. join( ) ) ] ,
128
132
Type :: TraitObject ( trait_object) => {
129
133
trait_object
130
134
. bounds
@@ -139,68 +143,83 @@ impl<'t> TypeTree<'t> {
139
143
} )
140
144
. map ( |path| vec ! [ TypeTreeValue :: Path ( path) ] ) . unwrap_or_else ( Vec :: new)
141
145
}
142
- _ => abort_call_site ! (
143
- "unexpected type in component part get type path, expected one of: Path, Tuple, Reference, Group, Array, Slice, TraitObject"
144
- ) ,
145
- }
146
+ unexpected => return Err ( Diagnostics :: with_span ( unexpected . span ( ) , "unexpected type in component part get type path, expected one of: Path, Tuple, Reference, Group, Array, Slice, TraitObject" ) ) ,
147
+ } ;
148
+
149
+ Ok ( type_tree_values )
146
150
}
147
151
148
- fn convert_types ( paths : Vec < TypeTreeValue < ' t > > ) -> impl Iterator < Item = TypeTree < ' t > > {
149
- paths. into_iter ( ) . map ( |value| {
150
- let path = match value {
151
- TypeTreeValue :: TypePath ( type_path) => & type_path. path ,
152
- TypeTreeValue :: Path ( path) => path,
153
- TypeTreeValue :: Array ( value, span) => {
154
- let array: Path = Ident :: new ( "Array" , span) . into ( ) ;
155
- return TypeTree {
156
- path : Some ( Cow :: Owned ( array) ) ,
157
- span : Some ( span) ,
158
- value_type : ValueType :: Object ,
159
- generic_type : Some ( GenericType :: Vec ) ,
160
- children : Some ( Self :: convert_types ( value) . collect ( ) ) ,
161
- } ;
162
- }
163
- TypeTreeValue :: Tuple ( tuple, span) => {
164
- return TypeTree {
165
- path : None ,
166
- span : Some ( span) ,
167
- children : Some ( Self :: convert_types ( tuple) . collect ( ) ) ,
168
- generic_type : None ,
169
- value_type : ValueType :: Tuple ,
152
+ fn convert_types (
153
+ paths : Vec < TypeTreeValue < ' t > > ,
154
+ ) -> Result < impl Iterator < Item = TypeTree < ' t > > , Diagnostics > {
155
+ paths
156
+ . into_iter ( )
157
+ . map ( |value| {
158
+ let path = match value {
159
+ TypeTreeValue :: TypePath ( type_path) => & type_path. path ,
160
+ TypeTreeValue :: Path ( path) => path,
161
+ TypeTreeValue :: Array ( value, span) => {
162
+ let array: Path = Ident :: new ( "Array" , span) . into ( ) ;
163
+ return Ok ( TypeTree {
164
+ path : Some ( Cow :: Owned ( array) ) ,
165
+ span : Some ( span) ,
166
+ value_type : ValueType :: Object ,
167
+ generic_type : Some ( GenericType :: Vec ) ,
168
+ children : Some ( match Self :: convert_types ( value) {
169
+ Ok ( converted_values) => converted_values. collect ( ) ,
170
+ Err ( diagnostics) => return Err ( diagnostics) ,
171
+ } ) ,
172
+ } ) ;
170
173
}
171
- }
172
- TypeTreeValue :: UnitType => {
173
- return TypeTree {
174
- path : None ,
175
- span : None ,
176
- value_type : ValueType :: Tuple ,
177
- generic_type : None ,
178
- children : None ,
174
+ TypeTreeValue :: Tuple ( tuple, span) => {
175
+ return Ok ( TypeTree {
176
+ path : None ,
177
+ span : Some ( span) ,
178
+ children : Some ( match Self :: convert_types ( tuple) {
179
+ Ok ( converted_values) => converted_values. collect ( ) ,
180
+ Err ( diagnostics) => return Err ( diagnostics) ,
181
+ } ) ,
182
+ generic_type : None ,
183
+ value_type : ValueType :: Tuple ,
184
+ } )
179
185
}
180
- }
181
- } ;
186
+ TypeTreeValue :: UnitType => {
187
+ return Ok ( TypeTree {
188
+ path : None ,
189
+ span : None ,
190
+ value_type : ValueType :: Tuple ,
191
+ generic_type : None ,
192
+ children : None ,
193
+ } )
194
+ }
195
+ } ;
182
196
183
- // there will always be one segment at least
184
- let last_segment = path
185
- . segments
186
- . last ( )
187
- . expect ( "at least one segment within path in TypeTree::convert_types" ) ;
197
+ // there will always be one segment at least
198
+ let last_segment = path
199
+ . segments
200
+ . last ( )
201
+ . expect ( "at least one segment within path in TypeTree::convert_types" ) ;
188
202
189
- if last_segment. arguments . is_empty ( ) {
190
- Self :: convert ( path, last_segment)
191
- } else {
192
- Self :: resolve_schema_type ( path, last_segment)
193
- }
194
- } )
203
+ if last_segment. arguments . is_empty ( ) {
204
+ Ok ( Self :: convert ( path, last_segment) )
205
+ } else {
206
+ Self :: resolve_schema_type ( path, last_segment)
207
+ }
208
+ } )
209
+ . collect :: < Result < Vec < TypeTree < ' t > > , Diagnostics > > ( )
210
+ . map ( IntoIterator :: into_iter)
195
211
}
196
212
197
213
// Only when type is a generic type we get to this function.
198
- fn resolve_schema_type ( path : & ' t Path , last_segment : & ' t PathSegment ) -> TypeTree < ' t > {
214
+ fn resolve_schema_type (
215
+ path : & ' t Path ,
216
+ last_segment : & ' t PathSegment ,
217
+ ) -> Result < TypeTree < ' t > , Diagnostics > {
199
218
if last_segment. arguments . is_empty ( ) {
200
- abort ! (
201
- last_segment. ident,
202
- "expected at least one angle bracket argument but was 0"
203
- ) ;
219
+ return Err ( Diagnostics :: with_span (
220
+ last_segment. ident . span ( ) ,
221
+ "expected at least one angle bracket argument but was 0" ,
222
+ ) ) ;
204
223
} ;
205
224
206
225
let mut generic_schema_type = Self :: convert ( path, last_segment) ;
@@ -227,26 +246,32 @@ impl<'t> TypeTree<'t> {
227
246
)
228
247
} )
229
248
. map ( |arg| match arg {
230
- GenericArgument :: Type ( arg) => arg,
231
- _ => abort ! (
232
- arg,
233
- "expected generic argument type or generic argument lifetime"
234
- ) ,
235
- } ) ,
249
+ GenericArgument :: Type ( arg) => Ok ( arg) ,
250
+ unexpected => Err ( Diagnostics :: with_span (
251
+ unexpected. span ( ) ,
252
+ "expected generic argument type or generic argument lifetime" ,
253
+ ) ) ,
254
+ } )
255
+ . collect :: < Result < Vec < _ > , Diagnostics > > ( ) ?
256
+ . into_iter ( ) ,
236
257
)
237
258
}
238
259
}
239
- _ => abort ! (
240
- last_segment. ident,
241
- "unexpected path argument, expected angle bracketed path argument"
242
- ) ,
260
+ _ => {
261
+ return Err ( Diagnostics :: with_span (
262
+ last_segment. ident . span ( ) ,
263
+ "unexpected path argument, expected angle bracketed path argument" ,
264
+ ) )
265
+ }
243
266
} ;
244
267
245
- generic_schema_type. children = generic_types
246
- . as_mut ( )
247
- . map ( |generic_type| generic_type. map ( Self :: from_type) . collect ( ) ) ;
268
+ generic_schema_type. children = generic_types. as_mut ( ) . map_try ( |generic_type| {
269
+ generic_type
270
+ . map ( Self :: from_type)
271
+ . collect :: < Result < Vec < _ > , Diagnostics > > ( )
272
+ } ) ?;
248
273
249
- generic_schema_type
274
+ Ok ( generic_schema_type)
250
275
}
251
276
252
277
fn convert ( path : & ' t Path , last_segment : & ' t PathSegment ) -> TypeTree < ' t > {
@@ -489,6 +514,12 @@ impl<'c> ComponentSchema {
489
514
let deprecated_stream = ComponentSchema :: get_deprecated ( deprecated) ;
490
515
let description_stream = ComponentSchema :: get_description ( description) ;
491
516
517
+ let match_diagnostics =
518
+ |result : Result < ( ) , Diagnostics > , tokens : & mut TokenStream | match result {
519
+ Err ( diagnostics) => diagnostics. to_tokens ( tokens) ,
520
+ _ => ( ) ,
521
+ } ;
522
+
492
523
match type_tree. generic_type {
493
524
Some ( GenericType :: Map ) => ComponentSchema :: map_to_tokens (
494
525
& mut tokens,
@@ -498,38 +529,50 @@ impl<'c> ComponentSchema {
498
529
description_stream,
499
530
deprecated_stream,
500
531
) ,
501
- Some ( GenericType :: Vec ) => ComponentSchema :: vec_to_tokens (
532
+ Some ( GenericType :: Vec ) => match_diagnostics (
533
+ ComponentSchema :: vec_to_tokens (
534
+ & mut tokens,
535
+ features,
536
+ type_tree,
537
+ object_name,
538
+ description_stream,
539
+ deprecated_stream,
540
+ ) ,
502
541
& mut tokens,
503
- features,
504
- type_tree,
505
- object_name,
506
- description_stream,
507
- deprecated_stream,
508
542
) ,
509
- Some ( GenericType :: LinkedList ) => ComponentSchema :: vec_to_tokens (
543
+ Some ( GenericType :: LinkedList ) => match_diagnostics (
544
+ ComponentSchema :: vec_to_tokens (
545
+ & mut tokens,
546
+ features,
547
+ type_tree,
548
+ object_name,
549
+ description_stream,
550
+ deprecated_stream,
551
+ ) ,
510
552
& mut tokens,
511
- features,
512
- type_tree,
513
- object_name,
514
- description_stream,
515
- deprecated_stream,
516
553
) ,
517
- Some ( GenericType :: Set ) => ComponentSchema :: vec_to_tokens (
554
+ Some ( GenericType :: Set ) => match_diagnostics (
555
+ ComponentSchema :: vec_to_tokens (
556
+ & mut tokens,
557
+ features,
558
+ type_tree,
559
+ object_name,
560
+ description_stream,
561
+ deprecated_stream,
562
+ ) ,
518
563
& mut tokens,
519
- features,
520
- type_tree,
521
- object_name,
522
- description_stream,
523
- deprecated_stream,
524
564
) ,
525
565
#[ cfg( feature = "smallvec" ) ]
526
- Some ( GenericType :: SmallVec ) => ComponentSchema :: vec_to_tokens (
566
+ Some ( GenericType :: SmallVec ) => match_diagnostics (
567
+ ComponentSchema :: vec_to_tokens (
568
+ & mut tokens,
569
+ features,
570
+ type_tree,
571
+ object_name,
572
+ description_stream,
573
+ deprecated_stream,
574
+ ) ,
527
575
& mut tokens,
528
- features,
529
- type_tree,
530
- object_name,
531
- description_stream,
532
- deprecated_stream,
533
576
) ,
534
577
Some ( GenericType :: Option ) => {
535
578
// Add nullable feature if not already exists. Option is always nullable
@@ -658,9 +701,9 @@ impl<'c> ComponentSchema {
658
701
object_name : & str ,
659
702
description_stream : Option < TokenStream > ,
660
703
deprecated_stream : Option < TokenStream > ,
661
- ) {
704
+ ) -> Result < ( ) , Diagnostics > {
662
705
let example = pop_feature ! ( features => Feature :: Example ( _) ) ;
663
- let xml = features. extract_vec_xml_feature ( type_tree) ;
706
+ let xml = features. extract_vec_xml_feature ( type_tree) ? ;
664
707
let max_items = pop_feature ! ( features => Feature :: MaxItems ( _) ) ;
665
708
let min_items = pop_feature ! ( features => Feature :: MinItems ( _) ) ;
666
709
let nullable = pop_feature ! ( features => Feature :: Nullable ( _) ) ;
@@ -753,6 +796,8 @@ impl<'c> ComponentSchema {
753
796
example. to_tokens ( tokens) ;
754
797
xml. to_tokens ( tokens) ;
755
798
nullable. to_tokens ( tokens) ;
799
+
800
+ Ok ( ( ) )
756
801
}
757
802
758
803
fn non_generic_to_tokens (
0 commit comments