aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2015-12-17 14:14:54 +0100
committerLukas Larsson <[email protected]>2016-03-29 14:57:11 +0200
commit1bd56e2b5141a3afdca4e854e9b667807bf4e2f3 (patch)
tree0171c0a573a08068d7155ac73bcd6a6d3fc941d6
parent348f3f2ee2d2707e30658c3600e05309ad0e72bf (diff)
downloadotp-1bd56e2b5141a3afdca4e854e9b667807bf4e2f3.tar.gz
otp-1bd56e2b5141a3afdca4e854e9b667807bf4e2f3.tar.bz2
otp-1bd56e2b5141a3afdca4e854e9b667807bf4e2f3.zip
erts: Add enif_term_to_binary and enif_binary_to_term
-rw-r--r--erts/doc/src/erl_nif.xml24
-rw-r--r--erts/emulator/beam/erl_nif.c70
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h4
-rw-r--r--erts/emulator/test/nif_SUITE.erl25
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c53
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, &amp;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)