From b349b4db0fb742774d465de05eb877601790c08e Mon Sep 17 00:00:00 2001 From: Robert Kovacsics Date: Fri, 9 Dec 2022 22:13:13 +0000 Subject: [PATCH 1/2] Allow arbitrary NIF names (e.g. those ending with `!` or `?`) To use, do ```rust \#[nif(name = "foo!")] fn foo_bang(...) -> ... { ... } ``` --- rustler_codegen/src/nif.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rustler_codegen/src/nif.rs b/rustler_codegen/src/nif.rs index 27514cee..fed2d110 100644 --- a/rustler_codegen/src/nif.rs +++ b/rustler_codegen/src/nif.rs @@ -15,16 +15,14 @@ pub fn transcoder_decorator(args: syn::AttributeArgs, fun: syn::ItemFn) -> Token let arity = arity(inputs.clone()); let decoded_terms = extract_inputs(inputs.clone()); let argument_names = create_function_params(inputs.clone()); - let erl_func_name = extract_attr_value(args, "name") - .map(|ref n| syn::Ident::new(n, Span::call_site())) - .unwrap_or_else(|| name.clone()); + let erl_func_name = extract_attr_value(args, "name").unwrap_or_else(|| name.to_string()); quote! { #[allow(non_camel_case_types)] pub struct #name; impl rustler::Nif for #name { - const NAME: *const u8 = concat!(stringify!(#erl_func_name), "\0").as_ptr() as *const u8; + const NAME: *const u8 = concat!(#erl_func_name, "\0").as_ptr() as *const u8; const ARITY: u32 = #arity; const FLAGS: u32 = #flags as u32; const RAW_FUNC: unsafe extern "C" fn( From caefd14d1d7394fca7b5f65fd35e8852f5c9afbf Mon Sep 17 00:00:00 2001 From: Robert Kovacsics Date: Mon, 12 Dec 2022 18:53:19 +0000 Subject: [PATCH 2/2] Restrict erlang function names to latin1 encoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From https://www.erlang.org/doc/apps/stdlib/unicode_usage.html > Erlang drivers and NIF-shared objects still cannot be named with names > containing code points > 127. This limitation will be removed in a > future release. However, Erlang modules can, but it is definitely not a > good idea and is still considered experimental. While I believe this refers to file-names this also seems to apply to function names, otherwise you get: {:error, {:bad_lib, [70, 117, 110, 99, 116, 105, ...]}} With this, if you try to do it, you get at compile-time the following error: ❯ mix compile Compiling 1 file (.ex) Compiling crate nif in debug mode (native/nif) Compiling nif v0.1.0 (/home/rmk/programming/rust/rustler_raise_error/native/nif) error: custom attribute panicked --> src/lib.rs:76:1 | 76 | #[nif(name = "🧀")] | ^^^^^^^^^^^^^^^^^^^ | = help: message: NIF names need to be Latin-1 encoded error[E0433]: failed to resolve: use of undeclared crate or module `cheese` --> src/lib.rs:90:9 | 90 | cheese | ^^^^^^ use of undeclared crate or module `cheese` For more information about this error, try `rustc --explain E0433`. error: could not compile `nif` due to 2 previous errors == Compilation error in file lib/nif.ex == ** (RuntimeError) Rust NIF compile error (rustc exit code 101) (rustler 0.26.0) lib/rustler/compiler.ex:41: Rustler.Compiler.compile_crate/2 lib/nif.ex:2: (module) --- rustler_codegen/src/nif.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rustler_codegen/src/nif.rs b/rustler_codegen/src/nif.rs index fed2d110..9c816678 100644 --- a/rustler_codegen/src/nif.rs +++ b/rustler_codegen/src/nif.rs @@ -17,6 +17,12 @@ pub fn transcoder_decorator(args: syn::AttributeArgs, fun: syn::ItemFn) -> Token let argument_names = create_function_params(inputs.clone()); let erl_func_name = extract_attr_value(args, "name").unwrap_or_else(|| name.to_string()); + for chr in erl_func_name.chars() { + if chr > '\x7f' { + panic!("NIF names need to be Latin-1 encoded") + } + } + quote! { #[allow(non_camel_case_types)] pub struct #name;