rustler icon indicating copy to clipboard operation
rustler copied to clipboard

Make sure all relevant erl_nif functionality is represented in some way

Open hansihe opened this issue 9 years ago • 10 comments

If there is anything in particular you need, please comment below and we can work something out.

Primitives

Primitives are fully supported through Encoder.

  • [x] enif_get_double()
  • [x] enif_get_int()
  • [x] enif_get_int64()
  • [x] enif_get_long()
  • [x] enif_get_uint()
  • [x] enif_get_uint64()
  • [x] enif_get_ulong()
  • [x] enif_make_double()
  • [x] enif_make_int64()
  • [x] enif_make_long()
  • [x] enif_make_int()
  • [x] enif_make_uint()
  • [x] enif_make_uint64()
  • [x] enif_make_ulong()

Atoms

  • [x] enif_get_atom()
  • [ ] enif_get_atom_length() Will add if anyone has a legitimate use.
  • [ ] enif_make_existing_atom() N/A
  • [x] enif_make_existing_atom_len()
  • [ ] enif_make_atom() N/A
  • [x] enif_make_atom_len()

Lists

  • [x] enif_make_reverse_list() NifTerm::list_reverse()
  • [x] enif_get_list_cell() NifTerm::list_get_cell()
  • [x] enif_get_list_length() NifTerm::list_length()
  • [ ] enif_make_list()
  • [x] enif_make_list_from_array()
  • [x] enif_make_list_cell()
  • [ ] enif_make_string_len()

Char lists

  • [ ] enif_make_string()
  • [ ] enif_get_string()

Maps

  • [x] enif_get_map_size()
  • [x] enif_get_map_value()
  • [x] enif_make_map_put()
  • [x] enif_make_map_remove()
  • [x] enif_make_map_update()
  • [x] enif_map_iterator_create()
  • [x] enif_map_iterator_get_pair()
  • [ ] enif_map_iterator_is_head()
  • [ ] enif_map_iterator_is_tail()
  • [x] enif_map_iterator_next()
  • [ ] enif_map_iterator_prev()
  • [x] enif_map_iterator_destroy()
  • [x] enif_make_new_map()

Binaries

Supported through binary abstraction.

  • [x] enif_alloc_binary()
  • [x] enif_realloc_binary()
  • [x] enif_inspect_binary()
  • [x] enif_inspect_iolist_as_binary()
  • [x] enif_make_new_binary()
  • [x] enif_release_binary()
  • [x] enif_make_binary()
  • [x] enif_make_sub_binary()

Tuples

  • [x] enif_get_tuple()
  • [x] enif_make_tuple_from_array()
  • [ ] enif_make_tuple() N/A

Resources

Exposed through resource abstraction.

  • [x] enif_keep_resource()
  • [x] enif_get_resource()
  • [x] enif_sizeof_resource()
  • [x] enif_release_resource()
  • [x] enif_alloc_resource()
  • [x] enif_make_resource()
  • [x] enif_open_resource_type()
  • [ ] enif_make_resource_binary()

Misc terms

  • [ ] enif_make_pid()
  • [ ] enif_make_ref()
  • [ ] enif_get_local_pid()
  • [ ] enif_get_local_port()

Term utils

  • [x] enif_make_copy()
  • [x] enif_term_to_binary()
  • [x] enif_binary_to_term()
  • [x] enif_compare()
  • [x] enif_is_identical()
  • [x] enif_snprintf()
  • [ ] enif_port_command()
  • [ ] enif_is_port_alive()
  • [ ] enif_is_process_alive()

Type tests

Exposed as methods on NifTerm.

  • [x] enif_is_atom()
  • [x] enif_is_binary()
  • [x] enif_is_list()
  • [x] enif_is_pid()
  • [x] enif_is_port()
  • [x] enif_is_ref()
  • [x] enif_is_tuple()
  • [x] enif_is_empty_list()
  • [x] enif_is_exception()
  • [x] enif_is_fun()
  • [x] enif_is_map()
  • [x] enif_is_number()

Scheduling

  • [x] enif_consume_timeslice()
  • [ ] enif_schedule_nif() See this

Exceptions

  • [ ] enif_has_pending_exception() Useless for us since we don't expose raise_exception to the user.

Supported through rustler::Error. It is undesirable to expose these directly:

  • [x] enif_make_badarg()
  • [x] enif_raise_exception()

