Преглед на файлове

Add new return_trailer option

Previously Jiffy would throw an error about trailing data if there is
any non-whitespace character encounter after the first term had been
decoded.

This patch adds a decoder option `return_trailer` that will instead
return a sub-binary starting at the first non-whitespace character. This
allows users to be able to decode multiple terms from a single iodata()
term.

Thanks to @vlm for the original patch.
return-trailer
Paul J. Davis преди 9 години
родител
ревизия
5cead13b2b
променени са 5 файла, в които са добавени 60 реда и са изтрити 2 реда
  1. +16
    -2
      c_src/decoder.c
  2. +2
    -0
      c_src/jiffy.c
  3. +2
    -0
      c_src/jiffy.h
  4. +21
    -0
      test/jiffy_11_proper_tests.erl
  5. +19
    -0
      test/jiffy_15_return_trailer_tests.erl

+ 16
- 2
c_src/decoder.c Целия файл

@ -52,6 +52,7 @@ typedef struct {
size_t bytes_per_iter;
int is_partial;
int return_maps;
int return_trailer;
ERL_NIF_TERM null_term;
char* p;
@ -80,6 +81,7 @@ dec_new(ErlNifEnv* env)
d->bytes_per_iter = DEFAULT_BYTES_PER_ITER;
d->is_partial = 0;
d->return_maps = 0;
d->return_trailer = 0;
d->null_term = d->atoms->atom_null;
d->p = NULL;
@ -710,6 +712,8 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
#else
return enif_make_badarg(env);
#endif
} else if(enif_compare(val, d->atoms->atom_return_trailer) == 0) {
d->return_trailer = 1;
} else if(enif_compare(val, d->atoms->atom_use_nil) == 0) {
d->null_term = d->atoms->atom_nil;
} else if(get_null_term(env, val, &(d->null_term))) {
@ -733,6 +737,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ERL_NIF_TERM objs;
ERL_NIF_TERM curr;
ERL_NIF_TERM val = argv[2];
ERL_NIF_TERM trailer;
ERL_NIF_TERM ret;
size_t start;
@ -1030,8 +1035,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++;
break;
default:
ret = dec_error(d, "invalid_trailing_data");
goto done;
goto decode_done;
}
break;
@ -1041,6 +1045,16 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
}
decode_done:
if(d->i < bin.size && d->return_trailer) {
trailer = enif_make_sub_binary(env, argv[0], d->i, bin.size - d->i);
val = enif_make_tuple3(env, d->atoms->atom_has_trailer, val, trailer);
} else if(d->i < bin.size) {
ret = dec_error(d, "invalid_trailing_data");
goto done;
}
if(dec_curr(d) != st_done) {
ret = dec_error(d, "truncated_json");
} else if(d->is_partial) {

+ 2
- 0
c_src/jiffy.c Целия файл

@ -26,6 +26,8 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
st->atom_iter = make_atom(env, "iter");
st->atom_bytes_per_iter = make_atom(env, "bytes_per_iter");
st->atom_return_maps = make_atom(env, "return_maps");
st->atom_return_trailer = make_atom(env, "return_trailer");
st->atom_has_trailer = make_atom(env, "has_trailer");
st->atom_nil = make_atom(env, "nil");
st->atom_use_nil = make_atom(env, "use_nil");
st->atom_null_term = make_atom(env, "null_term");

+ 2
- 0
c_src/jiffy.h Целия файл

@ -28,6 +28,8 @@ typedef struct {
ERL_NIF_TERM atom_iter;
ERL_NIF_TERM atom_bytes_per_iter;
ERL_NIF_TERM atom_return_maps;
ERL_NIF_TERM atom_return_trailer;
ERL_NIF_TERM atom_has_trailer;
ERL_NIF_TERM atom_nil;
ERL_NIF_TERM atom_use_nil;
ERL_NIF_TERM atom_null_term;

+ 21
- 0
test/jiffy_11_proper_tests.erl Целия файл

@ -24,6 +24,7 @@ proper_encode_decode_test_() ->
[
run(prop_enc_dec),
run(prop_enc_dec_pretty),
run(prop_dec_trailer),
run(prop_enc_no_crash),
run(prop_dec_no_crash_bin),
run(prop_dec_no_crash_any)
@ -37,6 +38,26 @@ prop_enc_dec() ->
end
).
prop_dec_trailer() ->
?FORALL({T1, T2}, {json(), json()},
begin
B1 = jiffy:encode(T1),
B2 = jiffy:encode(T2),
Combiners = [
<<" ">>,
<<"\r\t">>,
<<"\n \t">>,
<<" ">>
],
lists:foreach(fun(Comb) ->
Bin = <<B1/binary, Comb/binary, B2/binary>>,
{has_trailer, T1, Rest} = jiffy:decode(Bin, [return_trailer]),
T2 = jiffy:decode(Rest)
end, Combiners),
true
end
).
-ifndef(JIFFY_NO_MAPS).
to_map_ejson({Props}) ->
NewProps = [{K, to_map_ejson(V)} || {K, V} <- Props],

+ 19
- 0
test/jiffy_15_return_trailer_tests.erl Целия файл

@ -0,0 +1,19 @@
% This file is part of Jiffy released under the MIT license.
% See the LICENSE file for more information.
-module(jiffy_15_return_trailer_tests).
-include_lib("eunit/include/eunit.hrl").
trailer_test_() ->
Opts = [return_trailer],
Cases = [
{<<"true">>, true},
{<<"true;">>, {has_trailer, true, <<";">>}},
{<<"true[]">>, {has_trailer, true, <<"[]">>}},
{<<"[]{}">>, {has_trailer, [], <<"{}">>}},
{<<"1 2 3">>, {has_trailer, 1, <<"2 3">>}}
],
{"Test return_trailer", lists:map(fun({Data, Result}) ->
?_assertEqual(Result, jiffy:decode(Data, Opts))
end, Cases)}.

Зареждане…
Отказ
Запис