pub fn role_override(attrs: &[syn::Attribute]) -> Option<proc_macro2::TokenStream> {
let mut found = None;
for attr in attrs {
if !attr.path().is_ident("hex") {
continue;
}
let _ = attr.parse_nested_meta(|meta| {
if meta.path.is_ident("role") {
let value = meta.value()?;
let lit: syn::LitStr = value.parse()?;
let ident = syn::Ident::new(&lit.value(), lit.span());
found = Some(quote::quote!(::hexser::graph::Role::#ident));
}
Ok(())
});
}
found
}
pub fn registrable_and_submit(
input: &syn::DeriveInput,
derive_name: &str,
layer: proc_macro2::TokenStream,
role: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
let name = &input.ident;
let is_generic = !input.generics.params.is_empty();
let generics = {
let mut g = input.generics.clone();
if is_generic {
let (_, ty_generics, _) = input.generics.split_for_impl();
let self_ty: syn::Type = syn::parse_quote!(#name #ty_generics);
g.make_where_clause()
.predicates
.push(syn::parse_quote!(#self_ty: 'static));
}
g
};
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let registrable = quote::quote! {
impl #impl_generics ::hexser::registry::Registrable for #name #ty_generics #where_clause {
fn node_info() -> ::hexser::registry::NodeInfo {
::hexser::registry::NodeInfo {
layer: #layer,
role: #role,
type_name: ::std::any::type_name::<Self>(),
module_path: ::std::module_path!(),
}
}
fn dependencies() -> ::std::vec::Vec<::hexser::graph::NodeId> {
::std::vec::Vec::new()
}
}
};
let submission = if is_generic {
let message = format!(
"`#[derive({derive_name})]` cannot register a generic type in the architecture graph, \
and will not skip it in silence: `inventory` submits one entry per component and \
`type_name::<Self>()` on a generic names a monomorphization chosen by a consumer crate, \
so there is no single honest node for this type (a lifetime or const parameter is \
likewise not in scope where the submission expands). Derive on a NON-GENERIC marker \
struct that stands for the component instead, e.g. `#[derive({derive_name})] struct \
{name}Component;`, and leave the generic type underived; or hand-write `impl \
hexser::registry::Registrable` on the generic and submit the instantiation you mean. \
This previously compiled: the type implemented `Registrable`, answered `node_info()`, \
and was never in the graph."
);
syn::Error::new_spanned(input, message).to_compile_error()
} else {
quote::quote! {
::hexser::inventory::submit! {
::hexser::registry::ComponentEntry::new::<#name>()
}
}
};
quote::quote! {
#registrable
#submission
}
}