diff --git a/rustler/src/resource/registration.rs b/rustler/src/resource/registration.rs index eeca24ce..2c761bcd 100644 --- a/rustler/src/resource/registration.rs +++ b/rustler/src/resource/registration.rs @@ -17,6 +17,7 @@ use std::ptr; pub struct Registration { get_type_id: fn() -> TypeId, get_type_name: fn() -> &'static str, + type_name: Option<&'static str>, init: ErlNifResourceTypeInit, } @@ -60,11 +61,19 @@ impl Registration { }, get_type_name: std::any::type_name::, get_type_id: TypeId::of::, + type_name: None, } .maybe_add_destructor_callback::() .maybe_add_down_callback::() } + pub const fn with_name(self, name: &'static str) -> Self { + Self { + type_name: Some(name), + ..self + } + } + const fn maybe_add_destructor_callback(self) -> Self { if T::IMPLEMENTS_DESTRUCTOR || std::mem::needs_drop::() { Self { @@ -104,7 +113,7 @@ impl Registration { } let type_id = (self.get_type_id)(); - let type_name = (self.get_type_name)(); + let type_name = self.type_name.unwrap_or_else(self.get_type_name); let res: Option<*const ErlNifResourceType> = unsafe { open_resource_type( diff --git a/rustler_codegen/src/lib.rs b/rustler_codegen/src/lib.rs index a5cd6d60..8399f49f 100644 --- a/rustler_codegen/src/lib.rs +++ b/rustler_codegen/src/lib.rs @@ -456,8 +456,15 @@ pub fn nif_untagged_enum(input: TokenStream) -> TokenStream { /// } /// ``` #[proc_macro_attribute] -pub fn resource_impl(_attr: TokenStream, item: TokenStream) -> TokenStream { +pub fn resource_impl(args: TokenStream, item: TokenStream) -> TokenStream { + let mut attributes = resource_impl::Attributes::default(); + + if !args.is_empty() { + let parser = syn::meta::parser(|meta| attributes.parse(meta)); + + syn::parse_macro_input!(args with parser); + } let input = syn::parse_macro_input!(item as syn::ItemImpl); - resource_impl::transcoder_decorator(input).into() + resource_impl::transcoder_decorator(attributes, input).into() } diff --git a/rustler_codegen/src/resource_impl.rs b/rustler_codegen/src/resource_impl.rs index 80ebe44f..1e8049af 100644 --- a/rustler_codegen/src/resource_impl.rs +++ b/rustler_codegen/src/resource_impl.rs @@ -1,8 +1,39 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use std::collections::HashSet; +use syn::{meta::ParseNestedMeta, LitBool, LitStr}; -pub fn transcoder_decorator(mut input: syn::ItemImpl) -> TokenStream { +pub struct Attributes { + register: bool, + name: Option, +} + +impl Default for Attributes { + fn default() -> Self { + Self { + register: true, + name: None, + } + } +} + +impl Attributes { + pub fn parse(&mut self, meta: ParseNestedMeta) -> syn::parse::Result<()> { + if meta.path.is_ident("register") { + let value: LitBool = meta.value()?.parse()?; + self.register = value.value; + Ok(()) + } else if meta.path.is_ident("name") { + let value: LitStr = meta.value()?.parse()?; + self.name = Some(value.value()); + Ok(()) + } else { + Err(meta.error("Unsupported macro attribute. Expecting register or name.")) + } + } +} + +pub fn transcoder_decorator(attrs: Attributes, mut input: syn::ItemImpl) -> TokenStream { // Should be `Resource` but will fail somewhere else anyway if it isn't. // let (_, _trait_path, _) = input.trait_.unwrap(); let type_path = match *input.self_ty { @@ -32,11 +63,23 @@ pub fn transcoder_decorator(mut input: syn::ItemImpl) -> TokenStream { input.items.push(impl_item); } - quote!( - #input + let mut res = quote!(#input); + + if attrs.register { + if let Some(name) = attrs.name { + res.extend(quote!( + rustler::codegen_runtime::inventory::submit!( + rustler::codegen_runtime::ResourceRegistration::new::<#type_path>().with_name(#name) + ); + )); + } else { + res.extend(quote!( + rustler::codegen_runtime::inventory::submit!( + rustler::codegen_runtime::ResourceRegistration::new::<#type_path>() + ); + )); + } + } - rustler::codegen_runtime::inventory::submit!( - rustler::codegen_runtime::ResourceRegistration::new::<#type_path>() - ); - ) + res } diff --git a/rustler_tests/native/rustler_test/src/test_resource.rs b/rustler_tests/native/rustler_test/src/test_resource.rs index 95f6771a..1dc13de9 100644 --- a/rustler_tests/native/rustler_test/src/test_resource.rs +++ b/rustler_tests/native/rustler_test/src/test_resource.rs @@ -14,7 +14,7 @@ pub struct TestMonitorResource { inner: Mutex, } -#[rustler::resource_impl(register = true)] +#[rustler::resource_impl(register = true, name = "monitor")] impl Resource for TestMonitorResource { fn down<'a>(&'a self, _env: Env<'a>, _pid: LocalPid, mon: Monitor) { let mut inner = self.inner.lock().unwrap();