Skip to content

Commit 66797a9

Browse files
committed
Add return_truncated decode flag
1 parent dddb392 commit 66797a9

File tree

6 files changed

+45
-2
lines changed

6 files changed

+45
-2
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ The options for decode are:
4848
JSON term is decoded the return value of decode/2 becomes
4949
`{has_trailer, FirstTerm, RestData::iodata()}`. This is useful to
5050
decode multiple terms in a single binary.
51+
* `return_truncated` - If the JSON passed to the decoder is incomplete
52+
return `{truncated, Pos}`, where `Pos`, is the length of JSON read
53+
before hitting the end of the interpretable term.
5154
* `dedupe_keys` - If a key is repeated in a JSON object this flag
5255
will ensure that the parsed object only contains a single entry
5356
containing the last value seen. This mirrors the parsing beahvior

c_src/decoder.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ typedef struct {
5252
size_t bytes_per_red;
5353
int is_partial;
5454
int return_maps;
55+
int return_truncated;
5556
int return_trailer;
5657
int dedupe_keys;
5758
int copy_strings;
@@ -84,6 +85,7 @@ dec_new(ErlNifEnv* env)
8485
d->is_partial = 0;
8586
d->return_maps = 0;
8687
d->return_trailer = 0;
88+
d->return_truncated = 0;
8789
d->dedupe_keys = 0;
8890
d->copy_strings = 0;
8991
d->null_term = d->atoms->atom_null;
@@ -689,6 +691,8 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
689691
#endif
690692
} else if(enif_compare(val, d->atoms->atom_return_trailer) == 0) {
691693
d->return_trailer = 1;
694+
} else if(enif_compare(val, d->atoms->atom_return_truncated) == 0) {
695+
d->return_truncated = 1;
692696
} else if(enif_compare(val, d->atoms->atom_dedupe_keys) == 0) {
693697
d->dedupe_keys = 1;
694698
} else if(enif_compare(val, d->atoms->atom_copy_strings) == 0) {
@@ -1035,7 +1039,12 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
10351039
}
10361040

10371041
if(dec_curr(d) != st_done) {
1038-
ret = dec_error(d, "truncated_json");
1042+
if (d->return_truncated) {
1043+
ret = enif_make_tuple2(env, d->atoms->atom_truncated,
1044+
enif_make_int(d->env, d->i+1));
1045+
} else {
1046+
ret = dec_error(d, "truncated_json");
1047+
}
10391048
} else if(d->is_partial) {
10401049
ret = enif_make_tuple2(env, d->atoms->atom_partial, val);
10411050
} else {

c_src/jiffy.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
2424
st->atom_pretty = make_atom(env, "pretty");
2525
st->atom_force_utf8 = make_atom(env, "force_utf8");
2626
st->atom_iter = make_atom(env, "iter");
27+
st->atom_truncated = make_atom(env, "truncated");
2728
st->atom_bytes_per_iter = make_atom(env, "bytes_per_iter");
2829
st->atom_return_maps = make_atom(env, "return_maps");
2930
st->atom_return_trailer = make_atom(env, "return_trailer");
31+
st->atom_return_truncated = make_atom(env, "return_truncated");
3032
st->atom_has_trailer = make_atom(env, "has_trailer");
3133
st->atom_nil = make_atom(env, "nil");
3234
st->atom_use_nil = make_atom(env, "use_nil");

c_src/jiffy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ typedef struct {
2727
ERL_NIF_TERM atom_pretty;
2828
ERL_NIF_TERM atom_force_utf8;
2929
ERL_NIF_TERM atom_iter;
30+
ERL_NIF_TERM atom_truncated;
3031
ERL_NIF_TERM atom_bytes_per_iter;
3132
ERL_NIF_TERM atom_return_maps;
3233
ERL_NIF_TERM atom_return_trailer;
34+
ERL_NIF_TERM atom_return_truncated;
3335
ERL_NIF_TERM atom_has_trailer;
3436
ERL_NIF_TERM atom_nil;
3537
ERL_NIF_TERM atom_use_nil;

src/jiffy.erl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@
3434
-endif.
3535

3636
-type jiffy_decode_result() :: json_value()
37-
| {has_trailer, json_value(), binary()}.
37+
| {has_trailer, json_value(), binary()}
38+
| {truncated, non_neg_integer()}.
3839

3940
-type decode_option() :: return_maps
4041
| use_nil
4142
| return_trailer
43+
| return_truncated
4244
| dedupe_keys
4345
| {null_term, any()}
4446
| {bytes_per_iter, non_neg_integer()}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
% This file is part of Jiffy released under the MIT license.
2+
% See the LICENSE file for more information.
3+
4+
-module(jiffy_18_return_truncated_tests).
5+
6+
-include_lib("eunit/include/eunit.hrl").
7+
8+
cases() ->
9+
[
10+
{<<"">>, 1},
11+
{<<"{">>, 2}
12+
].
13+
14+
return_truncated_test_() ->
15+
Opts = [return_truncated],
16+
{"Test return_truncated", lists:map(fun({Data, Pos}) ->
17+
?_assertEqual({truncated, Pos}, jiffy:decode(Data, Opts))
18+
end, cases())}.
19+
20+
error_truncated_test_() ->
21+
Opts = [],
22+
{"Test truncated error case", lists:map(fun({Data, Pos}) ->
23+
Error = {error, {Pos, truncated_json}},
24+
?_assertException(throw, Error, jiffy:decode(Data, Opts))
25+
end, cases())}.

0 commit comments

Comments
 (0)