Skip to content

Commit

Permalink
add attempt_atom flag
Browse files Browse the repository at this point in the history
add attempt_atom flag, which is compatable with

  jsx:decode(Bin, [{label, attempt_atom}])
  • Loading branch information
yjh0502 committed Dec 30, 2015
1 parent c65273f commit 3b338d9
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 2 deletions.
32 changes: 30 additions & 2 deletions c_src/decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ typedef struct {
int is_partial;
int return_maps;
int return_trailer;
int attempt_atom;
ERL_NIF_TERM null_term;

char* p;
Expand Down Expand Up @@ -82,6 +83,7 @@ dec_new(ErlNifEnv* env)
d->is_partial = 0;
d->return_maps = 0;
d->return_trailer = 0;
d->attempt_atom = 0;
d->null_term = d->atoms->atom_null;

d->p = NULL;
Expand Down Expand Up @@ -623,20 +625,41 @@ make_empty_object(ErlNifEnv* env, int ret_map)
return enif_make_tuple1(env, enif_make_list(env, 0));
}

ERL_NIF_TERM
key_attempt_atom(ErlNifEnv* env, ERL_NIF_TERM key) {
ERL_NIF_TERM keyatom;
ErlNifBinary keybin;
// maximum atom length is 255 bytes
char keybuf[256];

if(enif_inspect_binary(env, key, &keybin) && keybin.size < sizeof(keybuf)) {
memcpy(keybuf, keybin.data, keybin.size);
keybuf[keybin.size] = 0;
if(enif_make_existing_atom(env, keybuf, &keyatom, ERL_NIF_LATIN1)) {
return keyatom;
}
}
return key;
}

int
make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out, int ret_map)
make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out, int ret_map, int attempt_atom)
{
ERL_NIF_TERM ret;
ERL_NIF_TERM key;
ERL_NIF_TERM val;

#if MAP_TYPE_PRESENT

if(ret_map) {
ret = enif_make_new_map(env);
while(enif_get_list_cell(env, pairs, &val, &pairs)) {
if(!enif_get_list_cell(env, pairs, &key, &pairs)) {
assert(0 == 1 && "Unbalanced object pairs.");
}
if(attempt_atom) {
key = key_attempt_atom(env, key);
}
if(!enif_make_map_put(env, ret, key, val, &ret)) {
return 0;
}
Expand All @@ -651,6 +674,9 @@ make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out, int ret_map)
if(!enif_get_list_cell(env, pairs, &key, &pairs)) {
assert(0 == 1 && "Unbalanced object pairs.");
}
if(attempt_atom) {
key = key_attempt_atom(env, key);
}
val = enif_make_tuple2(env, key, val);
ret = enif_make_list_cell(env, val, ret);
}
Expand Down Expand Up @@ -720,6 +746,8 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->null_term = d->atoms->atom_nil;
} else if(get_null_term(env, val, &(d->null_term))) {
continue;
} else if(enif_compare(val, d->atoms->atom_attempt_atom) == 0) {
d->attempt_atom = 1;
} else {
return enif_make_badarg(env);
}
Expand Down Expand Up @@ -984,7 +1012,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
dec_pop(d, st_object);
dec_pop(d, st_value);
if(!make_object(env, curr, &val, d->return_maps)) {
if(!make_object(env, curr, &val, d->return_maps, d->attempt_atom)) {
ret = dec_error(d, "internal_object_error");
goto done;
}
Expand Down
1 change: 1 addition & 0 deletions c_src/jiffy.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
st->atom_use_nil = make_atom(env, "use_nil");
st->atom_null_term = make_atom(env, "null_term");
st->atom_escape_forward_slashes = make_atom(env, "escape_forward_slashes");
st->atom_attempt_atom = make_atom(env, "attempt_atom");

// Markers used in encoding
st->ref_object = make_atom(env, "$object_ref$");
Expand Down
1 change: 1 addition & 0 deletions c_src/jiffy.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ typedef struct {
ERL_NIF_TERM atom_use_nil;
ERL_NIF_TERM atom_null_term;
ERL_NIF_TERM atom_escape_forward_slashes;
ERL_NIF_TERM atom_attempt_atom;

ERL_NIF_TERM ref_object;
ERL_NIF_TERM ref_array;
Expand Down
1 change: 1 addition & 0 deletions src/jiffy.erl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
-type decode_option() :: return_maps
| use_nil
| return_trailer
| attempt_atom
| {null_term, any()}
| {bytes_per_iter, non_neg_integer()}
| {bytes_per_red, non_neg_integer()}.
Expand Down
32 changes: 32 additions & 0 deletions test/jiffy_16_attempt_atom_tests.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
% This file is part of Jiffy released under the MIT license.
% See the LICENSE file for more information.

-module(jiffy_16_attempt_atom_tests).

-include_lib("eunit/include/eunit.hrl").

attempt_atom_test_() ->
Opts = [attempt_atom],
_ = key_is_atom,
Cases = [
{<<"{\"key_no_atom\":1}">>, {[{<<"key_no_atom">>, 1}]}},
{<<"{\"key_is_atom\":1}">>, {[{key_is_atom, 1}]}}
],
{"Test attempt_atom", lists:map(fun({Data, Result}) ->
?_assertEqual(Result, jiffy:decode(Data, Opts))
end, Cases)}.

-ifndef(JIFFY_NO_MAPS).

attempt_atom_map_test_() ->
Opts = [attempt_atom, return_maps],
_ = key_is_atom,
Cases = [
{<<"{\"key_no_atom\":1}">>, #{<<"key_no_atom">> => 1}},
{<<"{\"key_is_atom\":1}">>, #{key_is_atom => 1}}
],
{"Test attempt_atom_map", lists:map(fun({Data, Result}) ->
?_assertEqual(Result, jiffy:decode(Data, Opts))
end, Cases)}.

-endif.

0 comments on commit 3b338d9

Please sign in to comment.