Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type_replacements option to control output of name mangling #720

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,14 @@ rename_types = "PascalCase"
# Whether the underscores from the mangled name should be omitted.
remove_underscores = false

# Table of replacement strings for substituting type parameters when name mangling.
# The keys are processed type names, and the values are the replacement strings.
# This is useful for controlling the mangled names of generic types.
[export.mangle.type_replacements]
"U8" = "Char"
"VecChar" = "Bytes" # This key corresponds to a mangled Vec<u8>
"Empty" = ""

[layout]
# A string that should come before the name of any type which has been marked
# as `#[repr(packed)]`. For instance, "__attribute__((packed))" would be a
Expand Down
3 changes: 3 additions & 0 deletions src/bindgen/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ pub struct MangleConfig {
pub rename_types: RenameRule,
/// Remove the underscores used for name mangling.
pub remove_underscores: bool,
/// Table of replacement strings for substituting type parameters when name mangling.
/// The keys are processed type names, and the values are the replacement strings.
pub type_replacements: HashMap<String, String>,
}

impl ExportConfig {
Expand Down
31 changes: 17 additions & 14 deletions src/bindgen/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,21 +95,24 @@ impl<T: Item + Clone> ItemMap<T> {
}

pub fn try_insert(&mut self, item: T) -> bool {
match (item.cfg().is_some(), self.data.get_mut(item.path())) {
(true, Some(&mut ItemValue::Cfg(ref mut items))) => {
items.push(item);
return true;
}
(false, Some(&mut ItemValue::Cfg(_))) => {
return false;
}
(true, Some(&mut ItemValue::Single(_))) => {
return false;
}
(false, Some(&mut ItemValue::Single(_))) => {
return false;
self.try_insert_item(item, false)
}

pub fn try_insert_item(&mut self, item: T, overwrite_existing: bool) -> bool {
if !overwrite_existing {
match (item.cfg().is_some(), self.data.get_mut(item.path())) {
(true, Some(&mut ItemValue::Cfg(ref mut items))) => {
items.push(item);
return true;
}
(false, Some(&mut ItemValue::Cfg(_))) => {
return false;
}
(_, Some(&mut ItemValue::Single(_))) => {
return false;
}
_ => {}
}
_ => {}
}

let path = item.path().clone();
Expand Down
13 changes: 7 additions & 6 deletions src/bindgen/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,21 +396,22 @@ impl Library {
x.add_monomorphs(self, &mut monomorphs);
}

// Insert the monomorphs into self
// Insert the monomorphs into self. Allow overwriting to enable empty type parameter
// replacements to work properly.
for monomorph in monomorphs.drain_structs() {
self.structs.try_insert(monomorph);
self.structs.try_insert_item(monomorph, true);
}
for monomorph in monomorphs.drain_unions() {
self.unions.try_insert(monomorph);
self.unions.try_insert_item(monomorph, true);
}
for monomorph in monomorphs.drain_opaques() {
self.opaque_items.try_insert(monomorph);
self.opaque_items.try_insert_item(monomorph, true);
}
for monomorph in monomorphs.drain_typedefs() {
self.typedefs.try_insert(monomorph);
self.typedefs.try_insert_item(monomorph, true);
}
for monomorph in monomorphs.drain_enums() {
self.enums.try_insert(monomorph);
self.enums.try_insert_item(monomorph, true);
}

// Remove structs and opaque items that are generic
Expand Down
109 changes: 97 additions & 12 deletions src/bindgen/mangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,32 @@ impl<'a> Mangler<'a> {
let sub_path =
Mangler::new(generic.export_name(), generic.generics(), last, self.config)
.mangle();
let mangled = self
.config
.rename_types
.apply(&sub_path, IdentifierType::Type);
let type_str = self
.config
.type_replacements
.get(mangled.as_ref())
.map(String::as_str)
.unwrap_or_else(|| mangled.as_ref());

self.output.push_str(
&self
.config
.rename_types
.apply(&sub_path, IdentifierType::Type),
);
self.output.push_str(type_str);
}
Type::Primitive(ref primitive) => {
self.output.push_str(
&self
.config
.rename_types
.apply(primitive.to_repr_rust(), IdentifierType::Type),
);
let mangled = self
.config
.rename_types
.apply(primitive.to_repr_rust(), IdentifierType::Type);
let type_str = self
.config
.type_replacements
.get(mangled.as_ref())
.map(String::as_str)
.unwrap_or_else(|| mangled.as_ref());

self.output.push_str(type_str);
}
Type::Ptr {
ref ty, is_const, ..
Expand Down Expand Up @@ -145,6 +156,8 @@ impl<'a> Mangler<'a> {

#[test]
fn generics() {
use std::collections::HashMap;

use crate::bindgen::ir::{GenericPath, PrimitiveType};
use crate::bindgen::rename::RenameRule::{self, PascalCase};

Expand Down Expand Up @@ -196,6 +209,7 @@ fn generics() {
&MangleConfig {
remove_underscores: true,
rename_types: RenameRule::None,
type_replacements: HashMap::new(),
}
),
Path::new("FooBar")
Expand All @@ -209,6 +223,7 @@ fn generics() {
&MangleConfig {
remove_underscores: true,
rename_types: PascalCase,
type_replacements: HashMap::new(),
},
),
Path::new("FooBarF32")
Expand All @@ -222,6 +237,7 @@ fn generics() {
&MangleConfig {
remove_underscores: true,
rename_types: PascalCase,
type_replacements: HashMap::new(),
},
),
Path::new("FooBarCChar")
Expand Down Expand Up @@ -268,6 +284,7 @@ fn generics() {
&MangleConfig {
remove_underscores: true,
rename_types: PascalCase,
type_replacements: HashMap::new(),
},
),
Path::new("FooBarTE")
Expand All @@ -284,8 +301,76 @@ fn generics() {
&MangleConfig {
remove_underscores: true,
rename_types: PascalCase,
type_replacements: HashMap::new(),
},
),
Path::new("FooBarTBarE")
);

// Foo<Bar<T>, E> => Foo_BarX__E
assert_eq!(
mangle_path(
&Path::new("Foo"),
&[generic_path("Bar", &[path("T")]), path("E")],
&MangleConfig {
remove_underscores: false,
rename_types: PascalCase,
type_replacements: vec![("T".to_owned(), "X".to_owned())]
.into_iter()
.collect::<HashMap<_, _>>()
},
),
Path::new("Foo_BarX__E")
);

// Foo<Bar<T>, E> => FooChickenE
assert_eq!(
mangle_path(
&Path::new("Foo"),
&[generic_path("Bar", &[path("T")]), path("E")],
&MangleConfig {
remove_underscores: true,
rename_types: PascalCase,
type_replacements: vec![("BarT".to_owned(), "Chicken".to_owned())]
.into_iter()
.collect::<HashMap<_, _>>()
},
),
Path::new("FooChickenE")
);

// Foo<Bar<T>, T> => FooChickenNugget
assert_eq!(
mangle_path(
&Path::new("Foo"),
&[generic_path("Bar", &[path("T")]), path("T")],
&MangleConfig {
remove_underscores: true,
rename_types: PascalCase,
type_replacements: vec![
("T".to_owned(), "Nugget".to_owned()),
("BarNugget".to_owned(), "Chicken".to_owned()),
]
.into_iter()
.collect::<HashMap<_, _>>()
},
),
Path::new("FooChickenNugget")
);

// Foo<Bar<T>, T> => FooT
assert_eq!(
mangle_path(
&Path::new("Foo"),
&[generic_path("Bar", &[path("T")]), path("T")],
&MangleConfig {
remove_underscores: true,
rename_types: PascalCase,
type_replacements: vec![("BarT".to_owned(), "".to_owned()),]
.into_iter()
.collect::<HashMap<_, _>>()
},
),
Path::new("FooT")
);
}
15 changes: 14 additions & 1 deletion tests/expectations/mangle.both.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,17 @@ typedef struct FooU8 {

typedef struct FooU8 Boo;

void root(Boo x, enum Bar y);
typedef enum Dog_Tag {
DogWoof,
} Dog_Tag;

typedef struct Dog {
Dog_Tag tag;
union {
struct {
struct FooU8 woof;
};
};
} Dog;

void root(Boo x, enum Bar y, struct Dog z);
15 changes: 14 additions & 1 deletion tests/expectations/mangle.both.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,24 @@ typedef struct FooU8 {

typedef struct FooU8 Boo;

typedef enum Dog_Tag {
DogWoof,
} Dog_Tag;

typedef struct Dog {
Dog_Tag tag;
union {
struct {
struct FooU8 woof;
};
};
} Dog;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void root(Boo x, enum Bar y);
void root(Boo x, enum Bar y, struct Dog z);

#ifdef __cplusplus
} // extern "C"
Expand Down
15 changes: 14 additions & 1 deletion tests/expectations/mangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,17 @@ typedef struct {

typedef FooU8 Boo;

void root(Boo x, Bar y);
typedef enum {
DogWoof,
} Dog_Tag;

typedef struct {
Dog_Tag tag;
union {
struct {
FooU8 woof;
};
};
} Dog;

void root(Boo x, Bar y, Dog z);
15 changes: 14 additions & 1 deletion tests/expectations/mangle.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,24 @@ typedef struct {

typedef FooU8 Boo;

typedef enum {
DogWoof,
} Dog_Tag;

typedef struct {
Dog_Tag tag;
union {
struct {
FooU8 woof;
};
};
} Dog;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

void root(Boo x, Bar y);
void root(Boo x, Bar y, Dog z);

#ifdef __cplusplus
} // extern "C"
Expand Down
18 changes: 17 additions & 1 deletion tests/expectations/mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,24 @@ struct Foo {

using Boo = Foo<uint8_t>;

template<typename T>
struct Dog {
enum class Tag {
DogWoof,
};

struct DogWoof_Body {
T _0;
};

Tag tag;
union {
DogWoof_Body woof;
};
};

extern "C" {

void root(Boo x, Bar y);
void root(Boo x, Bar y, Dog<Foo<uint8_t>> z);

} // extern "C"
9 changes: 8 additions & 1 deletion tests/expectations/mangle.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,11 @@ cdef extern from *:

ctypedef FooU8 Boo;

void root(Boo x, Bar y);
ctypedef enum Dog_Tag:
DogWoof,

ctypedef struct Dog:
Dog_Tag tag;
FooU8 woof;

void root(Boo x, Bar y, Dog z);