use proc_macro2::Span;
pub fn option_inner_type(ty: &syn::Type) -> Option<syn::Type> {
generic_inner(ty, "Option")
}
pub fn vec_inner_type(ty: &syn::Type) -> Option<syn::Type> {
generic_inner(ty, "Vec")
}
fn generic_inner(ty: &syn::Type, wrapper: &str) -> Option<syn::Type> {
let syn::Type::Path(tp) = ty else { return None };
let seg = tp.path.segments.last()?;
if seg.ident != wrapper {
return None;
}
let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
return None;
};
match ab.args.first()? {
syn::GenericArgument::Type(inner) => Some(inner.clone()),
_ => None,
}
}
pub fn path_tail_ident(ty: &syn::Type) -> Option<syn::Ident> {
match ty {
syn::Type::Path(tp) => tp.path.segments.last().map(|s| s.ident.clone()),
_ => None,
}
}
fn path_tail_is(ty: &syn::Type, name: &str) -> bool {
path_tail_ident(ty).is_some_and(|i| i == name)
}
pub fn is_result_type(ty: &syn::Type) -> bool {
path_tail_is(ty, "Result")
}
pub fn result_parts(ty: &syn::Type) -> Option<(syn::Type, syn::Type)> {
let syn::Type::Path(tp) = ty else { return None };
let seg = tp.path.segments.last()?;
if seg.ident != "Result" {
return None;
}
let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
return None;
};
let mut args = ab.args.iter().filter_map(|a| match a {
syn::GenericArgument::Type(t) => Some(t.clone()),
_ => None,
});
let ok = args.next()?;
let err = args.next()?;
Some((ok, err))
}
pub fn result_ok_type(ty: &syn::Type) -> Option<syn::Type> {
result_parts(ty).map(|(ok, _)| ok)
}
pub fn bare_path_ident(ty: &syn::Type) -> Option<syn::Ident> {
let syn::Type::Path(tp) = ty else { return None };
let seg = tp.path.segments.last()?;
if !matches!(seg.arguments, syn::PathArguments::None) {
return None;
}
Some(seg.ident.clone())
}
pub fn ident(s: &str) -> syn::Ident {
syn::Ident::new(s, Span::call_site())
}
pub fn pascal_to_snake(s: &str) -> String {
let mut out = String::new();
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
}
#[cfg(test)]
mod tests;