use derive_utils::quick_derive as enum_derive;
use proc_macro2::{Span, TokenStream};
use proc_quote::quote;
use quote::ToTokens;
fn crate_name() -> TokenStream {
match proc_macro_crate::crate_name("hobo") {
Err(_) | Ok(proc_macro_crate::FoundCrate::Itself) => quote! { crate },
Ok(proc_macro_crate::FoundCrate::Name(x)) => { let hobo = syn::Ident::new(&x, Span::call_site()); quote! { ::#hobo } },
}
}
#[proc_macro_derive(AsEntity)]
pub fn derive_as_entity(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let crate_name = crate_name();
let input = syn::parse_macro_input!(input as syn::DeriveInput);
match &input.data {
syn::Data::Enum(_) => enum_derive! {
input.to_token_stream(),
::hobo_core::entity::AsEntity,
trait AsEntity {
fn as_entity(&self) -> ::hobo_core::entity::Entity;
}
},
syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => {
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
(quote! {
impl #impl_generics #crate_name::entity::AsEntity for #name #ty_generics #where_clause {
fn as_entity(&self) -> #crate_name::entity::Entity { self.element.as_entity() }
}
}).into()
},
syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Unnamed(_), .. }) => {
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
(quote! {
impl #impl_generics #crate_name::entity::AsEntity for #name #ty_generics #where_clause {
fn as_entity(&self) -> #crate_name::entity::Entity { self.0.as_entity() }
}
}).into()
},
_ => unimplemented!(),
}
}
#[proc_macro_derive(Element)]
pub fn derive_element(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let crate_name = crate_name();
let as_entity: TokenStream = derive_as_entity(input.clone()).into();
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
(quote! {
#as_entity
impl #impl_generics #crate_name::Element for #name #ty_generics #where_clause {}
}).into()
}