From a2a7bc91afe8d38553afad6dd721da217666760c Mon Sep 17 00:00:00 2001 From: "Paul J. Davis" Date: Fri, 27 May 2011 19:30:22 -0400 Subject: [PATCH] API Change - No more {ok, Value} wrapping. The encode and decode functions now return the value directly without being wrapped in a tuple on success. If there is an error, it is thrown. This is to more closely match the semantics of term_to_binary and binary_to_term. --- c_src/decoder.c | 6 +++++- c_src/encoder.c | 13 +++++-------- src/jiffy.erl | 19 ++++++++++++------- test/001-yajl-tests.t | 11 +++-------- test/002-literals.t | 12 ++++++------ test/004-strings.t | 7 ++++--- test/util.erl | 15 +++++++-------- 7 files changed, 42 insertions(+), 41 deletions(-) diff --git a/c_src/decoder.c b/c_src/decoder.c index 80bcb35..6debfd8 100644 --- a/c_src/decoder.c +++ b/c_src/decoder.c @@ -284,6 +284,10 @@ dec_string(Decoder* d, ERL_NIF_TERM* value) } parse: + if(d->p[d->i-1] != '\"') { + return 0; + } + if(!has_escape) { *value = enif_make_sub_binary(d->env, d->arg, st, (d->i - st - 1)); return 1; @@ -930,7 +934,7 @@ decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } else if(d->is_partial) { ret = enif_make_tuple2(env, d->atoms->atom_partial, val); } else { - ret = enif_make_tuple2(env, d->atoms->atom_ok, val); + ret = val; } done: diff --git a/c_src/encoder.c b/c_src/encoder.c index fc8a727..5164c2f 100644 --- a/c_src/encoder.c +++ b/c_src/encoder.c @@ -424,8 +424,6 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) double dval; long lval; - int is_partial = 0; - if(argc != 1) { return enif_make_badarg(env); } @@ -563,15 +561,15 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { - ret = enc_error(e, "invalid_object_pair"); + ret = enc_error(e, "invalid_object_member"); goto done; } if(arity != 2) { - ret = enc_error(e, "invalid_object_pair"); + ret = enc_error(e, "invalid_object_member_arity"); goto done; } if(!enc_string(e, tuple[0])) { - ret = enc_error(e, "invalid_object_key"); + ret = enc_error(e, "invalid_object_member_key"); goto done; } if(!enc_colon(e)) { @@ -601,7 +599,6 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else { - is_partial = 1; if(!enc_unknown(e, curr)) { ret = enc_error(e, "internal_error"); goto done; @@ -614,8 +611,8 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) goto done; } - if(!is_partial) { - ret = enif_make_tuple2(env, e->atoms->atom_ok, item); + if(e->iolen == 0) { + ret = item; } else { ret = enif_make_tuple2(env, e->atoms->atom_partial, item); } diff --git a/src/jiffy.erl b/src/jiffy.erl index d79a2b9..190ef21 100644 --- a/src/jiffy.erl +++ b/src/jiffy.erl @@ -9,18 +9,23 @@ decode(Data) -> case nif_decode(Data) of + {error, _} = Error -> + throw(Error); {partial, EJson} -> - {ok, finish_decode(EJson)}; - Else -> - Else + finish_decode(EJson); + EJson -> + EJson end. + encode(Data) -> case nif_encode(Data) of + {error, _} = Error -> + throw(Error); {partial, IOData} -> finish_encode(IOData, []); - Else -> - Else + IOData -> + IOData end. @@ -59,14 +64,14 @@ finish_decode_arr([V | Vals], Acc) -> finish_encode([], Acc) -> %% No reverse! The NIF returned us %% the pieces in reverse order. - {ok, Acc}; + Acc; finish_encode([<<_/binary>>=B | Rest], Acc) -> finish_encode(Rest, [B | 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(_, _) -> - {error, invalid_ejson}. + throw({error, invalid_ejson}). init() -> diff --git a/test/001-yajl-tests.t b/test/001-yajl-tests.t index ca8d493..14529f9 100755 --- a/test/001-yajl-tests.t +++ b/test/001-yajl-tests.t @@ -12,6 +12,8 @@ main([]) -> lists:foreach(fun(Case) -> test(Case) end, Cases), etap:end_tests(). +test({Name, Json, {error, _}=Erl}) -> + etap:is((catch jiffy:decode(Json)), Erl, Name); test({Name, Json, Erl}) -> etap:is(jiffy:decode(Json), Erl, Name). @@ -25,11 +27,4 @@ make_pair(FileName) -> {BaseName, _} = lists:splitwith(fun(C) -> C /= $. end, FileName), ErlFname = BaseName ++ ".erl", {ok, [Term]} = file:consult(ErlFname), - case Term of - {error, _} -> - {BaseName, Json, Term}; - {error, _, _} -> - {BaseName, Json, Term}; - _ -> - {BaseName, Json, {ok, Term}} - end. + {BaseName, Json, Term}. diff --git a/test/002-literals.t b/test/002-literals.t index 022808a..2cdf28f 100755 --- a/test/002-literals.t +++ b/test/002-literals.t @@ -7,14 +7,14 @@ main([]) -> code:add_pathz("test"), etap:plan(6), - etap:is(jiffy:decode(<<"true">>), {ok, true}, "DEC: true -> true"), - etap:is(jiffy:encode(true), {ok, <<"true">>}, "ENC: true -> true"), + etap:is(jiffy:decode(<<"true">>), true, "DEC: true -> true"), + etap:is(jiffy:encode(true), <<"true">>, "ENC: true -> true"), - etap:is(jiffy:decode(<<"false">>), {ok, false}, "DEC: false -> false"), - etap:is(jiffy:encode(false), {ok, <<"false">>}, "ENC: false -> false"), + etap:is(jiffy:decode(<<"false">>), false, "DEC: false -> false"), + etap:is(jiffy:encode(false), <<"false">>, "ENC: false -> false"), - etap:is(jiffy:decode(<<"null">>), {ok, null}, "DEC: null -> null"), - etap:is(jiffy:encode(null), {ok, <<"null">>}, "ENC: null -> null"), + etap:is(jiffy:decode(<<"null">>), null, "DEC: null -> null"), + etap:is(jiffy:encode(null), <<"null">>, "ENC: null -> null"), etap:end_tests(). diff --git a/test/004-strings.t b/test/004-strings.t index b6695cb..00d87e4 100755 --- a/test/004-strings.t +++ b/test/004-strings.t @@ -6,7 +6,7 @@ main([]) -> code:add_pathz("ebin"), code:add_pathz("test"), - etap:plan(75), + etap:plan(76), util:test_good(good()), util:test_errors(errors()), @@ -32,6 +32,7 @@ good() -> errors() -> [ + <<"\"foo">>, <<"\"", 0, "\"">>, <<"\"\\g\"">>, <<"\"\\uFFFF\"">>, @@ -45,13 +46,13 @@ test_utf8([]) -> test_utf8([Case | Rest]) -> etap:fun_is( fun({error, invalid_string}) -> true; (Else) -> Else end, - jiffy:encode(Case), + (catch jiffy:encode(Case)), lists:flatten(io_lib:format("Invalid utf-8: ~p", [Case])) ), Case2 = <<34, Case/binary, 34>>, etap:fun_is( fun({error, {_, invalid_string}}) -> true; (Else) -> Else end, - jiffy:decode(Case2), + (catch jiffy:decode(Case2)), lists:flatten(io_lib:format("Invalid utf-8: ~p", [Case2])) ), test_utf8(Rest). diff --git a/test/util.erl b/test/util.erl index 767f72f..b05edc9 100644 --- a/test/util.erl +++ b/test/util.erl @@ -14,29 +14,28 @@ ok_enc(E, _J) -> lists:flatten(io_lib:format("Encoded ~p", [E])). do_encode(E) -> - {ok, Data} = jiffy:encode(E), - {ok, iolist_to_binary(Data)}. + iolist_to_binary(jiffy:encode(E)). error_mesg(J) -> lists:flatten(io_lib:format("Decoding ~p returns an error.", [J])). check_good({J, E}) -> - etap:is(jiffy:decode(J), {ok, E}, ok_dec(J, E)), - etap:is(do_encode(E), {ok, J}, ok_enc(E, J)); + etap:is(jiffy:decode(J), E, ok_dec(J, E)), + etap:is(do_encode(E), J, ok_enc(E, J)); check_good({J, E, J2}) -> - etap:is(jiffy:decode(J), {ok, E}, ok_dec(J, E)), - etap:is(do_encode(E), {ok, J2}, ok_enc(E, J2)). + etap:is(jiffy:decode(J), E, ok_dec(J, E)), + etap:is(do_encode(E), J2, ok_enc(E, J2)). check_error({J, E}) -> etap:fun_is( fun({error, E1}) when E1 == E -> true; (E1) -> E1 end, - jiffy:decode(J), + (catch jiffy:decode(J)), error_mesg(J) ); check_error(J) -> etap:fun_is( fun({error, _}) -> true; (Else) -> Else end, - jiffy:decode(J), + (catch jiffy:decode(J)), error_mesg(J) ).