@@ -133,7 +133,7 @@ pub struct FieldOpts {
133133
134134impl FieldOpts {
135135 #[ must_use]
136- fn find_type ( & self , type_to_check : & str , symbol_resolver : & SymbolResolver ) -> bool {
136+ fn has_type ( & self , type_to_check : & str , symbol_resolver : & SymbolResolver ) -> bool {
137137 let mut ty = self . ty . clone ( ) ;
138138 symbol_resolver. resolve ( & mut ty) ;
139139 Self :: inner_type_names ( & ty)
@@ -171,6 +171,54 @@ impl FieldOpts {
171171 }
172172 }
173173
174+ fn find_type ( & self , type_to_find : & str , symbol_resolver : & SymbolResolver ) -> Option < syn:: Type > {
175+ let mut ty = self . ty . clone ( ) ;
176+ symbol_resolver. resolve ( & mut ty) ;
177+ Self :: find_type_resolved ( & ty, type_to_find)
178+ }
179+
180+ fn find_type_resolved ( ty : & syn:: Type , type_to_find : & str ) -> Option < syn:: Type > {
181+ if let syn:: Type :: Path ( type_path) = ty {
182+ let name = type_path
183+ . path
184+ . segments
185+ . iter ( )
186+ . map ( |s| s. ident . to_string ( ) )
187+ . collect :: < Vec < _ > > ( )
188+ . join ( "::" ) ;
189+
190+ if name == type_to_find {
191+ return Some ( ty. clone ( ) ) ;
192+ }
193+
194+ for arg in & type_path. path . segments {
195+ if let syn:: PathArguments :: AngleBracketed ( arg) = & arg. arguments {
196+ if let Some ( ty) = Self :: find_type_in_generics ( arg, type_to_find) {
197+ return Some ( ty) ;
198+ }
199+ }
200+ }
201+ }
202+
203+ None
204+ }
205+
206+ fn find_type_in_generics (
207+ arg : & syn:: AngleBracketedGenericArguments ,
208+ type_to_find : & str ,
209+ ) -> Option < syn:: Type > {
210+ arg. args
211+ . iter ( )
212+ . filter_map ( |arg| {
213+ if let syn:: GenericArgument :: Type ( ty) = arg {
214+ Self :: find_type_resolved ( ty, type_to_find)
215+ } else {
216+ None
217+ }
218+ } )
219+ . next ( )
220+ }
221+
174222 /// Convert the field options into a field.
175223 ///
176224 /// # Panics
@@ -183,10 +231,13 @@ impl FieldOpts {
183231 let column_name = name. to_string ( ) ;
184232 let ( auto_value, foreign_key) = match symbol_resolver {
185233 Some ( resolver) => (
186- Some ( self . find_type ( "flareon::db::Auto" , resolver) ) ,
187- Some ( self . find_type ( "flareon::db::ForeignKey" , resolver) ) ,
234+ MaybeUnknown :: Determined ( self . find_type ( "flareon::db::Auto" , resolver) . is_some ( ) ) ,
235+ MaybeUnknown :: Determined (
236+ self . find_type ( "flareon::db::ForeignKey" , resolver)
237+ . map ( ForeignKeySpec :: from) ,
238+ ) ,
188239 ) ,
189- None => ( None , None ) ,
240+ None => ( MaybeUnknown :: Unknown , MaybeUnknown :: Unknown ) ,
190241 } ;
191242 let is_primary_key = column_name == "id" || self . primary_key . is_present ( ) ;
192243
@@ -224,19 +275,65 @@ pub struct Field {
224275 pub field_name : syn:: Ident ,
225276 pub column_name : String ,
226277 pub ty : syn:: Type ,
227- /// Whether the field is an auto field (e.g. `id`); `None` if it could not
228- /// be determined.
229- pub auto_value : Option < bool > ,
278+ /// Whether the field is an auto field (e.g. `id`);
279+ /// [`MaybeUnknown::Unknown`] if this `Field` instance was not resolved with
280+ /// a [`SymbolResolver`].
281+ pub auto_value : MaybeUnknown < bool > ,
230282 pub primary_key : bool ,
231- /// Whether the field is a foreign key; `None` if it could not be
232- /// determined.
233- pub foreign_key : Option < bool > ,
283+ /// [`Some`] wrapped in [`MaybeUnknown::Determined`] if this field is a
284+ /// foreign key; [`None`] wrapped in [`MaybeUnknown::Determined`] if this
285+ /// field is determined not to be a foreign key; [`MaybeUnknown::Unknown`]
286+ /// if this `Field` instance was not resolved with a [`SymbolResolver`].
287+ pub foreign_key : MaybeUnknown < Option < ForeignKeySpec > > ,
234288 pub unique : bool ,
235289}
236290
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 ,
300+ }
301+
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+ }
311+
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+ }
321+
322+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
323+ pub struct ForeignKeySpec {
324+ pub ty : syn:: Type ,
325+ }
326+
327+ impl From < syn:: Type > for ForeignKeySpec {
328+ fn from ( value : syn:: Type ) -> Self {
329+ todo ! ( )
330+ }
331+ }
332+
237333#[ cfg( test) ]
238334mod tests {
239335 use syn:: parse_quote;
336+ use syn:: TraitBoundModifier :: Maybe ;
240337
241338 use super :: * ;
242339 #[ cfg( feature = "symbol-resolver" ) ]
@@ -371,8 +468,8 @@ mod tests {
371468 assert_eq ! ( field. column_name, "name" ) ;
372469 assert_eq ! ( field. ty, parse_quote!( String ) ) ;
373470 assert ! ( field. unique) ;
374- assert_eq ! ( field. auto_value, None ) ;
375- assert_eq ! ( field. foreign_key, None ) ;
471+ assert_eq ! ( field. auto_value, MaybeUnknown :: Unknown ) ;
472+ assert_eq ! ( field. foreign_key, MaybeUnknown :: Unknown ) ;
376473 }
377474
378475 #[ test]
@@ -403,9 +500,9 @@ mod tests {
403500 unique : Default :: default ( ) ,
404501 } ;
405502
406- assert ! ( opts. find_type ( "my_crate::MyContainer" , & resolver) ) ;
407- assert ! ( opts. find_type ( "std::string::String" , & resolver) ) ;
408- assert ! ( !opts. find_type ( "MyContainer" , & resolver) ) ;
409- assert ! ( !opts. find_type ( "String" , & resolver) ) ;
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) ) ;
410507 }
411508}
0 commit comments