Skip to content

Commit

Permalink
Add partial_encode/2 function.
Browse files Browse the repository at this point in the history
  • Loading branch information
David Hull committed Mar 16, 2017
1 parent f7831e6 commit 6801624
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 15 deletions.
27 changes: 18 additions & 9 deletions c_src/encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,16 +601,25 @@ enc_object_element(Encoder* e, int first, ERL_NIF_TERM curr, ERL_NIF_TERM* stack
if(!first && !enc_comma(e)) {
return enc_error(e, "internal_error");
}
if(!enc_string(e, tuple[0])) {
return enc_obj_error(e, "invalid_object_member_key", tuple[0]);
}
if(!enc_colon(e)) {
return enc_error(e, "internal_error");
if(enif_compare(tuple[0], e->atoms->atom_partial_object) == 0) {
if(!enc_unknown(e, tuple[1])) {
return enc_error(e, "internal_error");
}
stack = enif_make_list_cell(env, curr, stack);
stack = enif_make_list_cell(env, e->atoms->ref_object, stack);
*stackp = stack;
} else {
if(!enc_string(e, tuple[0])) {
return enc_obj_error(e, "invalid_object_member_key", tuple[0]);
}
if(!enc_colon(e)) {
return enc_error(e, "internal_error");
}
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);
*stackp = stack;
}
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);
*stackp = stack;
return 0;
}

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_partial_object = make_atom(env, "$partial_object$");
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_partial_object;
ERL_NIF_TERM atom_bignum;
ERL_NIF_TERM atom_bignum_e;
ERL_NIF_TERM atom_bigdbl;
Expand Down
23 changes: 18 additions & 5 deletions src/jiffy.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
% See the LICENSE file for more information.

-module(jiffy).
-export([decode/1, decode/2, encode/1, encode/2]).
-export([decode/1, decode/2, encode/1, encode/2, partial_encode/2]).
-define(NOT_LOADED, not_loaded(?LINE)).

-compile([no_native]).
Expand All @@ -19,17 +19,20 @@
| json_array()
| json_preencoded().

-type json_array() :: [json_value()].
-type json_array() :: [json_value()|json_partial_array()].
-type json_string() :: atom() | binary().
-type json_number() :: integer() | float().

-type json_partial_array() :: {'$partial_array$', iodata()}.
-type json_partial_object() :: {'$partial_object$', iodata()}.

-ifdef(JIFFY_NO_MAPS).

-type json_object() :: {[{json_string(),json_value()}]}.
-type json_object() :: {[({json_string(),json_value()})|json_partial_object()]}.

-else.

-type json_object() :: {[{json_string(),json_value()}]}
-type json_object() :: {[({json_string(),json_value()})|json_partial_object()]}
| #{json_string() => json_value()}.

-endif.
Expand Down Expand Up @@ -107,6 +110,16 @@ encode(Data, Options) ->
end.


-spec partial_encode(json_array(), encode_options()) -> json_partial_array();
(json_object(), encode_options()) -> json_partial_object().
partial_encode(Data, Options) when is_list(Data) ->
Json = iolist_to_binary(encode(Data, Options)),
{'$partial_array$', binary_part(Json, 1, byte_size(Json) - 2)};
partial_encode(Data, Options) when is_tuple(Data) ->
Json = iolist_to_binary(encode(Data, Options)),
{'$partial_object$', binary_part(Json, 1, byte_size(Json) - 2)}.


finish_decode({bignum, Value}) ->
list_to_integer(binary_to_list(Value));
finish_decode({bignum_e, Value}) ->
Expand Down Expand Up @@ -161,7 +174,7 @@ finish_encode([<<_/binary>>=B | Rest], Acc) ->
finish_encode([Val | Rest], Acc) when is_integer(Val) ->
Bin = list_to_binary(integer_to_list(Val)),
finish_encode(Rest, [Bin | Acc]);
finish_encode([{json, Json} | Rest], Acc) ->
finish_encode([{RawJson, Json} | Rest], Acc) when RawJson =:= json; RawJson =:= '$partial_array$'; RawJson =:= '$partial_object$' ->
finish_encode(Rest, [Json | Acc]);
finish_encode([InvalidEjson | _], _) ->
throw({error, {invalid_ejson, InvalidEjson}});
Expand Down
24 changes: 23 additions & 1 deletion test/jiffy_16_preencode_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ gen(ok, {E1, J, E2}) ->
{msg("~p", [E1]), [
{"Encode", ?_assertEqual(J, enc(E1))},
{"Decode", ?_assertEqual(E2, dec(J))}
]};

gen(ok, {E, J}) ->
{msg("~p", [E]), [
{"Encode", ?_assertEqual(J, enc(E))}
]}.

%% gen(error, E) ->
Expand Down Expand Up @@ -45,7 +50,24 @@ cases(ok) ->
, { [ {json, JSON}, {json, JSON} ], <<"[[1,\"a\"],[1,\"a\"]]">>, [ EJSON, EJSON ]}
, { {[ {<<"a">>, {json, JSON}} ]}, <<"{\"a\":[1,\"a\"]}">>, {[ {<<"a">>, EJSON} ]}}
],
TopTests ++ BuriedTests.

PartialArray = jiffy:partial_encode([ 2, 3 ], []),
PartialArrayTests =
[ {[ PartialArray ], <<"[2,3]">>}
, {[ 1, PartialArray ], <<"[1,2,3]">>}
, {[ PartialArray, 4 ], <<"[2,3,4]">>}
, {[ 1, PartialArray, 4 ], <<"[1,2,3,4]">>}
],

PartialObject = jiffy:partial_encode({[ {<<"ii">>, <<"two">>}, {<<"iii">>, 3} ]}, []),
PartialObjectTests =
[ {{[ PartialObject ]}, <<"{\"ii\":\"two\",\"iii\":3}">>}
, {{[ {<<"i">>, 1}, PartialObject ]}, <<"{\"i\":1,\"ii\":\"two\",\"iii\":3}">>}
, {{[ PartialObject, {<<"iv">>, 4} ]}, <<"{\"ii\":\"two\",\"iii\":3,\"iv\":4}">>}
, {{[ {<<"i">>, 1}, PartialObject, {<<"iv">>, 4} ]}, <<"{\"i\":1,\"ii\":\"two\",\"iii\":3,\"iv\":4}">>}
],

TopTests ++ BuriedTests ++ PartialArrayTests ++ PartialObjectTests.

%% cases(error) ->
%% [ {json, true}
Expand Down

0 comments on commit 6801624

Please sign in to comment.