use darling::ast::NestedMeta;
use heck::ToSnakeCase;
use proc_macro_error::abort;
use proc_macro_error::abort_call_site;
use syn::parse::Parser;
use syn::punctuated::Punctuated;
use syn::{Fields, Token};
pub fn to_snake_case(name: Option<String>, v_ident: &syn::Ident) -> String {
match name {
Some(s) => s,
None => v_ident.to_string().to_snake_case(),
}
}
pub fn ignore_enum_data(fields: &Fields) -> proc_macro2::TokenStream {
match fields {
Fields::Named(_) => quote::quote! {{..}},
Fields::Unit => quote::quote! {},
Fields::Unnamed(_) => quote::quote! {(_)},
}
}
pub fn get_unit_ident(attrs: &[syn::Attribute]) -> syn::Ident {
attrs
.iter()
.find(|a| {
a.path()
.segments
.last()
.is_some_and(|s| s.ident == "unit_enum")
})
.and_then(|a| darling::util::parse_attribute_to_meta_list(a).ok())
.and_then(|syn::MetaList { path, tokens, .. }| {
let Ok(nested) = Punctuated::<NestedMeta, Token![,]>::parse_terminated.parse2(tokens)
else {
return None;
};
nested
.first()
.filter(|_| path.is_ident("unit_enum"))
.and_then(|f| match f {
NestedMeta::Meta(syn::Meta::Path(path)) => path.get_ident().cloned(),
_ => None,
})
})
.unwrap_or_else(|| {
abort_call_site!("macro requires attribute `unit_enum`.";
help = "Add attribute like `unit_enum(UnitEnumName)`")
})
}
pub fn index_to_u8(index: usize) -> u8 {
match u8::try_from(index) {
Ok(i) => i,
Err(_) => abort_call_site!("Can only have a maximum of 255 enum variants"),
}
}
pub fn get_single_tuple_variant<'a>(ident: &syn::Ident, fields: &'a syn::Fields) -> &'a syn::Field {
match fields {
syn::Fields::Named(_) | syn::Fields::Unit => abort!(
ident,
"hdk_entry_types_conversions only works for tuple enums"
),
syn::Fields::Unnamed(syn::FieldsUnnamed { unnamed, .. }) => unnamed
.first()
.filter(|_| unnamed.len() == 1)
.unwrap_or_else(|| {
abort!(
unnamed,
"hdk_entry_types_conversions must only have a single enum tuple"
);
}),
}
}
pub fn get_return_type_ident(ty: &syn::Type) -> Option<syn::Ident> {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
return Some(segment.ident.clone());
}
}
None
}
pub fn is_extern_result_callback_result(ty: &syn::Type, callback_result: &str) -> bool {
if let syn::Type::Path(type_path) = ty {
if let Some(segment) = type_path.path.segments.last() {
if segment.ident == "ExternResult" {
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(syn::GenericArgument::Type(syn::Type::Tuple(t))) = args.args.first()
{
return t.elems.is_empty() && callback_result == "()";
}
if let Some(syn::GenericArgument::Type(syn::Type::Path(inner_path))) =
args.args.first()
{
if let Some(inner_segment) = inner_path.path.segments.last() {
return inner_segment.ident == callback_result;
}
}
}
}
}
}
false
}