use quote::quote;
use syn::ItemEnum;
use crate::{Namer, structs::expand_type};
pub fn is_c_compatible_enum(item: &ItemEnum) -> bool {
item.generics.gt_token.is_none()
&& item
.variants
.iter()
.all(|v| matches!(v.fields, syn::Fields::Unit))
}
pub fn expand_enum(item: &ItemEnum) -> syn::Result<proc_macro2::TokenStream> {
if item.generics.gt_token.is_some() {
return Err(syn::Error::new_spanned(
&item.generics,
"generic enums are not supported by #[ezffi::export]",
));
}
if let Some(lt) = item.generics.lifetimes().next() {
return Err(syn::Error::new_spanned(
lt,
"lifetime parameters are not supported by #[ezffi::export]",
));
}
Ok(expand_type(&item.ident))
}
pub fn expand_c_enum(item: &ItemEnum) -> proc_macro2::TokenStream {
let rust_ty_name = &item.ident;
let c_ty_name = Namer::name_struct(rust_ty_name);
let variants = &item.variants;
let attrs = &item.attrs;
let has_repr = attrs.iter().any(|a| a.path().is_ident("repr"));
let repr = if has_repr {
quote! {}
} else {
quote! { #[repr(C)] }
};
quote! {
#[derive(Clone, Copy)]
#repr
#(#attrs)*
pub enum #c_ty_name {
#variants
}
pub type #rust_ty_name = #c_ty_name;
impl ::ezffi::RustRefIntoC<()> for #c_ty_name {
type C = #c_ty_name;
unsafe fn ref_into_c(&self) -> Self::C { *self }
}
impl ::ezffi::RustOwnedIntoC<()> for #c_ty_name {
type C = #c_ty_name;
unsafe fn owned_into_c(self) -> Self::C { self }
}
impl ::ezffi::CRefIntoRust<#c_ty_name> for #c_ty_name {
unsafe fn into_rust(&self) -> &#c_ty_name { self }
unsafe fn into_rust_mut(&mut self) -> &mut #c_ty_name { self }
}
impl ::ezffi::COwnedIntoRust<#c_ty_name> for #c_ty_name {
unsafe fn into_rust_owned(self) -> #c_ty_name { self }
}
}
}