Skip to content

Commit

Permalink
Add preencoded JSON support.
Browse files Browse the repository at this point in the history
  • Loading branch information
David Hull committed Mar 14, 2017
1 parent 06aaf44 commit a132437
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 38 deletions.
115 changes: 78 additions & 37 deletions c_src/encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,33 @@ enc_string(Encoder* e, ERL_NIF_TERM val)
return 1;
}

static inline int
enc_json(Encoder* e, ERL_NIF_TERM val)
{
ErlNifBinary bin;
unsigned char* data;
size_t size;

if(!enif_is_binary(e->env, val)) {
return 0;
}
if(!enif_inspect_binary(e->env, val, &bin)) {
return 0;
}
data = bin.data;
size = bin.size;

if(!enc_ensure(e, size + 2)) {
return 0;
}

memcpy(e->p + e->i, data, size);
e->i += size;
e->count++;

return 1;
}

static inline int
enc_long(Encoder* e, ErlNifSInt64 val)
{
Expand Down Expand Up @@ -783,48 +810,62 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto done;
}
} else if(enif_get_tuple(env, curr, &arity, &tuple)) {
if(arity != 1) {
ret = enc_obj_error(e, "invalid_ejson", curr);
goto done;
}
if(!enif_is_list(env, tuple[0])) {
ret = enc_obj_error(e, "invalid_object", curr);
goto done;
}
if(!enc_start_object(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
if(enif_is_empty_list(env, tuple[0])) {
if(!enc_end_object(e)) {
if(arity == 1) {
if(!enif_is_list(env, tuple[0])) {
ret = enc_obj_error(e, "invalid_object", curr);
goto done;
}
if(!enc_start_object(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
continue;
}
if(!enif_get_list_cell(env, tuple[0], &item, &curr)) {
ret = enc_error(e, "internal_error");
goto done;
}
if(!enif_get_tuple(env, item, &arity, &tuple)) {
ret = enc_obj_error(e, "invalid_object_member", item);
goto done;
}
if(arity != 2) {
ret = enc_obj_error(e, "invalid_object_member_arity", item);
goto done;
}
if(!enc_string(e, tuple[0])) {
ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]);
goto done;
}
if(!enc_colon(e)) {
ret = enc_error(e, "internal_error");
if(enif_is_empty_list(env, tuple[0])) {
if(!enc_end_object(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
continue;
}
if(!enif_get_list_cell(env, tuple[0], &item, &curr)) {
ret = enc_error(e, "internal_error");
goto done;
}
if(!enif_get_tuple(env, item, &arity, &tuple)) {
ret = enc_obj_error(e, "invalid_object_member", item);
goto done;
}
if(arity != 2) {
ret = enc_obj_error(e, "invalid_object_member_arity", item);
goto done;
}
if(!enc_string(e, tuple[0])) {
ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]);
goto done;
}
if(!enc_colon(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
stack = enif_make_list_cell(env, curr, stack);
stack = enif_make_list_cell(env, e->atoms->ref_object, stack);
stack = enif_make_list_cell(env, tuple[1], stack);
} else if(arity == 2) {
if(enif_compare(tuple[0], e->atoms->atom_json) != 0) {
ret = enc_obj_error(e, "invalid_ejson", curr);
goto done;
}
if(!enif_is_binary(env, tuple[1])) {
ret = enc_obj_error(e, "invalid_json_string", curr);
goto done;
}
if(!enc_json(e, tuple[1])) {
ret = enc_error(e, "internal_error");
goto done;
}
} else {
ret = enc_obj_error(e, "invalid_ejson", curr);
goto done;
}
stack = enif_make_list_cell(env, curr, stack);
stack = enif_make_list_cell(env, e->atoms->ref_object, stack);
stack = enif_make_list_cell(env, tuple[1], stack);
#if MAP_TYPE_PRESENT
} else if(enif_is_map(env, curr)) {
if(!enc_map_to_ejson(env, curr, &curr)) {
Expand Down
1 change: 1 addition & 0 deletions c_src/jiffy.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
st->atom_null = make_atom(env, "null");
st->atom_true = make_atom(env, "true");
st->atom_false = make_atom(env, "false");
st->atom_json = make_atom(env, "json");
st->atom_bignum = make_atom(env, "bignum");
st->atom_bignum_e = make_atom(env, "bignum_e");
st->atom_bigdbl = make_atom(env, "bigdbl");
Expand Down
1 change: 1 addition & 0 deletions c_src/jiffy.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ typedef struct {
ERL_NIF_TERM atom_null;
ERL_NIF_TERM atom_true;
ERL_NIF_TERM atom_false;
ERL_NIF_TERM atom_json;
ERL_NIF_TERM atom_bignum;
ERL_NIF_TERM atom_bignum_e;
ERL_NIF_TERM atom_bigdbl;
Expand Down
5 changes: 4 additions & 1 deletion src/jiffy.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
| json_string()
| json_number()
| json_object()
| json_array().
| json_array()
| json_preencoded().

-type json_array() :: [json_value()].
-type json_string() :: atom() | binary().
Expand All @@ -33,6 +34,8 @@

-endif.

-type json_preencoded() :: {'json', JSON::binary()}.

-type jiffy_decode_result() :: json_value()
| {has_trailer, json_value(), binary()}.

Expand Down
53 changes: 53 additions & 0 deletions test/jiffy_16_preencode_tests.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
-module(jiffy_16_preencode_tests).


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


preencode_success_test_() ->
[gen(ok, Case) || Case <- cases(ok)].


preencode_failure_test_() ->
[gen(error, Case) || Case <- cases(error)].


gen(ok, {E1, J, E2}) ->
{msg("~p", [E1]), [
{"Encode", ?_assertEqual(J, enc(E1))},
{"Decode", ?_assertEqual(E2, dec(J))}
]};

gen(error, E) ->
{msg("Error: ~p", [E]), [
?_assertThrow({error, _}, enc(E))
]}.


cases(ok) ->
TopTests =
lists:map(
fun (EJSON) ->
JSON = enc(EJSON),
{{json, JSON}, JSON, EJSON}
end, [ 123
, <<"hello world">>
, true
, false
, {[ {<<"a">>, <<"apple">>}, {<<"b">>, <<"banana">>} ]}
]),
EJSON = [ 1, <<"a">> ],
JSON = enc(EJSON),
BuriedTests =
[ { [ {json, JSON} ], <<"[[1,\"a\"]]">>, [ EJSON ]}
, { [ 1, {json, JSON}, 3 ], <<"[1,[1,\"a\"],3]">>, [ 1, EJSON, 3 ]}
, { [ {json, JSON}, {json, JSON} ], <<"[[1,\"a\"],[1,\"a\"]]">>, [ EJSON, EJSON ]}
, { {[ {<<"a">>, {json, JSON}} ]}, <<"{\"a\":[1,\"a\"]}">>, {[ {<<"a">>, EJSON} ]}}
],
TopTests ++ BuriedTests;

cases(error) ->
[ {json, true}
, {json, "true"}
].

0 comments on commit a132437

Please sign in to comment.