Jihyun Yu 11 anni fa
parent
commit
eafe2bf89e
8 ha cambiato i file con 139 aggiunte e 18 eliminazioni
  1. +1
    -3
      Makefile
  2. +76
    -7
      c_src/decoder.c
  3. +25
    -0
      c_src/encoder.c
  4. +2
    -1
      c_src/jiffy.c
  5. +5
    -0
      c_src/jiffy.h
  6. +9
    -0
      c_src/util.c
  7. +10
    -7
      src/jiffy.erl
  8. +11
    -0
      test/util.erl

+ 1
- 3
Makefile Vedi File

@ -1,9 +1,7 @@
REBAR?=./rebar
all: build
clean:
$(REBAR) clean
rm -rf logs
@ -41,7 +39,7 @@ check: build etap eunit
%.beam: %.erl
erlc -o test/ $<
erlc -DTEST_MAP -o test/ $<
.PHONY: all clean distclean depends build etap eunit check

+ 76
- 7
c_src/decoder.c Vedi File

@ -59,10 +59,11 @@ typedef struct {
char* st_data;
int st_size;
int st_top;
int to_map;
} Decoder;
void
dec_init(Decoder* d, ErlNifEnv* env, ERL_NIF_TERM arg, ErlNifBinary* bin)
int
dec_init(Decoder* d, ErlNifEnv* env, ERL_NIF_TERM arg, ERL_NIF_TERM opts, ErlNifBinary* bin)
{
int i;
@ -80,6 +81,7 @@ dec_init(Decoder* d, ErlNifEnv* env, ERL_NIF_TERM arg, ErlNifBinary* bin)
d->st_data = (char*) enif_alloc(STACK_SIZE_INC * sizeof(char));
d->st_size = STACK_SIZE_INC;
d->st_top = 0;
d->to_map = 0;
for(i = 0; i < d->st_size; i++) {
d->st_data[i] = st_invalid;
@ -87,6 +89,16 @@ dec_init(Decoder* d, ErlNifEnv* env, ERL_NIF_TERM arg, ErlNifBinary* bin)
d->st_data[0] = st_value;
d->st_top++;
ERL_NIF_TERM val;
while(enif_get_list_cell(env, opts, &val, &opts)) {
if(enif_compare(val, d->atoms->atom_map) == 0) {
d->to_map = 1;
} else {
return 0;
}
}
return 1;
}
void
@ -575,8 +587,58 @@ parse:
}
ERL_NIF_TERM
make_object(ErlNifEnv* env, ERL_NIF_TERM pairs)
make_object_map(ErlNifEnv* env, ERL_NIF_TERM pairs)
{
ERL_NIF_TERM ret;
ERL_NIF_TERM key, val;
#if MAP_SUPPORT
ret = enif_make_new_map(env);
while(enif_get_list_cell(env, pairs, &val, &pairs)) {
if(!enif_get_list_cell(env, pairs, &key, &pairs)) {
assert(0 == 1 && "Unbalanced object pairs.");
}
enif_make_map_put(env, ret, key, val, &ret);
}
#else
assert(0 == 1 && "maps not supported");
#endif
return ret;
}
ERL_NIF_TERM
make_empty_object_map(ErlNifEnv* env) {
ERL_NIF_TERM ret;
#if MAP_SUPPORT
ret = enif_make_new_map(env);
#else
assert(0 == 1 && "maps not supported");
#endif
return ret;
}
ERL_NIF_TERM
make_empty_object(Decoder* d) {
ErlNifEnv* env = d->env;
if(d->to_map) {
return make_empty_object_map(env);
}
return enif_make_tuple1(env, enif_make_list(env, 0));
}
ERL_NIF_TERM
make_object(Decoder* d, ERL_NIF_TERM pairs)
{
ErlNifEnv* env = d->env;
if(d->to_map) {
return make_object_map(env, pairs);
}
ERL_NIF_TERM ret = enif_make_list(env, 0);
ERL_NIF_TERM key, val;
@ -617,13 +679,20 @@ decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ERL_NIF_TERM val;
ERL_NIF_TERM ret;
if(argc != 1) {
if(argc != 2) {
return enif_make_badarg(env);
} else if(!enif_inspect_binary(env, argv[0], &bin)) {
return enif_make_badarg(env);
}
dec_init(d, env, argv[0], &bin);
if(!dec_init(d, env, argv[0], argv[1], &bin)) {
return enif_make_badarg(env);
}
if(d->to_map && !maps_enabled()) {
ret = dec_error(d, "map_unavailable");
goto done;
}
//fprintf(stderr, "Parsing:\r\n");
while(d->i < bin.size) {
@ -770,7 +839,7 @@ decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
dec_pop(d, st_key);
dec_pop(d, st_object);
dec_pop(d, st_value);
val = enif_make_tuple1(env, curr);
val = make_empty_object(d);
if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error");
goto done;
@ -839,7 +908,7 @@ decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
dec_pop(d, st_object);
dec_pop(d, st_value);
val = make_object(env, curr);
val = make_object(d, curr);
if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error");
goto done;

+ 25
- 0
c_src/encoder.c Vedi File

@ -623,6 +623,7 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto done;
}
} else if(enif_get_tuple(env, curr, &arity, &tuple)) {
// Old-fasioned object definition: {[{Key1, Val1}, {Key2, Val2}]}
if(arity != 1) {
ret = enc_error(e, "invalid_ejson");
goto done;
@ -665,6 +666,30 @@ encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
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);
#if MAP_SUPPORT
} else if(enif_is_map(env, curr)) {
ErlNifMapIterator iter;
if(!enif_map_iterator_create(env, curr, &iter, ERL_NIF_MAP_ITERATOR_HEAD)) {
ret = enc_error(e, "internal_error");
goto done;
}
curr = enif_make_list(env, 0);
ERL_NIF_TERM key, val, tup;
while(!enif_map_iterator_is_tail(env, &iter)) {
if(!enif_map_iterator_get_pair(env, &iter, &key, &val)) {
ret = enc_error(e, "internal_error");
goto done;
}
tup = enif_make_tuple2(env, key, val);
curr = enif_make_list_cell(env, tup, curr);
enif_map_iterator_next(env, &iter);
}
stack = enif_make_list_cell(env, enif_make_tuple1(env, curr), stack);
#endif
} else if(enif_is_list(env, curr)) {
if(!enc_start_array(e)) {
ret = enc_error(e, "internal_error");

+ 2
- 1
c_src/jiffy.c Vedi File

@ -23,6 +23,7 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
st->atom_uescape = make_atom(env, "uescape");
st->atom_pretty = make_atom(env, "pretty");
st->atom_force_utf8 = make_atom(env, "force_utf8");
st->atom_map = make_atom(env, "map");
// Markers used in encoding
st->ref_object = make_atom(env, "$object_ref$");
@ -54,7 +55,7 @@ unload(ErlNifEnv* env, void* priv)
static ErlNifFunc funcs[] =
{
{"nif_decode", 1, decode},
{"nif_decode", 2, decode},
{"nif_encode", 2, encode}
};

+ 5
- 0
c_src/jiffy.h Vedi File

@ -6,6 +6,8 @@
#include "erl_nif.h"
#define MAP_SUPPORT ((ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION >= 6) || (ERL_NIF_MAJOR_VERSION > 2))
typedef struct {
ERL_NIF_TERM atom_ok;
ERL_NIF_TERM atom_error;
@ -19,6 +21,7 @@ typedef struct {
ERL_NIF_TERM atom_uescape;
ERL_NIF_TERM atom_pretty;
ERL_NIF_TERM atom_force_utf8;
ERL_NIF_TERM atom_map;
ERL_NIF_TERM ref_object;
ERL_NIF_TERM ref_array;
@ -27,6 +30,7 @@ typedef struct {
ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name);
ERL_NIF_TERM make_ok(jiffy_st* st, ErlNifEnv* env, ERL_NIF_TERM data);
ERL_NIF_TERM make_error(jiffy_st* st, ErlNifEnv* env, const char* error);
int maps_enabled(void);
ERL_NIF_TERM decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@ -42,4 +46,5 @@ int unicode_from_pair(int hi, int lo);
int unicode_uescape(int c, char* buf);
int double_to_shortest(char *buf, size_t size, size_t* len, double val);
#endif // Included JIFFY_H

+ 9
- 0
c_src/util.c Vedi File

@ -24,3 +24,12 @@ make_error(jiffy_st* st, ErlNifEnv* env, const char* error)
{
return enif_make_tuple2(env, st->atom_error, make_atom(env, error));
}
int
maps_enabled(void) {
#if MAP_SUPPORT
return 1;
#else
return 0;
#endif
}

+ 10
- 7
src/jiffy.erl Vedi File

@ -2,22 +2,25 @@
% See the LICENSE file for more information.
-module(jiffy).
-export([decode/1, encode/1, encode/2]).
-export([decode/1, decode/2, encode/1, encode/2]).
-define(NOT_LOADED, not_loaded(?LINE)).
-on_load(init/0).
decode(Data) when is_binary(Data) ->
case nif_decode(Data) of
decode(Data) ->
decode(Data, []).
decode(Data, Options) when is_list(Data) ->
decode(iolist_to_binary(Data), Options);
decode(Data, Options) when is_binary(Data) ->
case nif_decode(Data, Options) of
{error, _} = Error ->
throw(Error);
{partial, EJson} ->
finish_decode(EJson);
EJson ->
EJson
end;
decode(Data) when is_list(Data) ->
decode(iolist_to_binary(Data)).
end.
encode(Data) ->
@ -99,7 +102,7 @@ init() ->
not_loaded(Line) ->
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
nif_decode(_Data) ->
nif_decode(_Data, _Options) ->
?NOT_LOADED.
nif_encode(_Data, _Options) ->

+ 11
- 0
test/util.erl Vedi File

@ -27,8 +27,19 @@ check_good({J, E}, Options) ->
etap:is(do_encode(E, Options), J, ok_enc(E, J));
check_good({J, E, J2}, Options) ->
etap:is(jiffy:decode(J), E, ok_dec(J, E)),
check_map({J, J2}, Options),
etap:is(do_encode(E, Options), J2, ok_enc(E, J2)).
check_map({J, J2}, Options) ->
try jiffy:decode(J, [map]) of
E2 ->
% etap function breaks all tests because of etap:plan, so stop
% if map test failed
J2 = do_encode(E2, Options)
catch throw:{error, {1, map_unavailable}} ->
ok
end.
check_error({J, E}) ->
etap:fun_is(
fun({error, E1}) when E1 == E -> true; (E1) -> E1 end,

Caricamento…
Annulla
Salva