You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by kx...@apache.org on 2015/07/25 14:42:42 UTC
[13/19] jiffy commit: updated refs/heads/upstream to f661ee9
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.
Project: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/commit/6d2278e9
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/tree/6d2278e9
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/diff/6d2278e9
Branch: refs/heads/upstream
Commit: 6d2278e90694bb484845ad149d484d0a3cae10ec
Parents: 238c653
Author: Paul J. Davis <pa...@gmail.com>
Authored: Wed Jul 15 16:18:13 2015 -0500
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Wed Jul 15 18:40:27 2015 -0500
----------------------------------------------------------------------
README.md | 4 ++++
c_src/decoder.c | 18 ++++++++++++++++--
c_src/jiffy.c | 2 ++
c_src/jiffy.h | 2 ++
src/jiffy.erl | 8 ++++++--
test/jiffy_11_proper_tests.erl | 21 +++++++++++++++++++++
test/jiffy_15_return_trailer_tests.erl | 19 +++++++++++++++++++
7 files changed, 70 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/6d2278e9/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 7f51ce1..f354ecf 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,10 @@ The options for decode are:
instead of `null`.
* `use_nil` - Returns the atom `nil` instead of `null` when decoding
JSON. This is a short hand for `{null_term, nil}`.
+* `return_trailer` - If any non-whitespace is found after the first
+ JSON term is decoded the return value of decode/2 becomes
+ `{has_trailer, FirstTerm, RestData::iodata()}`. This is useful to
+ decode multiple terms in a single binary.
`jiffy:encode/1,2`
------------------
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/6d2278e9/c_src/decoder.c
----------------------------------------------------------------------
diff --git a/c_src/decoder.c b/c_src/decoder.c
index f39575a..60b3257 100644
--- a/c_src/decoder.c
+++ b/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) {
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/6d2278e9/c_src/jiffy.c
----------------------------------------------------------------------
diff --git a/c_src/jiffy.c b/c_src/jiffy.c
index 9048f5e..1ea60a3 100644
--- a/c_src/jiffy.c
+++ b/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");
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/6d2278e9/c_src/jiffy.h
----------------------------------------------------------------------
diff --git a/c_src/jiffy.h b/c_src/jiffy.h
index 7a2b7d5..61c7b70 100644
--- a/c_src/jiffy.h
+++ b/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;
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/6d2278e9/src/jiffy.erl
----------------------------------------------------------------------
diff --git a/src/jiffy.erl b/src/jiffy.erl
index a272cf9..4517acb 100644
--- a/src/jiffy.erl
+++ b/src/jiffy.erl
@@ -23,8 +23,12 @@
-type json_number() :: integer() | float().
-type json_object() :: {[{json_string(),json_value()}]}.
+-type decode_result() :: json_value()
+ | {has_trailer, json_value(), binary()}.
+
-type decode_option() :: return_maps
| use_nil
+ | return_trailer
| {null_term, any()}
| {bytes_per_iter, non_neg_integer()}.
@@ -37,10 +41,10 @@
-type decode_options() :: [decode_option()].
-type encode_options() :: [encode_option()].
--export_type([json_value/0]).
+-export_type([json_value/0, jiffy_decode_result/0]).
--spec decode(iolist() | binary()) -> json_value().
+-spec decode(iolist() | binary()) -> jiffy_decode_result().
decode(Data) ->
decode(Data, []).
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/6d2278e9/test/jiffy_11_proper_tests.erl
----------------------------------------------------------------------
diff --git a/test/jiffy_11_proper_tests.erl b/test/jiffy_11_proper_tests.erl
index 2c254bf..23aa38d 100644
--- a/test/jiffy_11_proper_tests.erl
+++ b/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],
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/6d2278e9/test/jiffy_15_return_trailer_tests.erl
----------------------------------------------------------------------
diff --git a/test/jiffy_15_return_trailer_tests.erl b/test/jiffy_15_return_trailer_tests.erl
new file mode 100644
index 0000000..af80a46
--- /dev/null
+++ b/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)}.
\ No newline at end of file