11use convert_case:: { Case , Casing } ;
22use darling:: { FromDeriveInput , FromField , FromMeta } ;
3+ use syn:: spanned:: Spanned ;
34
5+ use crate :: maybe_unknown:: MaybeUnknown ;
46use crate :: symbol_resolver:: SymbolResolver ;
57
68#[ allow( clippy:: module_name_repetitions) ]
@@ -66,11 +68,11 @@ impl ModelOpts {
6668 args : & ModelArgs ,
6769 symbol_resolver : Option < & SymbolResolver > ,
6870 ) -> Result < Model , syn:: Error > {
69- let fields: Vec < _ > = self
71+ let fields = self
7072 . fields ( )
7173 . iter ( )
7274 . map ( |field| field. as_field ( symbol_resolver) )
73- . collect ( ) ;
75+ . collect :: < Result < Vec < _ > , _ > > ( ) ? ;
7476
7577 let mut original_name = self . ident . to_string ( ) ;
7678 if args. model_type == ModelType :: Migration {
@@ -132,45 +134,6 @@ pub struct FieldOpts {
132134}
133135
134136impl FieldOpts {
135- #[ must_use]
136- fn has_type ( & self , type_to_check : & str , symbol_resolver : & SymbolResolver ) -> bool {
137- let mut ty = self . ty . clone ( ) ;
138- symbol_resolver. resolve ( & mut ty) ;
139- Self :: inner_type_names ( & ty)
140- . iter ( )
141- . any ( |name| name == type_to_check)
142- }
143-
144- #[ must_use]
145- fn inner_type_names ( ty : & syn:: Type ) -> Vec < String > {
146- let mut names = Vec :: new ( ) ;
147- Self :: inner_type_names_impl ( ty, & mut names) ;
148- names
149- }
150-
151- fn inner_type_names_impl ( ty : & syn:: Type , names : & mut Vec < String > ) {
152- if let syn:: Type :: Path ( type_path) = ty {
153- let name = type_path
154- . path
155- . segments
156- . iter ( )
157- . map ( |s| s. ident . to_string ( ) )
158- . collect :: < Vec < _ > > ( )
159- . join ( "::" ) ;
160- names. push ( name) ;
161-
162- for arg in & type_path. path . segments {
163- if let syn:: PathArguments :: AngleBracketed ( arg) = & arg. arguments {
164- for arg in & arg. args {
165- if let syn:: GenericArgument :: Type ( ty) = arg {
166- Self :: inner_type_names_impl ( ty, names) ;
167- }
168- }
169- }
170- }
171- }
172- }
173-
174137 fn find_type ( & self , type_to_find : & str , symbol_resolver : & SymbolResolver ) -> Option < syn:: Type > {
175138 let mut ty = self . ty . clone ( ) ;
176139 symbol_resolver. resolve ( & mut ty) ;
@@ -225,31 +188,32 @@ impl FieldOpts {
225188 ///
226189 /// Panics if the field does not have an identifier (i.e. it is a tuple
227190 /// struct).
228- #[ must_use]
229- pub fn as_field ( & self , symbol_resolver : Option < & SymbolResolver > ) -> Field {
191+ pub fn as_field ( & self , symbol_resolver : Option < & SymbolResolver > ) -> Result < Field , syn:: Error > {
230192 let name = self . ident . as_ref ( ) . unwrap ( ) ;
231193 let column_name = name. to_string ( ) ;
194+
232195 let ( auto_value, foreign_key) = match symbol_resolver {
233196 Some ( resolver) => (
234197 MaybeUnknown :: Determined ( self . find_type ( "flareon::db::Auto" , resolver) . is_some ( ) ) ,
235198 MaybeUnknown :: Determined (
236199 self . find_type ( "flareon::db::ForeignKey" , resolver)
237- . map ( ForeignKeySpec :: from) ,
200+ . map ( ForeignKeySpec :: try_from)
201+ . transpose ( ) ?,
238202 ) ,
239203 ) ,
240204 None => ( MaybeUnknown :: Unknown , MaybeUnknown :: Unknown ) ,
241205 } ;
242206 let is_primary_key = column_name == "id" || self . primary_key . is_present ( ) ;
243207
244- Field {
208+ Ok ( Field {
245209 field_name : name. clone ( ) ,
246210 column_name,
247211 ty : self . ty . clone ( ) ,
248212 auto_value,
249213 primary_key : is_primary_key,
250214 foreign_key,
251215 unique : self . unique . is_present ( ) ,
252- }
216+ } )
253217 }
254218}
255219
@@ -288,52 +252,60 @@ pub struct Field {
288252 pub unique : bool ,
289253}
290254
291- /// Wraps a type whose value may or may not be possible to be determined using
292- /// the information available.
293- #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
294- pub enum MaybeUnknown < T > {
295- /// Indicates that this instance is determined to be a certain value
296- /// (possibly [`None`] if wrapping an [`Option`]).
297- Determined ( T ) ,
298- /// Indicates that the value is unknown.
299- Unknown ,
255+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
256+ pub struct ForeignKeySpec {
257+ pub to_model : syn:: Type ,
300258}
301259
302- impl < T > MaybeUnknown < T > {
303- pub fn unwrap ( self ) -> T {
304- match self {
305- MaybeUnknown :: Determined ( value) => value,
306- MaybeUnknown :: Unknown => {
307- panic ! ( "called `MaybeUnknown::unwrap()` on an `Unknown` value" )
308- }
309- }
310- }
260+ impl TryFrom < syn:: Type > for ForeignKeySpec {
261+ type Error = syn:: Error ;
311262
312- pub fn expect ( self , msg : & str ) -> T {
313- match self {
314- MaybeUnknown :: Determined ( value) => value,
315- MaybeUnknown :: Unknown => {
316- panic ! ( "{}" , msg)
317- }
318- }
319- }
320- }
263+ fn try_from ( ty : syn:: Type ) -> Result < Self , Self :: Error > {
264+ let type_path = if let syn:: Type :: Path ( type_path) = & ty {
265+ type_path
266+ } else {
267+ panic ! ( "Expected a path type for a foreign key" ) ;
268+ } ;
321269
322- #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
323- pub struct ForeignKeySpec {
324- pub ty : syn:: Type ,
325- }
270+ let args = if let syn:: PathArguments :: AngleBracketed ( args) = & type_path
271+ . path
272+ . segments
273+ . last ( )
274+ . expect ( "type path must have at least one segment" )
275+ . arguments
276+ {
277+ args
278+ } else {
279+ return Err ( syn:: Error :: new (
280+ ty. span ( ) ,
281+ "expected ForeignKey to have angle-bracketed generic arguments" ,
282+ ) ) ;
283+ } ;
284+
285+ if args. args . len ( ) != 1 {
286+ return Err ( syn:: Error :: new (
287+ ty. span ( ) ,
288+ "expected ForeignKey to have only one generic parameter" ,
289+ ) ) ;
290+ }
326291
327- impl From < syn:: Type > for ForeignKeySpec {
328- fn from ( value : syn:: Type ) -> Self {
329- todo ! ( )
292+ let inner = & args. args [ 0 ] ;
293+ if let syn:: GenericArgument :: Type ( ty) = inner {
294+ Ok ( Self {
295+ to_model : ty. clone ( ) ,
296+ } )
297+ } else {
298+ Err ( syn:: Error :: new (
299+ ty. span ( ) ,
300+ "expected ForeignKey to have a type generic argument" ,
301+ ) )
302+ }
330303 }
331304}
332305
333306#[ cfg( test) ]
334307mod tests {
335308 use syn:: parse_quote;
336- use syn:: TraitBoundModifier :: Maybe ;
337309
338310 use super :: * ;
339311 #[ cfg( feature = "symbol-resolver" ) ]
@@ -463,7 +435,7 @@ mod tests {
463435 name: String
464436 } ;
465437 let field_opts = FieldOpts :: from_field ( & input) . unwrap ( ) ;
466- let field = field_opts. as_field ( None ) ;
438+ let field = field_opts. as_field ( None ) . unwrap ( ) ;
467439 assert_eq ! ( field. field_name. to_string( ) , "name" ) ;
468440 assert_eq ! ( field. column_name, "name" ) ;
469441 assert_eq ! ( field. ty, parse_quote!( String ) ) ;
@@ -473,19 +445,18 @@ mod tests {
473445 }
474446
475447 #[ test]
476- fn inner_type_names ( ) {
448+ fn find_type_resolved ( ) {
477449 let input: syn:: Type =
478450 parse_quote ! { :: my_crate:: MyContainer <' a, Vec <std:: string:: String >> } ;
479- let names = FieldOpts :: inner_type_names ( & input) ;
480- assert_eq ! (
481- names,
482- vec![ "my_crate::MyContainer" , "Vec" , "std::string::String" ]
483- ) ;
451+ assert ! ( FieldOpts :: find_type_resolved( & input, "my_crate::MyContainer" ) . is_some( ) ) ;
452+ assert ! ( FieldOpts :: find_type_resolved( & input, "Vec" ) . is_some( ) ) ;
453+ assert ! ( FieldOpts :: find_type_resolved( & input, "std::string::String" ) . is_some( ) ) ;
454+ assert ! ( !FieldOpts :: find_type_resolved( & input, "OtherType" ) . is_some( ) ) ;
484455 }
485456
486457 #[ cfg( feature = "symbol-resolver" ) ]
487458 #[ test]
488- fn contains_type ( ) {
459+ fn find_type ( ) {
489460 let symbols = vec ! [ VisibleSymbol :: new(
490461 "MyContainer" ,
491462 "my_crate::MyContainer" ,
@@ -500,9 +471,9 @@ mod tests {
500471 unique : Default :: default ( ) ,
501472 } ;
502473
503- assert ! ( opts. has_type ( "my_crate::MyContainer" , & resolver) ) ;
504- assert ! ( opts. has_type ( "std::string::String" , & resolver) ) ;
505- assert ! ( !opts. has_type ( "MyContainer" , & resolver) ) ;
506- assert ! ( !opts. has_type ( "String" , & resolver) ) ;
474+ assert ! ( opts. find_type ( "my_crate::MyContainer" , & resolver) . is_some ( ) ) ;
475+ assert ! ( opts. find_type ( "std::string::String" , & resolver) . is_some ( ) ) ;
476+ assert ! ( !opts. find_type ( "MyContainer" , & resolver) . is_none ( ) ) ;
477+ assert ! ( !opts. find_type ( "String" , & resolver) . is_none ( ) ) ;
507478 }
508479}
0 commit comments