diff --git a/c_src/encoder.c b/c_src/encoder.c index 09e0727..af2585a 100644 --- a/c_src/encoder.c +++ b/c_src/encoder.c @@ -628,16 +628,28 @@ 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(!enif_is_binary(env, tuple[1])) { + return enc_obj_error(e, "invalid_json_string", curr); + } + if(!enc_json(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; } @@ -843,7 +855,8 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ret = enc_object_element(e, 1, tuple[0], &stack); if (ret) { goto done; } } else if(arity == 2) { - if(enif_compare(tuple[0], e->atoms->atom_json) != 0) { + if((enif_compare(tuple[0], e->atoms->atom_json) != 0) && + (enif_compare(tuple[0], e->atoms->atom_partial_array) != 0)) { ret = enc_obj_error(e, "invalid_ejson", curr); goto done; } diff --git a/c_src/jiffy.c b/c_src/jiffy.c index 1a8d285..dde4da4 100644 --- a/c_src/jiffy.c +++ b/c_src/jiffy.c @@ -17,6 +17,8 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info) st->atom_true = make_atom(env, "true"); st->atom_false = make_atom(env, "false"); st->atom_json = make_atom(env, "json"); + st->atom_partial_object = make_atom(env, "$partial_object$"); + st->atom_partial_array = make_atom(env, "$partial_array$"); st->atom_bignum = make_atom(env, "bignum"); st->atom_bignum_e = make_atom(env, "bignum_e"); st->atom_bigdbl = make_atom(env, "bigdbl"); diff --git a/c_src/jiffy.h b/c_src/jiffy.h index aea0833..a63d77e 100644 --- a/c_src/jiffy.h +++ b/c_src/jiffy.h @@ -20,6 +20,8 @@ typedef struct { ERL_NIF_TERM atom_true; ERL_NIF_TERM atom_false; ERL_NIF_TERM atom_json; + ERL_NIF_TERM atom_partial_object; + ERL_NIF_TERM atom_partial_array; ERL_NIF_TERM atom_bignum; ERL_NIF_TERM atom_bignum_e; ERL_NIF_TERM atom_bigdbl; diff --git a/src/jiffy.erl b/src/jiffy.erl index 426b542..9a0937f 100644 --- a/src/jiffy.erl +++ b/src/jiffy.erl @@ -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]). @@ -107,6 +107,16 @@ encode(Data, Options) -> end. +-spec partial_encode(json_array(), encode_options()) -> {'$partial_array$', binary()}; + (json_object(), encode_options()) -> {'$partial_object$', binary()}. +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}) -> diff --git a/test/jiffy_16_preencode_tests.erl b/test/jiffy_16_preencode_tests.erl index 09d73b4..062d7de 100644 --- a/test/jiffy_16_preencode_tests.erl +++ b/test/jiffy_16_preencode_tests.erl @@ -19,6 +19,11 @@ gen(ok, {E1, J, E2}) -> {"Decode", ?_assertEqual(E2, dec(J))} ]}; +gen(ok, {E, J}) -> + {msg("~p", [E]), [ + {"Encode", ?_assertEqual(J, enc(E))} + ]}; + gen(error, E) -> {msg("Error: ~p", [E]), [ ?_assertThrow({error, _}, enc(E)) @@ -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}