@@ -46,11 +46,16 @@ pub(crate) struct TypeEntryEnum {
4646 pub schema : SchemaWrapper ,
4747}
4848
49+ /// Cached attributes that (mostly) result in customized impl generation.
4950#[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
5051pub ( crate ) enum TypeEntryEnumImpl {
5152 AllSimpleVariants ,
5253 UntaggedFromStr ,
5354 UntaggedDisplay ,
55+ /// This is a cached marker to let us know that at least one of the
56+ /// variants is irrefutably a string. There is currently no associated
57+ /// implementation that we generate.
58+ UntaggedFromStringIrrefutable ,
5459}
5560
5661#[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
@@ -315,12 +320,14 @@ impl TypeEntryEnum {
315320 . iter ( )
316321 . all ( |variant| matches ! ( variant. details, VariantDetails :: Simple ) ) )
317322 . then_some ( TypeEntryEnumImpl :: AllSimpleVariants ) ,
318- // Untagged and all variants impl FromStr.
323+ // Untagged and all variants impl FromStr, but none **is** a
324+ // String (i.e. irrefutably).
319325 untagged_newtype_variants (
320326 type_space,
321327 & self . tag_type ,
322328 & self . variants ,
323329 TypeSpaceImpl :: FromStr ,
330+ Some ( TypeSpaceImpl :: FromStringIrrefutable ) ,
324331 )
325332 . then_some ( TypeEntryEnumImpl :: UntaggedFromStr ) ,
326333 // Untagged and all variants impl Display.
@@ -329,8 +336,11 @@ impl TypeEntryEnum {
329336 & self . tag_type ,
330337 & self . variants ,
331338 TypeSpaceImpl :: Display ,
339+ None ,
332340 )
333341 . then_some ( TypeEntryEnumImpl :: UntaggedDisplay ) ,
342+ untagged_newtype_string ( type_space, & self . tag_type , & self . variants )
343+ . then_some ( TypeEntryEnumImpl :: UntaggedFromStringIrrefutable ) ,
334344 ]
335345 . into_iter ( )
336346 . flatten ( )
@@ -597,7 +607,6 @@ impl TypeEntry {
597607 match & self . details {
598608 TypeEntryDetails :: Enum ( details) => match impl_name {
599609 TypeSpaceImpl :: Default => details. default . is_some ( ) ,
600-
601610 TypeSpaceImpl :: FromStr => {
602611 details
603612 . bespoke_impls
@@ -614,6 +623,9 @@ impl TypeEntry {
614623 . bespoke_impls
615624 . contains ( & TypeEntryEnumImpl :: UntaggedDisplay )
616625 }
626+ TypeSpaceImpl :: FromStringIrrefutable => details
627+ . bespoke_impls
628+ . contains ( & TypeEntryEnumImpl :: UntaggedFromStringIrrefutable ) ,
617629 } ,
618630
619631 TypeEntryDetails :: Struct ( details) => match impl_name {
@@ -627,7 +639,7 @@ impl TypeEntry {
627639 ( TypeEntryNewtypeConstraints :: None , _) => {
628640 // TODO this is a lucky kludge that will need to be removed
629641 // once we have proper handling of reference cycles (i.e.
630- // as opposed to containment cycles... which we also do not
642+ // as opposed to containment cycles... which we **do**
631643 // handle correctly). In particular output_newtype calls
632644 // this to determine if it should produce a FromStr impl.
633645 // This implementation could be infinitely recursive for a
@@ -685,10 +697,25 @@ impl TypeEntry {
685697 }
686698 }
687699
688- TypeEntryDetails :: Boolean => true ,
689- TypeEntryDetails :: Integer ( _) => true ,
690- TypeEntryDetails :: Float ( _) => true ,
691- TypeEntryDetails :: String => true ,
700+ TypeEntryDetails :: Boolean => match impl_name {
701+ TypeSpaceImpl :: Default | TypeSpaceImpl :: FromStr | TypeSpaceImpl :: Display => true ,
702+ TypeSpaceImpl :: FromStringIrrefutable => false ,
703+ } ,
704+ TypeEntryDetails :: Integer ( _) => match impl_name {
705+ TypeSpaceImpl :: Default | TypeSpaceImpl :: FromStr | TypeSpaceImpl :: Display => true ,
706+ TypeSpaceImpl :: FromStringIrrefutable => false ,
707+ } ,
708+
709+ TypeEntryDetails :: Float ( _) => match impl_name {
710+ TypeSpaceImpl :: Default | TypeSpaceImpl :: FromStr | TypeSpaceImpl :: Display => true ,
711+ TypeSpaceImpl :: FromStringIrrefutable => false ,
712+ } ,
713+ TypeEntryDetails :: String => match impl_name {
714+ TypeSpaceImpl :: Default
715+ | TypeSpaceImpl :: FromStr
716+ | TypeSpaceImpl :: Display
717+ | TypeSpaceImpl :: FromStringIrrefutable => true ,
718+ } ,
692719
693720 TypeEntryDetails :: Reference ( _) => unreachable ! ( ) ,
694721 }
@@ -1994,17 +2021,18 @@ fn strings_to_derives<'a>(
19942021
19952022/// Returns true iff...
19962023/// - the enum is untagged
1997- /// - all variants are 1-item tuple-types (aka newtype variants)
2024+ /// - all variants are single items (aka newtype variants)
19982025/// - the type of the newtype variant implements the required trait
19992026fn untagged_newtype_variants (
20002027 type_space : & TypeSpace ,
20012028 tag_type : & EnumTagType ,
20022029 variants : & [ Variant ] ,
20032030 req_impl : TypeSpaceImpl ,
2031+ neg_impl : Option < TypeSpaceImpl > ,
20042032) -> bool {
20052033 tag_type == & EnumTagType :: Untagged
20062034 && variants. iter ( ) . all ( |variant| {
2007- // If the variant is a one-element tuple ...
2035+ // If the variant is a single item ...
20082036 match & variant. details {
20092037 VariantDetails :: Item ( type_id) => Some ( type_id) ,
20102038 _ => None ,
@@ -2015,6 +2043,34 @@ fn untagged_newtype_variants(
20152043 let type_entry = type_space. id_to_entry . get ( type_id) . unwrap ( ) ;
20162044 // ... and its type has the required impl
20172045 type_entry. has_impl ( type_space, req_impl)
2046+ && neg_impl
2047+ . is_none_or ( |neg_impl| !type_entry. has_impl ( type_space, neg_impl) )
2048+ } ,
2049+ )
2050+ } )
2051+ }
2052+
2053+ /// Returns true iff...
2054+ /// - the enum is untagged
2055+ /// - **any** variant is a single items **and** it is irrefutably a string
2056+ fn untagged_newtype_string (
2057+ type_space : & TypeSpace ,
2058+ tag_type : & EnumTagType ,
2059+ variants : & [ Variant ] ,
2060+ ) -> bool {
2061+ tag_type == & EnumTagType :: Untagged
2062+ && variants. iter ( ) . any ( |variant| {
2063+ // If the variant is a single item...
2064+ match & variant. details {
2065+ VariantDetails :: Item ( type_id) => Some ( type_id) ,
2066+ _ => None ,
2067+ }
2068+ . map_or_else (
2069+ || false ,
2070+ |type_id| {
2071+ let type_entry = type_space. id_to_entry . get ( type_id) . unwrap ( ) ;
2072+ // ... and it is irrefutably a string
2073+ type_entry. has_impl ( type_space, TypeSpaceImpl :: FromStringIrrefutable )
20182074 } ,
20192075 )
20202076 } )
0 commit comments