22 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44
5+ use std:: cell:: Cell ;
56use std:: io:: Write ;
7+ use std:: rc:: Rc ;
68
79use syn:: ext:: IdentExt ;
810
@@ -270,8 +272,13 @@ impl EnumVariant {
270272 mappings : & [ ( & Path , & GenericArgument ) ] ,
271273 config : & Config ,
272274 ) -> Self {
275+ let name = if config. enumeration . merge_generic_tags {
276+ self . name . clone ( )
277+ } else {
278+ mangle:: mangle_name ( & self . name , generic_values, & config. export . mangle )
279+ } ;
273280 Self :: new (
274- mangle :: mangle_name ( & self . name , generic_values , & config . export . mangle ) ,
281+ name,
275282 self . discriminant . clone ( ) ,
276283 self . body . specialize ( generic_values, mappings, config) ,
277284 self . cfg . clone ( ) ,
@@ -320,11 +327,15 @@ impl Source for EnumVariant {
320327#[ derive( Debug , Clone ) ]
321328pub struct Enum {
322329 pub path : Path ,
330+ pub unmangled_path : Path ,
323331 pub export_name : String ,
332+ pub unmangled_export_name : String ,
324333 pub generic_params : GenericParams ,
325334 pub repr : Repr ,
326335 pub variants : Vec < EnumVariant > ,
327336 pub tag : Option < String > ,
337+ /// Keep track of whether any instance of this enum has had its tag written.
338+ pub tag_written : Rc < Cell < bool > > ,
328339 pub cfg : Option < Cfg > ,
329340 pub annotations : AnnotationSet ,
330341 pub documentation : Documentation ,
@@ -433,11 +444,13 @@ impl Enum {
433444 } ;
434445
435446 Ok ( Enum :: new (
447+ path. clone ( ) ,
436448 path,
437449 generic_params,
438450 repr,
439451 variants,
440452 tag,
453+ Rc :: new ( Cell :: new ( false ) ) ,
441454 Cfg :: append ( mod_cfg, Cfg :: load ( & item. attrs ) ) ,
442455 annotations,
443456 Documentation :: load ( & item. attrs ) ,
@@ -447,22 +460,28 @@ impl Enum {
447460 #[ allow( clippy:: too_many_arguments) ]
448461 pub fn new (
449462 path : Path ,
463+ unmangled_path : Path ,
450464 generic_params : GenericParams ,
451465 repr : Repr ,
452466 variants : Vec < EnumVariant > ,
453467 tag : Option < String > ,
468+ tag_written : Rc < Cell < bool > > ,
454469 cfg : Option < Cfg > ,
455470 annotations : AnnotationSet ,
456471 documentation : Documentation ,
457472 ) -> Self {
458473 let export_name = path. name ( ) . to_owned ( ) ;
474+ let unmangled_export_name = unmangled_path. name ( ) . to_owned ( ) ;
459475 Self {
460476 path,
477+ unmangled_path,
461478 export_name,
479+ unmangled_export_name,
462480 generic_params,
463481 repr,
464482 variants,
465483 tag,
484+ tag_written,
466485 cfg,
467486 annotations,
468487 documentation,
@@ -518,10 +537,16 @@ impl Item for Enum {
518537
519538 fn rename_for_config ( & mut self , config : & Config ) {
520539 config. export . rename ( & mut self . export_name ) ;
540+ config. export . rename ( & mut self . unmangled_export_name ) ;
521541
522542 if config. language != Language :: Cxx && self . tag . is_some ( ) {
523543 // it makes sense to always prefix Tag with type name in C
524- let new_tag = format ! ( "{}_Tag" , self . export_name) ;
544+ let base_name = if config. enumeration . merge_generic_tags {
545+ & self . unmangled_export_name
546+ } else {
547+ & self . export_name
548+ } ;
549+ let new_tag = format ! ( "{}_Tag" , base_name) ;
525550 if self . repr . style == ReprStyle :: Rust {
526551 for variant in & mut self . variants {
527552 if let VariantBody :: Body { ref mut body, .. } = variant. body {
@@ -560,11 +585,16 @@ impl Item for Enum {
560585 } ;
561586
562587 for variant in & mut self . variants {
588+ let export_name = if config. enumeration . merge_generic_tags {
589+ & self . unmangled_export_name
590+ } else {
591+ & self . export_name
592+ } ;
563593 variant. export_name =
564- format ! ( "{}{}{}" , self . export_name, separator, variant. export_name) ;
594+ format ! ( "{}{}{}" , export_name, separator, variant. export_name) ;
565595 if let VariantBody :: Body { ref mut body, .. } = variant. body {
566596 body. export_name =
567- format ! ( "{}{}{}" , self . export_name, separator, body. export_name( ) ) ;
597+ format ! ( "{}{}{}" , export_name, separator, body. export_name( ) ) ;
568598 }
569599 }
570600 }
@@ -632,13 +662,15 @@ impl Item for Enum {
632662
633663 let monomorph = Enum :: new (
634664 mangled_path,
665+ self . unmangled_path . clone ( ) ,
635666 GenericParams :: default ( ) ,
636667 self . repr ,
637668 self . variants
638669 . iter ( )
639670 . map ( |v| v. specialize ( generic_values, & mappings, library. get_config ( ) ) )
640671 . collect ( ) ,
641672 self . tag . clone ( ) ,
673+ self . tag_written . clone ( ) ,
642674 self . cfg . clone ( ) ,
643675 self . annotations . clone ( ) ,
644676 self . documentation . clone ( ) ,
@@ -747,6 +779,12 @@ impl Enum {
747779 has_data : bool ,
748780 tag_name : & str ,
749781 ) {
782+ // Only emit the tag enum once if merge_generic_tags is set.
783+ if config. enumeration . merge_generic_tags && self . tag_written . get ( ) {
784+ return ;
785+ }
786+ self . tag_written . set ( true ) ;
787+
750788 // Open the tag enum.
751789 match config. language {
752790 Language :: C => {
0 commit comments