Skip to content

Commit d3ce6e7

Browse files
author
David Hull
committed
Add jiffy:partial_encode/2 function.
1 parent bbcfc12 commit d3ce6e7

File tree

5 files changed

+102
-5
lines changed

5 files changed

+102
-5
lines changed

c_src/encoder.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ enc_object_element(Encoder* e, int first, ERL_NIF_TERM curr, ERL_NIF_TERM* stack
580580
if(first && !enc_start_object(e)) {
581581
return enc_error(e, "internal_error");
582582
}
583+
next_object_elt:
583584
if(enif_is_empty_list(env, curr)) {
584585
if(!enc_end_object(e)) {
585586
return enc_error(e, "internal_error");
@@ -595,6 +596,22 @@ enc_object_element(Encoder* e, int first, ERL_NIF_TERM curr, ERL_NIF_TERM* stack
595596
if(arity != 2) {
596597
return enc_obj_error(e, "invalid_object_member_arity", item);
597598
}
599+
if(enif_compare(tuple[0], e->atoms->atom_partial_object) == 0) {
600+
ErlNifBinary bin;
601+
if(!enif_inspect_binary(env, tuple[1], &bin)) {
602+
return enc_error(e, "internal_error");
603+
}
604+
if(bin.size > 0) {
605+
if(!first && !enc_comma(e)) {
606+
return enc_error(e, "internal_error");
607+
}
608+
if(!enc_unknown(e, tuple[1])) {
609+
return enc_error(e, "internal_error");
610+
}
611+
first = 0;
612+
}
613+
goto next_object_elt;
614+
}
598615
if(!first && !enc_comma(e)) {
599616
return enc_error(e, "internal_error");
600617
}
@@ -617,10 +634,14 @@ enc_array_element(Encoder* e, int first, ERL_NIF_TERM curr, ERL_NIF_TERM* stackp
617634
ErlNifEnv* env = e->env;
618635
ERL_NIF_TERM stack = *stackp;
619636
ERL_NIF_TERM item;
637+
const ERL_NIF_TERM* tuple;
638+
int arity;
639+
ErlNifBinary bin;
620640

621641
if(first && !enc_start_array(e)) {
622642
return enc_error(e, "internal_error");
623643
}
644+
next_array_elt:
624645
if(enif_is_empty_list(env, curr)) {
625646
if(!enc_end_array(e)) {
626647
return enc_error(e, "internal_error");
@@ -630,6 +651,21 @@ enc_array_element(Encoder* e, int first, ERL_NIF_TERM curr, ERL_NIF_TERM* stackp
630651
if(!enif_get_list_cell(env, curr, &item, &curr)) {
631652
return enc_error(e, "internal_error");
632653
}
654+
if(enif_get_tuple(env, item, &arity, &tuple) &&
655+
(arity == 2) &&
656+
(enif_compare(tuple[0], e->atoms->atom_partial_array) == 0) &&
657+
enif_inspect_binary(env, tuple[1], &bin)) {
658+
if (bin.size > 0) {
659+
if(!first && !enc_comma(e)) {
660+
return enc_error(e, "internal_error");
661+
}
662+
if(!enc_unknown(e, tuple[1])) {
663+
return enc_error(e, "internal_error");
664+
}
665+
first = 0;
666+
}
667+
goto next_array_elt;
668+
}
633669
if(!first && !enc_comma(e)) {
634670
return enc_error(e, "internal_error");
635671
}

c_src/jiffy.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
1616
st->atom_null = make_atom(env, "null");
1717
st->atom_true = make_atom(env, "true");
1818
st->atom_false = make_atom(env, "false");
19+
st->atom_partial_object = make_atom(env, "$partial_object$");
20+
st->atom_partial_array = make_atom(env, "$partial_array$");
1921
st->atom_bignum = make_atom(env, "bignum");
2022
st->atom_bignum_e = make_atom(env, "bignum_e");
2123
st->atom_bigdbl = make_atom(env, "bigdbl");

c_src/jiffy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ typedef struct {
1919
ERL_NIF_TERM atom_null;
2020
ERL_NIF_TERM atom_true;
2121
ERL_NIF_TERM atom_false;
22+
ERL_NIF_TERM atom_partial_object;
23+
ERL_NIF_TERM atom_partial_array;
2224
ERL_NIF_TERM atom_bignum;
2325
ERL_NIF_TERM atom_bignum_e;
2426
ERL_NIF_TERM atom_bigdbl;

src/jiffy.erl

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
% See the LICENSE file for more information.
33

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

88
-compile([no_native]).
@@ -19,17 +19,20 @@
1919
| json_array()
2020
| json_preencoded().
2121

22-
-type json_array() :: [json_value()].
22+
-type json_array() :: [json_value()|json_partial_array()].
2323
-type json_string() :: atom() | binary().
2424
-type json_number() :: integer() | float().
2525

26+
-type json_partial_array() :: {'$partial_array$', iodata()}.
27+
-type json_partial_object() :: {'$partial_object$', iodata()}.
28+
2629
-ifdef(JIFFY_NO_MAPS).
2730

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

3033
-else.
3134

32-
-type json_object() :: {[{json_string(),json_value()}]}
35+
-type json_object() :: {[({json_string(),json_value()})|json_partial_object()]}
3336
| #{json_string() => json_value()}.
3437

3538
-endif.
@@ -109,6 +112,16 @@ encode(Data, Options) ->
109112
end.
110113

111114

115+
-spec partial_encode(json_array(), encode_options()) -> json_partial_array();
116+
(json_object(), encode_options()) -> json_partial_object().
117+
partial_encode(Data, Options) when is_list(Data) ->
118+
Json = iolist_to_binary(encode(Data, Options)),
119+
{'$partial_array$', binary_part(Json, 1, byte_size(Json) - 2)};
120+
partial_encode(Data, Options) when is_tuple(Data) ->
121+
Json = iolist_to_binary(encode(Data, Options)),
122+
{'$partial_object$', binary_part(Json, 1, byte_size(Json) - 2)}.
123+
124+
112125
finish_decode({bignum, Value}) ->
113126
list_to_integer(binary_to_list(Value));
114127
finish_decode({bignum_e, Value}) ->

test/jiffy_18_preencode_tests.erl

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ gen(ok, {E1, J, E2}) ->
1717
{msg("~p", [E1]), [
1818
{"Encode", ?_assertEqual(J, enc(E1))},
1919
{"Decode", ?_assertEqual(E2, dec(J))}
20+
]};
21+
22+
gen(ok, {E, J}) ->
23+
{msg("~p", [E]), [
24+
{"Encode", ?_assertEqual(J, enc(E))}
2025
]}.
2126

2227
%% gen(error, E) ->
@@ -45,7 +50,46 @@ cases(ok) ->
4550
, { [ {json, JSON}, {json, JSON} ], <<"[[1,\"a\"],[1,\"a\"]]">>, [ EJSON, EJSON ]}
4651
, { {[ {<<"a">>, {json, JSON}} ]}, <<"{\"a\":[1,\"a\"]}">>, {[ {<<"a">>, EJSON} ]}}
4752
],
48-
TopTests ++ BuriedTests.
53+
54+
PartialArray1 = jiffy:partial_encode([ 2, 3 ], []),
55+
PartialArray2 = jiffy:partial_encode([], []),
56+
PartialArray3 = jiffy:partial_encode([ 5 ], []),
57+
PartialArrayTests =
58+
[ {[ PartialArray1 ], <<"[2,3]">>}
59+
, {[ 1, PartialArray1 ], <<"[1,2,3]">>}
60+
, {[ PartialArray1, 4 ], <<"[2,3,4]">>}
61+
, {[ 1, PartialArray1, 4 ], <<"[1,2,3,4]">>}
62+
, {[ PartialArray2 ], <<"[]">>}
63+
, {[ 1, PartialArray2 ], <<"[1]">>}
64+
, {[ PartialArray2, 4 ], <<"[4]">>}
65+
, {[ 1, PartialArray2, 4 ], <<"[1,4]">>}
66+
, {[ PartialArray1, PartialArray2 ], <<"[2,3]">>}
67+
, {[ PartialArray2, PartialArray1 ], <<"[2,3]">>}
68+
, {[ PartialArray1, PartialArray1 ], <<"[2,3,2,3]">>}
69+
, {[ PartialArray2, PartialArray2 ], <<"[]">>}
70+
, {[ PartialArray1, PartialArray3 ], <<"[2,3,5]">>}
71+
, {[ 1, PartialArray1, 4, PartialArray3, 6 ], <<"[1,2,3,4,5,6]">>}
72+
],
73+
74+
PartialObject1 = jiffy:partial_encode({[ {<<"ii">>, <<"two">>}, {<<"iii">>, 3} ]}, []),
75+
PartialObject2 = jiffy:partial_encode({[]}, []),
76+
PartialObject3 = jiffy:partial_encode({[ {<<"v">>, [ 1, 2, 3, 4, 5 ]} ]}, []),
77+
PartialObjectTests =
78+
[ {{[ PartialObject1 ]}, <<"{\"ii\":\"two\",\"iii\":3}">>}
79+
, {{[ {<<"i">>, 1}, PartialObject1 ]}, <<"{\"i\":1,\"ii\":\"two\",\"iii\":3}">>}
80+
, {{[ PartialObject1, {<<"iv">>, 4} ]}, <<"{\"ii\":\"two\",\"iii\":3,\"iv\":4}">>}
81+
, {{[ {<<"i">>, 1}, PartialObject1, {<<"iv">>, 4} ]}, <<"{\"i\":1,\"ii\":\"two\",\"iii\":3,\"iv\":4}">>}
82+
, {{[ PartialObject2 ]}, <<"{}">>}
83+
, {{[ {<<"i">>, 1}, PartialObject2 ]}, <<"{\"i\":1}">>}
84+
, {{[ PartialObject2, {<<"iv">>, 4} ]}, <<"{\"iv\":4}">>}
85+
, {{[ {<<"i">>, 1}, PartialObject2, {<<"iv">>, 4} ]}, <<"{\"i\":1,\"iv\":4}">>}
86+
, {{[ PartialObject1, PartialObject2 ]}, <<"{\"ii\":\"two\",\"iii\":3}">>}
87+
, {{[ PartialObject2, PartialObject1 ]}, <<"{\"ii\":\"two\",\"iii\":3}">>}
88+
, {{[ PartialObject2, PartialObject2 ]}, <<"{}">>}
89+
, {{[ PartialObject1, PartialObject3 ]}, <<"{\"ii\":\"two\",\"iii\":3,\"v\":[1,2,3,4,5]}">>}
90+
],
91+
92+
TopTests ++ BuriedTests ++ PartialArrayTests ++ PartialObjectTests.
4993

5094
%% cases(error) ->
5195
%% [ {json, true}

0 commit comments

Comments
 (0)