Fix #418: Use heck for case conversion

All case conversion cases seem to be covered by this crate so this
greatly simplifies `rename.rs`.
This commit is contained in:
Vincent Tavernier 2020-04-17 15:42:23 +02:00 committed by Emilio Cobos Álvarez
parent 4beb526516
commit 8139fbf3c7
8 changed files with 46 additions and 170 deletions

16
Cargo.lock generated
View File

@ -35,6 +35,7 @@ name = "cbindgen"
version = "0.14.1"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -74,6 +75,14 @@ dependencies = [
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
@ -240,6 +249,11 @@ dependencies = [
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.7"
@ -287,6 +301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
@ -308,6 +323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"

View File

@ -23,6 +23,7 @@ tempfile = "3.0"
toml = "0.5"
proc-macro2 = "1"
quote = "1"
heck = "0.3"
[dependencies.syn]
version = "1.0.3"

View File

@ -139,10 +139,8 @@ impl EnumVariant {
discriminant,
body.map(|body| {
(
RenameRule::SnakeCase.apply_to_pascal_case(
&format!("{}", variant.ident),
IdentifierType::StructMember,
),
RenameRule::SnakeCase
.apply(&format!("{}", variant.ident), IdentifierType::StructMember),
body,
)
}),
@ -452,14 +450,11 @@ impl Item for Enum {
.iter()
.map(|variant| {
EnumVariant::new(
r.apply_to_pascal_case(
&variant.export_name,
IdentifierType::EnumVariant(self),
),
r.apply(&variant.export_name, IdentifierType::EnumVariant(self)),
variant.discriminant,
variant.body.as_ref().map(|body| {
(
r.apply_to_snake_case(&body.0, IdentifierType::StructMember),
r.apply(&body.0, IdentifierType::StructMember),
body.1.clone(),
)
}),
@ -769,7 +764,7 @@ impl Source for Enum {
.rename_args
.as_ref()
.unwrap_or(&RenameRule::GeckoCase)
.apply_to_snake_case(name, IdentifierType::FunctionArg)
.apply(name, IdentifierType::FunctionArg)
};
write!(out, "static {} {}(", self.export_name, variant.export_name);
@ -901,7 +896,7 @@ impl Source for Enum {
}
let other = if let Some(r) = config.function.rename_args {
r.apply_to_snake_case("other", IdentifierType::FunctionArg)
r.apply("other", IdentifierType::FunctionArg)
} else {
String::from("other")
};

View File

@ -159,12 +159,7 @@ impl Function {
self.args = self
.args
.iter()
.map(|x| {
(
r.apply_to_snake_case(&x.0, IdentifierType::FunctionArg),
x.1.clone(),
)
})
.map(|x| (r.apply(&x.0, IdentifierType::FunctionArg), x.1.clone()))
.collect()
}

View File

@ -310,7 +310,7 @@ impl Item for Struct {
}
} else if let Some(r) = find_first_some(&field_rules) {
for name in names {
*name = r.apply_to_snake_case(name, IdentifierType::StructMember);
*name = r.apply(name, IdentifierType::StructMember);
}
} else if self.tuple_struct {
// If there is a tag field, skip it
@ -489,7 +489,7 @@ impl Source for Struct {
.rename_args
.as_ref()
.unwrap_or(&RenameRule::GeckoCase)
.apply_to_snake_case(name, IdentifierType::FunctionArg)
.apply(name, IdentifierType::FunctionArg)
};
write!(out, "{}(", self.export_name());
let vec: Vec<_> = self
@ -516,7 +516,7 @@ impl Source for Struct {
}
let other = if let Some(r) = config.function.rename_args {
r.apply_to_snake_case("other", IdentifierType::FunctionArg)
r.apply("other", IdentifierType::FunctionArg)
} else {
String::from("other")
};

View File

@ -190,7 +190,7 @@ impl Item for Union {
.iter()
.map(|x| {
(
r.apply_to_snake_case(&x.0, IdentifierType::StructMember),
r.apply(&x.0, IdentifierType::StructMember),
x.1.clone(),
x.2.clone(),
)

View File

@ -114,6 +114,7 @@ impl<'a> Parser<'a> {
// If we have a whitelist, check it
if let Some(ref include) = self.config.parse.include {
if !include.contains(&pkg_name) {
debug!("Excluding crate {}", pkg_name);
return false;
}
}
@ -124,6 +125,7 @@ impl<'a> Parser<'a> {
fn parse_crate(&mut self, pkg: &PackageRef) -> Result<(), Error> {
assert!(self.lib.is_some());
debug!("Parsing crate {}", pkg.name);
self.parsed_crates.insert(pkg.name.clone());
// Check if we should use cargo expand for this crate

View File

@ -51,168 +51,35 @@ pub enum RenameRule {
}
impl RenameRule {
/// Applies the rename rule to a string that is formatted in PascalCase.
pub fn apply_to_pascal_case(self, text: &str, context: IdentifierType) -> String {
/// Applies the rename rule to a string
pub fn apply(self, text: &str, context: IdentifierType) -> String {
use heck::*;
if text.is_empty() {
return String::new();
}
match self {
RenameRule::None => String::from(text),
RenameRule::GeckoCase => context.to_str().to_owned() + text,
RenameRule::None => text.to_owned(),
RenameRule::GeckoCase => context.to_str().to_owned() + &text.to_camel_case(),
RenameRule::LowerCase => text.to_lowercase(),
RenameRule::UpperCase => text.to_uppercase(),
RenameRule::PascalCase => text.to_owned(),
RenameRule::CamelCase => text[..1].to_lowercase() + &text[1..],
RenameRule::SnakeCase => {
// Do not add additional `_` if the string already contains `_` e.g. `__Field`
// Do not split consecutive capital letters
let mut result = String::new();
let mut add_separator = true;
let mut prev_uppercase = false;
for (i, c) in text.char_indices() {
if c == '_' {
add_separator = false;
prev_uppercase = false;
}
if c.is_uppercase() {
if i != 0 && add_separator && !prev_uppercase {
result.push_str("_");
} else {
add_separator = true;
}
prev_uppercase = true;
} else {
prev_uppercase = false;
}
for x in c.to_lowercase() {
result.push(x);
}
}
result
}
RenameRule::ScreamingSnakeCase => {
// Same as SnakeCase code above, but uses to_uppercase
let mut result = String::new();
let mut add_separator = true;
let mut prev_uppercase = false;
for (i, c) in text.char_indices() {
if c == '_' {
add_separator = false;
prev_uppercase = false;
}
if c.is_uppercase() {
if i != 0 && add_separator && !prev_uppercase {
result.push_str("_");
} else {
add_separator = true;
}
prev_uppercase = true;
} else {
prev_uppercase = false;
}
for x in c.to_uppercase() {
result.push(x);
}
}
result
}
RenameRule::PascalCase => text.to_camel_case(),
RenameRule::CamelCase => text.to_mixed_case(),
RenameRule::SnakeCase => text.to_snake_case(),
RenameRule::ScreamingSnakeCase => text.to_shouty_snake_case(),
RenameRule::QualifiedScreamingSnakeCase => {
let mut result = String::new();
if let IdentifierType::EnumVariant(e) = context {
if let RenameRule::QualifiedScreamingSnakeCase = self {
result.push_str(
&RenameRule::ScreamingSnakeCase
.apply_to_pascal_case(e.path().name(), IdentifierType::Enum),
);
result.push_str("_");
}
result.push_str(
&RenameRule::ScreamingSnakeCase
.apply(e.path().name(), IdentifierType::Enum),
);
result.push_str("_");
}
result
.push_str(&RenameRule::ScreamingSnakeCase.apply_to_pascal_case(&text, context));
result
}
}
}
/// Applies the rename rule to a string that is formatted in snake_case.
pub fn apply_to_snake_case(self, mut text: &str, context: IdentifierType) -> String {
if text.is_empty() {
return String::new();
}
match self {
RenameRule::None => String::from(text),
RenameRule::GeckoCase => {
if &text[..1] == "_" {
text = &text[1..];
}
context.to_str().to_owned()
+ &RenameRule::PascalCase.apply_to_snake_case(text, context)
}
RenameRule::LowerCase => text.to_lowercase(),
RenameRule::UpperCase => text.to_uppercase(),
RenameRule::PascalCase => {
let mut result = String::new();
let mut is_uppercase = true;
for c in text.chars() {
if c == '_' {
is_uppercase = true;
continue;
}
if is_uppercase {
for x in c.to_uppercase() {
result.push(x);
}
is_uppercase = false;
} else {
result.push(c);
}
}
result
}
RenameRule::CamelCase => {
// Same as PascalCase code above, but is_uppercase = false to start
let mut result = String::new();
let mut is_uppercase = false;
for c in text.chars() {
if c == '_' {
is_uppercase = true;
continue;
}
if is_uppercase {
for x in c.to_uppercase() {
result.push(x);
}
is_uppercase = false;
} else {
result.push(c);
}
}
result
}
RenameRule::SnakeCase => text.to_owned(),
RenameRule::ScreamingSnakeCase => text.to_owned().to_uppercase(),
RenameRule::QualifiedScreamingSnakeCase => {
let mut result = String::new();
if let IdentifierType::EnumVariant(e) = context {
if let RenameRule::QualifiedScreamingSnakeCase = self {
result.push_str(
&RenameRule::ScreamingSnakeCase
.apply_to_snake_case(e.path().name(), IdentifierType::Enum),
);
result.push_str("_");
}
}
result
.push_str(&RenameRule::ScreamingSnakeCase.apply_to_snake_case(&text, context));
result.push_str(&RenameRule::ScreamingSnakeCase.apply(&text, context));
result
}
}