Env

  • [x] enif_free_env()
  • [x] enif_clear_env()
  • [x] enif_alloc_env()
  • [x] enif_self()
  • [x] enif_send() See this

Time

  • [ ] enif_cpu_time()
  • [ ] enif_now_time()
  • [ ] enif_monotonic_time()
  • [ ] enif_time_offset()
  • [ ] enif_convert_time_unit()

Misc

  • [ ] enif_getenv()
  • [ ] enif_alloc() N/A
  • [ ] enif_free() N/A
  • [ ] enif_priv_data() No plans to support.
  • [ ] enif_system_info()
  • [ ] enif_make_unique_integer()
  • [ ] enif_is_current_process_alive()

Threading

Rust has its own threading APIs. There are no plans to support this.

  • [ ] enif_rwlock_tryrlock()
  • [ ] enif_rwlock_tryrwlock()
  • [ ] enif_thread_create()
  • [ ] enif_thread_join()
  • [ ] enif_tsd_key_create()
  • [ ] enif_mutex_trylock()
  • [ ] enif_thread_type()
  • [ ] enif_equal_tids()
  • [ ] enif_cond_broadcast()
  • [ ] enif_cond_destroy()
  • [ ] enif_cond_signal()
  • [ ] enif_cond_wait()
  • [ ] enif_mutex_destroy()
  • [ ] enif_mutex_lock()
  • [ ] enif_mutex_unlock()
  • [ ] enif_rwlock_destroy()
  • [ ] enif_rwlock_rlock()
  • [ ] enif_rwlock_runlock()
  • [ ] enif_rwlock_rwlock()
  • [ ] enif_rwlock_rwunlock()
  • [ ] enif_thread_exit()
  • [ ] enif_thread_opts_destroy()
  • [ ] enif_tsd_key_destroy()
  • [ ] enif_tsd_set()
  • [ ] enif_tsd_get()
  • [ ] enif_cond_create()
  • [ ] enif_mutex_create()
  • [ ] enif_rwlock_create()
  • [ ] enif_thread_opts_create()
  • [ ] enif_thread_self()

hansihe avatar Dec 31 '16 17:12 hansihe

Problems

  • enif_send(): Documentation requires calling env to be passed when called within a NIF call. There is no way to enforce this at compile-time.
  • enif_schedule_nif(): Requires return value to be returned from the NIF call. There is no straightforward way to enforce this at compile-time.

Probably going to put these features under a cargo feature since they require additional caution from the user.

We might want to open an issue on OTP about these problems?

hansihe avatar Jan 01 '17 19:01 hansihe

For enif_send(), we can just always require an env. I'm not sure what kind of situation would lead a user to want to send a message without having an env handy.

jorendorff avatar Jan 09 '17 21:01 jorendorff

@jorendorff The erl_nif docs say: "env: The environment of the calling process. Must be NULL only if calling from a created thread"

This means that by not supplying an env when doing send from within a NIF call, we are technically breaking an API invariant.

hansihe avatar Jan 10 '17 12:01 hansihe

@hansihe We always supply an env, so I think we're OK.

jorendorff avatar Jan 11 '17 16:01 jorendorff

@jorendorff Just checked the current implementation. It is wrong.

The docs say the first env should be the env of the calling process if called from a nif, null if and only if from a calling thread. The second env should be the env the message term belongs to.

The message term env is never supposed to be passed as the first argument.

hansihe avatar Jan 11 '17 16:01 hansihe

You're right. We could fix it using thread-local storage; I don't see any other way.

jorendorff avatar Jan 11 '17 16:01 jorendorff

I checked the source a little while ago. They don't use the first env for anything other than to improve tracing functionality.

So, passing null always is fine with the current BEAM implementation. The question is if we want to take that risk, it might change in the future.

hansihe avatar Jan 11 '17 16:01 hansihe

It seems best to code to the documented API. I'll patch it.

jorendorff avatar Jan 11 '17 16:01 jorendorff

This API list hasn't been updated for quite a while and is missing all NIF API functions for OTP>=20.

filmor avatar Sep 19 '19 05:09 filmor

I wrote a small helper to find all documented NIF functions. The escript allows filtering by version prefix.

evnu avatar Feb 18 '20 22:02 evnu