#![allow(dead_code)]
use std::collections::HashMap;
use heck::{ToPascalCase, ToSnakeCase};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
const RUST_KEYWORDS: &[&str] = &[
"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", "try", "typeof", "unsized", "virtual", "yield",
];
pub fn to_snake_case(name: &str) -> String {
name.to_snake_case()
}
pub fn to_pascal_case(name: &str) -> String {
name.to_pascal_case()
}
pub fn field_ident_with_rename(rust_snake: &str, original_json_name: &str) -> (Ident, Option<TokenStream>) {
let s = rust_snake;
if s == "self" {
return (
format_ident!("self_"),
Some(quote!(#[serde(rename = #original_json_name)])),
);
}
if RUST_KEYWORDS.iter().any(|&k| k == s) {
return (format_ident!("r#{}", s), None);
}
(format_ident!("{}", s), None)
}
pub fn escape_keyword(ident: &str) -> String {
let s = to_snake_case(ident);
if RUST_KEYWORDS.iter().any(|&k| k == s.as_str()) {
format!("r#{s}")
} else {
s
}
}
pub fn dedupe_field_names(names: &[String]) -> Vec<String> {
let mut counts: HashMap<String, usize> = HashMap::new();
let mut out = Vec::with_capacity(names.len());
for n in names {
let base = to_snake_case(n);
let entry = counts.entry(base.clone()).or_insert(0);
let resolved = if *entry == 0 {
base.clone()
} else {
format!("{base}_{}", *entry)
};
*entry += 1;
out.push(resolved);
}
out
}