瀏覽代碼

Merge d3ce6e7ed6 into 2a14a3bb8c

pull/140/merge
David Hull 6 年之前
committed by GitHub
父節點
當前提交
162d532da0
沒有發現已知的金鑰在資料庫的簽署中 GPG Key ID: 4AEE18F83AFDEB23
共有 5 個文件被更改,包括 243 次插入109 次删除
  1. +119
    -104
      c_src/encoder.c
  2. +2
    -0
      c_src/jiffy.c
  3. +2
    -0
      c_src/jiffy.h
  4. +23
    -5
      src/jiffy.erl
  5. +97
    -0
      test/jiffy_18_preencode_tests.erl

+ 119
- 104
c_src/encoder.c 查看文件

@ -568,6 +568,114 @@ enc_map_to_ejson(ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM* out)
}
#endif
ERL_NIF_TERM
enc_object_element(Encoder* e, int first, ERL_NIF_TERM curr, ERL_NIF_TERM* stackp)
{
ErlNifEnv* env = e->env;
ERL_NIF_TERM stack = *stackp;
ERL_NIF_TERM item;
const ERL_NIF_TERM* tuple;
int arity;
if(first && !enc_start_object(e)) {
return enc_error(e, "internal_error");
}
next_object_elt:
if(enif_is_empty_list(env, curr)) {
if(!enc_end_object(e)) {
return enc_error(e, "internal_error");
}
return 0;
}
if(!enif_get_list_cell(env, curr, &item, &curr)) {
return enc_error(e, "internal_error");
}
if(!enif_get_tuple(env, item, &arity, &tuple)) {
return enc_obj_error(e, "invalid_object_member", item);
}
if(arity != 2) {
return enc_obj_error(e, "invalid_object_member_arity", item);
}
if(enif_compare(tuple[0], e->atoms->atom_partial_object) == 0) {
ErlNifBinary bin;
if(!enif_inspect_binary(env, tuple[1], &bin)) {
return enc_error(e, "internal_error");
}
if(bin.size > 0) {
if(!first && !enc_comma(e)) {
return enc_error(e, "internal_error");
}
if(!enc_unknown(e, tuple[1])) {
return enc_error(e, "internal_error");
}
first = 0;
}
goto next_object_elt;
}
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");
}
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;
}
ERL_NIF_TERM
enc_array_element(Encoder* e, int first, ERL_NIF_TERM curr, ERL_NIF_TERM* stackp)
{
ErlNifEnv* env = e->env;
ERL_NIF_TERM stack = *stackp;
ERL_NIF_TERM item;
const ERL_NIF_TERM* tuple;
int arity;
ErlNifBinary bin;
if(first && !enc_start_array(e)) {
return enc_error(e, "internal_error");
}
next_array_elt:
if(enif_is_empty_list(env, curr)) {
if(!enc_end_array(e)) {
return enc_error(e, "internal_error");
}
return 0;
}
if(!enif_get_list_cell(env, curr, &item, &curr)) {
return enc_error(e, "internal_error");
}
if(enif_get_tuple(env, item, &arity, &tuple) &&
(arity == 2) &&
(enif_compare(tuple[0], e->atoms->atom_partial_array) == 0) &&
enif_inspect_binary(env, tuple[1], &bin)) {
if (bin.size > 0) {
if(!first && !enc_comma(e)) {
return enc_error(e, "internal_error");
}
if(!enc_unknown(e, tuple[1])) {
return enc_error(e, "internal_error");
}
first = 0;
}
goto next_array_elt;
}
if(!first && !enc_comma(e)) {
return enc_error(e, "internal_error");
}
stack = enif_make_list_cell(env, curr, stack);
stack = enif_make_list_cell(env, e->atoms->ref_array, stack);
stack = enif_make_list_cell(env, item, stack);
*stackp = stack;
return 0;
}
ERL_NIF_TERM
encode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
@ -682,63 +790,15 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = enc_error(e, "internal_error");
goto done;
}
if(enif_is_empty_list(env, curr)) {
if(!enc_end_object(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
continue;
}
if(!enif_get_list_cell(env, curr, &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_comma(e)) {
ret = enc_error(e, "internal_error");
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);
ret = enc_object_element(e, 0, curr, &stack);
if(ret) { goto done; }
} else if(enif_is_identical(curr, e->atoms->ref_array)) {
if(!enif_get_list_cell(env, stack, &curr, &stack)) {
ret = enc_error(e, "internal_error");
goto done;
}
if(enif_is_empty_list(env, curr)) {
if(!enc_end_array(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
continue;
}
if(!enc_comma(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
if(!enif_get_list_cell(env, curr, &item, &curr)) {
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_array, stack);
stack = enif_make_list_cell(env, item, stack);
ret = enc_array_element(e, 0, curr, &stack);
if(ret) { goto done; }
} else if(enif_compare(curr, e->atoms->atom_null) == 0) {
if(!enc_literal(e, "null", 4)) {
ret = enc_error(e, "null");
@ -781,47 +841,18 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
} 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(!enc_unknown(e, curr)) {
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_list(env, tuple[0])) {
ret = enc_obj_error(e, "invalid_object", 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);
ret = enc_object_element(e, 1, tuple[0], &stack);
if (ret) { goto done; }
#if MAP_TYPE_PRESENT
} else if(enif_is_map(env, curr)) {
if(!enc_map_to_ejson(env, curr, &curr)) {
@ -831,24 +862,8 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
stack = enif_make_list_cell(env, curr, stack);
#endif
} else if(enif_is_list(env, curr)) {
if(!enc_start_array(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
if(enif_is_empty_list(env, curr)) {
if(!enc_end_array(e)) {
ret = enc_error(e, "internal_error");
goto done;
}
continue;
}
if(!enif_get_list_cell(env, curr, &item, &curr)) {
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_array, stack);
stack = enif_make_list_cell(env, item, stack);
ret = enc_array_element(e, 1, curr, &stack);
if(ret) { goto done; }
} else {
if(!enc_unknown(e, curr)) {
ret = enc_error(e, "internal_error");

+ 2
- 0
c_src/jiffy.c 查看文件

@ -16,6 +16,8 @@ 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_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");

+ 2
- 0
c_src/jiffy.h 查看文件

@ -19,6 +19,8 @@ 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_partial_array;
ERL_NIF_TERM atom_bignum;
ERL_NIF_TERM atom_bignum_e;
ERL_NIF_TERM atom_bigdbl;

+ 23
- 5
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]).
@ -16,23 +16,29 @@
| json_string()
| json_number()
| json_object()
| json_array().
| 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.
-type json_preencoded() :: {json, Json::iodata()}.
-type jiffy_decode_result() :: json_value()
| {has_trailer, json_value(), binary()}.
@ -106,6 +112,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}) ->
@ -160,6 +176,8 @@ 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(Rest, [Json | Acc]);
finish_encode([InvalidEjson | _], _) ->
error({invalid_ejson, InvalidEjson});
finish_encode(_, _) ->

+ 97
- 0
test/jiffy_18_preencode_tests.erl 查看文件

@ -0,0 +1,97 @@
-module(jiffy_18_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(ok, {E, J}) ->
{msg("~p", [E]), [
{"Encode", ?_assertEqual(J, enc(E))}
]}.
%% 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} ]}}
],
PartialArray1 = jiffy:partial_encode([ 2, 3 ], []),
PartialArray2 = jiffy:partial_encode([], []),
PartialArray3 = jiffy:partial_encode([ 5 ], []),
PartialArrayTests =
[ {[ PartialArray1 ], <<"[2,3]">>}
, {[ 1, PartialArray1 ], <<"[1,2,3]">>}
, {[ PartialArray1, 4 ], <<"[2,3,4]">>}
, {[ 1, PartialArray1, 4 ], <<"[1,2,3,4]">>}
, {[ PartialArray2 ], <<"[]">>}
, {[ 1, PartialArray2 ], <<"[1]">>}
, {[ PartialArray2, 4 ], <<"[4]">>}
, {[ 1, PartialArray2, 4 ], <<"[1,4]">>}
, {[ PartialArray1, PartialArray2 ], <<"[2,3]">>}
, {[ PartialArray2, PartialArray1 ], <<"[2,3]">>}
, {[ PartialArray1, PartialArray1 ], <<"[2,3,2,3]">>}
, {[ PartialArray2, PartialArray2 ], <<"[]">>}
, {[ PartialArray1, PartialArray3 ], <<"[2,3,5]">>}
, {[ 1, PartialArray1, 4, PartialArray3, 6 ], <<"[1,2,3,4,5,6]">>}
],
PartialObject1 = jiffy:partial_encode({[ {<<"ii">>, <<"two">>}, {<<"iii">>, 3} ]}, []),
PartialObject2 = jiffy:partial_encode({[]}, []),
PartialObject3 = jiffy:partial_encode({[ {<<"v">>, [ 1, 2, 3, 4, 5 ]} ]}, []),
PartialObjectTests =
[ {{[ PartialObject1 ]}, <<"{\"ii\":\"two\",\"iii\":3}">>}
, {{[ {<<"i">>, 1}, PartialObject1 ]}, <<"{\"i\":1,\"ii\":\"two\",\"iii\":3}">>}
, {{[ PartialObject1, {<<"iv">>, 4} ]}, <<"{\"ii\":\"two\",\"iii\":3,\"iv\":4}">>}
, {{[ {<<"i">>, 1}, PartialObject1, {<<"iv">>, 4} ]}, <<"{\"i\":1,\"ii\":\"two\",\"iii\":3,\"iv\":4}">>}
, {{[ PartialObject2 ]}, <<"{}">>}
, {{[ {<<"i">>, 1}, PartialObject2 ]}, <<"{\"i\":1}">>}
, {{[ PartialObject2, {<<"iv">>, 4} ]}, <<"{\"iv\":4}">>}
, {{[ {<<"i">>, 1}, PartialObject2, {<<"iv">>, 4} ]}, <<"{\"i\":1,\"iv\":4}">>}
, {{[ PartialObject1, PartialObject2 ]}, <<"{\"ii\":\"two\",\"iii\":3}">>}
, {{[ PartialObject2, PartialObject1 ]}, <<"{\"ii\":\"two\",\"iii\":3}">>}
, {{[ PartialObject2, PartialObject2 ]}, <<"{}">>}
, {{[ PartialObject1, PartialObject3 ]}, <<"{\"ii\":\"two\",\"iii\":3,\"v\":[1,2,3,4,5]}">>}
],
TopTests ++ BuriedTests ++ PartialArrayTests ++ PartialObjectTests.
%% cases(error) ->
%% [ {json, true}
%% , {json, "true"}
%% ].

Loading…
取消
儲存