use proc_macro2::Span;
use syn::Ident;
pub fn factory_struct_name(trait_path: &str) -> Ident {
let last = last_segment(trait_path);
Ident::new(&format!("{last}Factory"), Span::call_site())
}
pub fn vtable_struct_name(trait_path: &str) -> Ident {
let last = last_segment(trait_path);
Ident::new(&format!("{last}VTable"), Span::call_site())
}
pub fn to_snake_path(path: &str) -> String {
path.split("::")
.map(camel_to_snake)
.collect::<Vec<_>>()
.join("__")
}
pub fn param_struct_name(method_name: &str) -> Ident {
let pascal = snake_to_pascal(method_name);
Ident::new(&format!("{pascal}Params"), Span::call_site())
}
pub fn last_segment_str(path: &str) -> &str {
path.rsplit("::").next().unwrap_or(path)
}
fn last_segment(path: &str) -> &str {
last_segment_str(path)
}
pub fn camel_to_snake(s: &str) -> String {
let mut out = String::with_capacity(s.len() + 4);
for (i, c) in s.chars().enumerate() {
if c.is_uppercase() {
if i > 0 {
out.push('_');
}
out.extend(c.to_lowercase());
} else {
out.push(c);
}
}
out
}
fn snake_to_pascal(s: &str) -> String {
s.split('_')
.map(|word| {
let mut chars = word.chars();
match chars.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
}
})
.collect()
}