Skip to content

Commit 57330a8

Browse files
Merge generic enum tags
1 parent c8546ad commit 57330a8

24 files changed

+634
-4
lines changed

src/bindgen/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,8 @@ pub struct EnumConfig {
598598
/// Whether to generate empty, private default-constructors for tagged
599599
/// enums.
600600
pub private_default_tagged_enum_constructor: bool,
601+
/// Whether to only output a single tag enum for generic tagged enums.
602+
pub merge_generic_tags: bool,
601603
}
602604

603605
impl Default for EnumConfig {
@@ -618,6 +620,7 @@ impl Default for EnumConfig {
618620
derive_ostream: false,
619621
enum_class: true,
620622
private_default_tagged_enum_constructor: false,
623+
merge_generic_tags: false,
621624
}
622625
}
623626
}

src/bindgen/ir/enumeration.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
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;
56
use std::io::Write;
7+
use std::rc::Rc;
68

79
use 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)]
321328
pub 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 => {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef enum COption_Tag {
7+
Some,
8+
None,
9+
} COption_Tag;
10+
11+
typedef struct COption_u8 {
12+
COption_Tag tag;
13+
union {
14+
struct {
15+
uint8_t some;
16+
};
17+
};
18+
} COption_u8;
19+
20+
21+
22+
typedef struct COption_u32 {
23+
COption_Tag tag;
24+
union {
25+
struct {
26+
uint32_t some;
27+
};
28+
};
29+
} COption_u32;
30+
31+
void root(struct COption_u8 a, struct COption_u32 b);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef enum COption_Tag {
7+
Some,
8+
None,
9+
} COption_Tag;
10+
11+
typedef struct COption_u8 {
12+
COption_Tag tag;
13+
union {
14+
struct {
15+
uint8_t some;
16+
};
17+
};
18+
} COption_u8;
19+
20+
21+
22+
typedef struct COption_u32 {
23+
COption_Tag tag;
24+
union {
25+
struct {
26+
uint32_t some;
27+
};
28+
};
29+
} COption_u32;
30+
31+
#ifdef __cplusplus
32+
extern "C" {
33+
#endif // __cplusplus
34+
35+
void root(struct COption_u8 a, struct COption_u32 b);
36+
37+
#ifdef __cplusplus
38+
} // extern "C"
39+
#endif // __cplusplus
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef enum {
7+
Some,
8+
None,
9+
} COption_Tag;
10+
11+
typedef struct {
12+
COption_Tag tag;
13+
union {
14+
struct {
15+
uint8_t some;
16+
};
17+
};
18+
} COption_u8;
19+
20+
21+
22+
typedef struct {
23+
COption_Tag tag;
24+
union {
25+
struct {
26+
uint32_t some;
27+
};
28+
};
29+
} COption_u32;
30+
31+
void root(COption_u8 a, COption_u32 b);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef enum {
7+
Some,
8+
None,
9+
} COption_Tag;
10+
11+
typedef struct {
12+
COption_Tag tag;
13+
union {
14+
struct {
15+
uint8_t some;
16+
};
17+
};
18+
} COption_u8;
19+
20+
21+
22+
typedef struct {
23+
COption_Tag tag;
24+
union {
25+
struct {
26+
uint32_t some;
27+
};
28+
};
29+
} COption_u32;
30+
31+
#ifdef __cplusplus
32+
extern "C" {
33+
#endif // __cplusplus
34+
35+
void root(COption_u8 a, COption_u32 b);
36+
37+
#ifdef __cplusplus
38+
} // extern "C"
39+
#endif // __cplusplus
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <cstdarg>
2+
#include <cstdint>
3+
#include <cstdlib>
4+
#include <ostream>
5+
#include <new>
6+
7+
template<typename T>
8+
struct COption {
9+
enum class Tag {
10+
Some,
11+
None,
12+
};
13+
14+
struct Some_Body {
15+
T _0;
16+
};
17+
18+
Tag tag;
19+
union {
20+
Some_Body some;
21+
};
22+
};
23+
24+
extern "C" {
25+
26+
void root(COption<uint8_t> a, COption<uint32_t> b);
27+
28+
} // extern "C"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t
2+
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t
3+
cdef extern from *:
4+
ctypedef bint bool
5+
ctypedef struct va_list
6+
7+
cdef extern from *:
8+
9+
ctypedef enum COption_Tag:
10+
Some,
11+
None,
12+
13+
ctypedef struct COption_u8:
14+
COption_Tag tag;
15+
uint8_t some;
16+
17+
18+
19+
ctypedef struct COption_u32:
20+
COption_Tag tag;
21+
uint32_t some;
22+
23+
void root(COption_u8 a, COption_u32 b);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
enum COption_Tag {
7+
Some,
8+
None,
9+
};
10+
11+
struct COption_u8 {
12+
enum COption_Tag tag;
13+
union {
14+
struct {
15+
uint8_t some;
16+
};
17+
};
18+
};
19+
20+
21+
22+
struct COption_u32 {
23+
enum COption_Tag tag;
24+
union {
25+
struct {
26+
uint32_t some;
27+
};
28+
};
29+
};
30+
31+
void root(struct COption_u8 a, struct COption_u32 b);

0 commit comments

Comments
 (0)