Skip to content

Commit

Permalink
Merge pull request #103 from Dav1dde/invalid-variants
Browse files Browse the repository at this point in the history
Replaces invalid enum identifiers with generated ones
  • Loading branch information
clux authored Nov 12, 2022
2 parents c4493df + 51e2737 commit ab0e33f
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 80 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ quote = "1.0.10"
serde = { version = "1.0.130", features = ["derive"] }
serde_yaml = "0.8.23"
heck = "0.4.0"
syn = "1.0.103"

[dependencies.kube]
version = "0.76.0"
Expand Down
56 changes: 0 additions & 56 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,3 @@ mod analyzer;
pub use analyzer::analyze;
mod output;
pub use output::{Container, Member, Output};

// synced from https://doc.rust-lang.org/reference/keywords.html feb 2022
pub const KEYWORDS: [&str; 52] = [
"as",
"break",
"const",
"continue",
"crate",
"else",
"enum",
"extern",
"false",
"fn",
"for",
"if",
"impl",
"in",
"let",
"loop",
"match",
"mod",
"move",
"mut",
"pub",
"ref",
"return",
"self",
"Self",
"static",
"struct",
"super",
"trait",
"true",
"type",
"unsafe",
"use",
"where",
"while",
"async",
"await",
"dyn",
"abstract",
"become",
"box",
"do",
"final",
"macro",
"override",
"priv",
"typeof",
"unsized",
"virtual",
"yield",
"try",
"macro_rules",
];
15 changes: 4 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clap::{CommandFactory, Parser, Subcommand};
use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::{
CustomResourceDefinition, CustomResourceDefinitionVersion, CustomResourceSubresources,
};
use kopium::{analyze, Container, KEYWORDS};
use kopium::{analyze, Container};
use kube::{api, core::Version, Api, Client, ResourceExt};
use quote::format_ident;

Expand Down Expand Up @@ -230,23 +230,16 @@ impl Kopium {
if !m.serde_annot.is_empty() {
println!(" #[serde({})]", m.serde_annot.join(", "));
}
let safe_name = if KEYWORDS.contains(&m.name.as_ref()) {
format_ident!("r#{}", m.name)
} else if s.is_enum && m.name.parse::<u64>().is_ok() {
// sanitize numeric enum variant names from golang
format_ident!("r#_{}", m.name)
} else {
format_ident!("{}", m.name)
};
let name = format_ident!("{}", m.name);
for annot in &m.extra_annot {
println!(" {}", annot);
}
let spec_trimmed_type = m.type_.as_str().replace(&format!("{}Spec", kind), kind);
if s.is_enum {
// NB: only supporting plain enumerations atm, not oneOf
println!(" {},", safe_name);
println!(" {},", name);
} else {
println!(" pub {}: {},", safe_name, spec_trimmed_type);
println!(" pub {}: {},", name, spec_trimmed_type);
}
}
println!("}}");
Expand Down
56 changes: 43 additions & 13 deletions src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,31 @@ impl Container {
impl Container {
/// Rename all struct members to rust conventions
pub fn rename(&mut self) {
for m in &mut self.members {
if self.is_enum {
let pascald = m.name.to_pascal_case();
if pascald != m.name {
m.serde_annot.push(format!("rename = \"{}\"", m.name));
}
m.name = pascald;
for (i, m) in self.members.iter_mut().enumerate() {
let new_name = if self.is_enum {
// There are no rust keywords that start uppercase,
// making this name always a valid identifier except if it contains
// or starts with an invalid character.
//
// `` -> `KopiumEmpty`
// `mod` -> `Mod`
// `301` -> `301` -> `r#301` -> `r#_301`
// `!=` -> `!=` -> `r#!=` -> `r#_!=` -> `KopiumVariant{i}`
let name = if m.name.is_empty() {
"KopiumEmpty".to_owned()
} else {
m.name.to_pascal_case()
};

Container::try_esacape_name(name).unwrap_or_else(|| format!("KopiumVariant{i}"))
} else {
// regular container
let snaked = m.name.to_snake_case();
if snaked != m.name {
m.serde_annot.push(format!("rename = \"{}\"", m.name));
}
m.name = snaked;
Container::try_esacape_name(m.name.to_snake_case())
.unwrap_or_else(|| panic!("invalid field name '{}' could not be escaped", m.name))
};

if new_name != m.name {
m.serde_annot.push(format!("rename = \"{}\"", m.name));
m.name = new_name;
}
}
}
Expand All @@ -106,6 +117,25 @@ impl Container {
}
}
}

/// Tries to escape a field or variant name into a valid Rust identifier.
fn try_esacape_name(name: String) -> Option<String> {
if syn::parse_str::<syn::Ident>(&name).is_ok() {
return Some(name);
}

let escaped_name = format!("r#{name}");
if syn::parse_str::<syn::Ident>(&escaped_name).is_ok() {
return Some(escaped_name);
}

let escaped_name = format!("r#_{name}");
if syn::parse_str::<syn::Ident>(&escaped_name).is_ok() {
return Some(escaped_name);
}

None
}
}

impl Output {
Expand Down

0 comments on commit ab0e33f

Please sign in to comment.