diff options
-rw-r--r-- | erts/doc/src/erl_nif.xml | 24 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif.c | 70 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif_api_funcs.h | 4 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 25 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 53 |
5 files changed, 173 insertions, 3 deletions
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 6befdc124b..47d84bb813 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -655,6 +655,18 @@ typedef enum { have been allocated with <seealso marker="#enif_alloc_env">enif_alloc_env</seealso>. </p></desc> </func> + <func><name><ret>int</ret><nametext>enif_binary_to_term(ErlNifEnv *env, ErlNifBinary *bin, ERL_NIF_TERM *term)</nametext></name> + <fsummary>Convert a term from the external format</fsummary> + <desc> + <p>Returns a term that is the result of decoding <c>bin</c> + according to the Erlang external term format.</p> + <p>See also:</p> + <list> + <item><seealso marker="erlang#binary_to_term-1"><c>erlang:binary_to_term/1</c></seealso></item> + <item><seealso marker="#enif_term_to_binary"><c>enif_term_to_binary</c></seealso></item> + </list> + </desc> + </func> <func><name><ret>int</ret><nametext>enif_compare(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)</nametext></name> <fsummary>Compare two terms</fsummary> <desc><p>Return an integer less than, equal to, or greater than @@ -1599,6 +1611,18 @@ enif_map_iterator_destroy(env, &iter); <desc><p>Same as <seealso marker="erl_driver#driver_system_info">driver_system_info</seealso>. </p></desc> </func> + <func><name><ret>int</ret><nametext>enif_term_to_binary(ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *bin)</nametext></name> + <fsummary>Convert a term to the external format</fsummary> + <desc> + <p>Returns a binary data object that is the result of encoding <c>term</c> + according to the Erlang external term format.</p> + <p>See also:</p> + <list> + <item><seealso marker="erlang#term_to_binary-1"><c>erlang:term_to_binary/1</c></seealso></item> + <item><seealso marker="#enif_binary_to_term"><c>enif_binary_to_term</c></seealso></item> + </list> + </desc> + </func> <func><name><ret>int</ret><nametext>enif_thread_create(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts)</nametext></name> <fsummary></fsummary> <desc><p>Same as <seealso marker="erl_driver#erl_drv_thread_create">erl_drv_thread_create</seealso>. diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 8440fd26b5..21bf752bb6 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -638,6 +638,76 @@ unsigned char* enif_make_new_binary(ErlNifEnv* env, size_t size, return binary_bytes(*termp); } +int enif_term_to_binary(ErlNifEnv *dst_env, ERL_NIF_TERM term, + ErlNifBinary *bin) +{ + Sint size; + byte *bp; + Binary* refbin; + + size = erts_encode_ext_size(term); + if (!enif_alloc_binary(size, bin)) + return 0; + + refbin = bin->ref_bin; + + bp = bin->data; + + erts_encode_ext(term, &bp); + + bin->size = bp - bin->data; + refbin->orig_size = bin->size; + + ASSERT(bin->data + bin->size == bp); + + return 1; +} + +int enif_binary_to_term(ErlNifEnv *dst_env, ErlNifBinary *bin, + ERL_NIF_TERM *term) +{ + Sint size; + ErtsHeapFactory factory; + + if ((size = erts_decode_ext_size(bin->data, bin->size)) < 0) + return 0; + + if (size > 0) { + byte *bp; + + if (is_internal_pid(dst_env->proc->common.id)) { + flush_env(dst_env); + erts_factory_proc_prealloc_init(&factory, dst_env->proc, size); + cache_env(dst_env); + } else { + + /* this is guaranteed to create a heap fragment */ + if (!alloc_heap(dst_env, size)) + return 0; + + erts_factory_heap_frag_init(&factory, dst_env->heap_frag); + } + + bp = bin->data; + *term = erts_decode_ext(&factory, &bp); + + if (is_non_value(*term)) { + return 0; + } + + erts_factory_close(&factory); + } + else { + erts_factory_dummy_init(&factory); + *term = erts_decode_ext(&factory, &bin->data); + if (is_non_value(*term)) { + return 0; + } + ASSERT(is_immed(*term)); + } + return 1; +} + int enif_is_identical(Eterm lhs, Eterm rhs) { return EQ(lhs,rhs); diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index 21864c8b35..0333e95331 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -169,6 +169,8 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_unique_integer, (ErlNifEnv *env, E ERL_NIF_API_FUNC_DECL(int, enif_is_process_alive, (ErlNifEnv *env, ErlNifPid *pid)); ERL_NIF_API_FUNC_DECL(int, enif_is_port_alive, (ErlNifEnv *env, ErlNifPort *port_id)); ERL_NIF_API_FUNC_DECL(int, enif_get_local_port, (ErlNifEnv* env, ERL_NIF_TERM, ErlNifPort* port_id)); +ERL_NIF_API_FUNC_DECL(int, enif_term_to_binary, (ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *bin)); +ERL_NIF_API_FUNC_DECL(int, enif_binary_to_term, (ErlNifEnv *env, ErlNifBinary *bin, ERL_NIF_TERM *term)); /* ** ADD NEW ENTRIES HERE (before this comment) !!! @@ -330,6 +332,8 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*)); # define enif_is_process_alive ERL_NIF_API_FUNC_MACRO(enif_is_process_alive) # define enif_is_port_alive ERL_NIF_API_FUNC_MACRO(enif_is_port_alive) # define enif_get_local_port ERL_NIF_API_FUNC_MACRO(enif_get_local_port) +# define enif_term_to_binary ERL_NIF_API_FUNC_MACRO(enif_term_to_binary) +# define enif_binary_to_term ERL_NIF_API_FUNC_MACRO(enif_binary_to_term) /* ** ADD NEW ENTRIES HERE (before this comment) diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 3202986ce7..af25af9eeb 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -44,7 +44,8 @@ nif_nan_and_inf/1, nif_atom_too_long/1, nif_monotonic_time/1, nif_time_offset/1, nif_convert_time_unit/1, nif_now_time/1, nif_cpu_time/1, nif_unique_integer/1, - nif_is_process_alive/1, nif_is_port_alive/1 + nif_is_process_alive/1, nif_is_port_alive/1, + nif_term_to_binary/1, nif_binary_to_term/1 ]). -export([many_args_100/100]). @@ -77,7 +78,8 @@ all() -> nif_exception, nif_nan_and_inf, nif_atom_too_long, nif_monotonic_time, nif_time_offset, nif_convert_time_unit, nif_now_time, nif_cpu_time, nif_unique_integer, - nif_is_process_alive, nif_is_port_alive + nif_is_process_alive, nif_is_port_alive, + nif_term_to_binary, nif_binary_to_term ]. init_per_testcase(_Case, Config) -> @@ -1958,6 +1960,23 @@ nif_is_port_alive(Config) -> port_close(Port), false = is_port_alive_nif(Port). +nif_term_to_binary(Config) -> + ensure_lib_loaded(Config), + T = {#{ok => nok}, <<0:8096>>, lists:seq(1,100)}, + Bin = term_to_binary(T), + ct:log("~p",[Bin]), + Bin = term_to_binary_nif(T, undefined), + true = term_to_binary_nif(T, self()), + receive Bin -> ok end. + +nif_binary_to_term(Config) -> + ensure_lib_loaded(Config), + T = {#{ok => nok}, <<0:8096>>, lists:seq(1,100)}, + Bin = term_to_binary(T), + T = binary_to_term_nif(Bin, undefined), + true = binary_to_term_nif(Bin, self()), + receive T -> ok end. + %% The NIFs: lib_version() -> undefined. call_history() -> ?nif_stub. @@ -2018,6 +2037,8 @@ call_nif_atom_too_long(_) -> ?nif_stub. unique_integer_nif(_) -> ?nif_stub. is_process_alive_nif(_) -> ?nif_stub. is_port_alive_nif(_) -> ?nif_stub. +term_to_binary_nif(_, _) -> ?nif_stub. +binary_to_term_nif(_, _) -> ?nif_stub. %% maps is_map_nif(_) -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 2ce0168788..9db7614405 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -2030,6 +2030,55 @@ static ERL_NIF_TERM is_port_alive(ErlNifEnv* env, int argc, const ERL_NIF_TERM a return atom_false; } +static ERL_NIF_TERM term_to_binary(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary bin; + ErlNifPid pid; + ErlNifEnv *msg_env = env; + ERL_NIF_TERM term; + + if (enif_get_local_pid(env, argv[1], &pid)) + msg_env = enif_alloc_env(); + + if (!enif_term_to_binary(msg_env, argv[0], &bin)) + return enif_make_badarg(env); + + term = enif_make_binary(msg_env, &bin); + + if (msg_env != env) { + enif_send(env, &pid, msg_env, term); + enif_free_env(msg_env); + return atom_true; + } else { + return term; + } +} + +static ERL_NIF_TERM binary_to_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary bin; + ERL_NIF_TERM term; + ErlNifPid pid; + ErlNifEnv *msg_env = env; + + if (enif_get_local_pid(env, argv[1], &pid)) + msg_env = enif_alloc_env(); + + if (!enif_inspect_binary(env, argv[0], &bin)) + return enif_make_badarg(env); + + if (!enif_binary_to_term(env, &bin, &term)) + return enif_make_badarg(env); + + if (msg_env != env) { + enif_send(env, &pid, msg_env, term); + enif_free_env(msg_env); + return atom_true; + } else { + return term; + } +} + static ErlNifFunc nif_funcs[] = { {"lib_version", 0, lib_version}, @@ -2107,7 +2156,9 @@ static ErlNifFunc nif_funcs[] = {"cpu_time", 0, cpu_time}, {"unique_integer_nif", 1, unique_integer}, {"is_process_alive_nif", 1, is_process_alive}, - {"is_port_alive_nif", 1, is_port_alive} + {"is_port_alive_nif", 1, is_port_alive}, + {"term_to_binary_nif", 2, term_to_binary}, + {"binary_to_term_nif", 2, binary_to_term} }; ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload) |