diff --git a/lualib-src/sproto/README.md b/lualib-src/sproto/README.md index 8d9efd94..e397549d 100644 --- a/lualib-src/sproto/README.md +++ b/lualib-src/sproto/README.md @@ -140,11 +140,11 @@ The schema text is like this: } .AddressBook { - person 0 : *Person + person 0 : *Person(id) # (id) is optional, means Person.id is main index. } foobar 1 { # define a new protocol (for RPC used) with tag 1 - request person # Associate the type person with foobar.request + request Person # Associate the type Person with foobar.request response { # define the foobar.response type ok 0 : boolean } @@ -161,6 +161,7 @@ A schema text can be self-described by the sproto schema language. type 1 : string id 2 : integer array 3 : boolean + key 4 : integer # optional tag for map } name 0 : string fields 1 : *field @@ -183,10 +184,12 @@ Types ======= * **string** : binary string -* **integer** : integer, the max length of a integer is signed 64bit. +* **integer** : integer, the max length of an integer is signed 64bit. * **boolean** : true or false -You can add * before the typename to declare an array. +You can add * before the typename to declare an array. + +You can also specify a main index, the array whould be encode as an unordered map. User defined type can be any name in alphanumeric characters except the build-in typenames, and nested types are supported. @@ -319,7 +322,19 @@ struct sproto_type * sproto_type(struct sproto *, const char * typename); Query the type object from a sproto object: ```C -typedef int (*sproto_callback)(void *ud, const char *tagname, int type, int index, struct sproto_type *, void *value, int length); +struct sproto_arg { + void *ud; + const char *tagname; + int tagid; + int type; + struct sproto_type *subtype; + void *value; + int length; + int index; // array base 1 + int mainindex; // for map +}; + +typedef int (*sproto_callback)(const struct sproto_arg *args); int sproto_decode(struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud); int sproto_encode(struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud); @@ -334,13 +349,9 @@ int sproto_unpack(const void * src, int srcsz, void * buffer, int bufsz); pack and unpack the message with the 0 packing algorithm. -JIT +Other Implementions and bindings ===== -You may also interest in https://github.com/lvzixun/sproto-JIT - -C# version -===== -https://github.com/lvzixun/sproto-Csharp +See Wiki https://github.com/cloudwu/sproto/wiki Question? ========== diff --git a/lualib-src/sproto/lsproto.c b/lualib-src/sproto/lsproto.c index 290eeef4..a546b51d 100644 --- a/lualib-src/sproto/lsproto.c +++ b/lualib-src/sproto/lsproto.c @@ -9,7 +9,6 @@ #define MAX_GLOBALSPROTO 16 #define ENCODE_BUFFERSIZE 2050 -//#define ENCODE_BUFFERSIZE 2050 #define ENCODE_MAXSIZE 0x1000000 #define ENCODE_DEEPLEVEL 64 @@ -94,18 +93,19 @@ struct encode_ud { const char * array_tag; int array_index; int deep; + int iter_index; }; static int -encode(void *ud, const char *tagname, int type, int index, struct sproto_type *st, void *value, int length) { - struct encode_ud *self = ud; +encode(const struct sproto_arg *args) { + struct encode_ud *self = args->ud; lua_State *L = self->L; if (self->deep >= ENCODE_DEEPLEVEL) return luaL_error(L, "The table is too deep"); - if (index > 0) { - if (tagname != self->array_tag) { - self->array_tag = tagname; - lua_getfield(L, self->tbl_index, tagname); + if (args->index > 0) { + if (args->tagname != self->array_tag) { + self->array_tag = args->tagname; + lua_getfield(L, self->tbl_index, args->tagname); if (lua_isnil(L, -1)) { if (self->array_index) { lua_replace(L, self->array_index); @@ -119,15 +119,30 @@ encode(void *ud, const char *tagname, int type, int index, struct sproto_type *s self->array_index = lua_gettop(L); } } - lua_rawgeti(L, self->array_index, index); + if (args->mainindex >= 0) { + // use lua_next to iterate the table + // todo: check the key is equal to mainindex value + + lua_pushvalue(L,self->iter_index); + if (!lua_next(L, self->array_index)) { + // iterate end + lua_pushnil(L); + lua_replace(L, self->iter_index); + return 0; + } + lua_insert(L, -2); + lua_replace(L, self->iter_index); + } else { + lua_rawgeti(L, self->array_index, args->index); + } } else { - lua_getfield(L, self->tbl_index, tagname); + lua_getfield(L, self->tbl_index, args->tagname); } if (lua_isnil(L, -1)) { lua_pop(L,1); return 0; } - switch (type) { + switch (args->type) { case SPROTO_TINTEGER: { lua_Integer v = luaL_checkinteger(L, -1); lua_Integer vh; @@ -135,26 +150,26 @@ encode(void *ud, const char *tagname, int type, int index, struct sproto_type *s // notice: in lua 5.2, lua_Integer maybe 52bit vh = v >> 31; if (vh == 0 || vh == -1) { - *(uint32_t *)value = (uint32_t)v; + *(uint32_t *)args->value = (uint32_t)v; return 4; } else { - *(uint64_t *)value = (uint64_t)v; + *(uint64_t *)args->value = (uint64_t)v; return 8; } } case SPROTO_TBOOLEAN: { int v = lua_toboolean(L, -1); - *(int *)value = v; + *(int *)args->value = v; lua_pop(L,1); return 4; } case SPROTO_TSTRING: { size_t sz = 0; const char * str = luaL_checklstring(L, -1, &sz); - if (sz > length) + if (sz > args->length) return -1; - memcpy(value, str, sz); + memcpy(args->value, str, sz); lua_pop(L,1); return sz; } @@ -162,17 +177,19 @@ encode(void *ud, const char *tagname, int type, int index, struct sproto_type *s struct encode_ud sub; int r; sub.L = L; - sub.st = st; + sub.st = args->subtype; sub.tbl_index = lua_gettop(L); sub.array_tag = NULL; sub.array_index = 0; sub.deep = self->deep + 1; - r = sproto_encode(st, value, length, encode, &sub); - lua_pop(L,1); + lua_pushnil(L); // prepare an iterator slot + sub.iter_index = sub.tbl_index + 1; + r = sproto_encode(args->subtype, args->value, args->length, encode, &sub); + lua_pop(L,2); // pop the value and the iterator slot return r; } default: - return luaL_error(L, "Invalid field type %d", type); + return luaL_error(L, "Invalid field type %d", args->type); } } @@ -211,18 +228,23 @@ lencode(lua_State *L) { return luaL_argerror(L, 1, "Need a sproto_type object"); } luaL_checktype(L, 2, LUA_TTABLE); - luaL_checkstack(L, ENCODE_DEEPLEVEL + 8, NULL); + luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL); self.L = L; self.st = st; self.tbl_index = 2; self.array_tag = NULL; self.array_index = 0; self.deep = 0; + lua_pushnil(L); // for iterator (stack 3) + self.iter_index = 3; for (;;) { int r = sproto_encode(st, buffer, sz, encode, &self); if (r<0) { buffer = expand_buffer(L, sz, sz*2); sz *= 2; + // reset iterator slot + lua_pushnil(L); + lua_replace(L, 3); } else { lua_pushlstring(L, buffer, r); return 1; @@ -236,21 +258,23 @@ struct decode_ud { int array_index; int result_index; int deep; + int mainindex_tag; + int key_index; }; static int -decode(void *ud, const char *tagname, int type, int index, struct sproto_type *st, void *value, int length) { - struct decode_ud * self = ud; +decode(const struct sproto_arg *args) { + struct decode_ud * self = args->ud; lua_State *L = self->L; if (self->deep >= ENCODE_DEEPLEVEL) return luaL_error(L, "The table is too deep"); - if (index > 0) { + if (args->index > 0) { // It's array - if (tagname != self->array_tag) { - self->array_tag = tagname; + if (args->tagname != self->array_tag) { + self->array_tag = args->tagname; lua_newtable(L); lua_pushvalue(L, -1); - lua_setfield(L, self->result_index, tagname); + lua_setfield(L, self->result_index, args->tagname); if (self->array_index) { lua_replace(L, self->array_index); } else { @@ -258,20 +282,20 @@ decode(void *ud, const char *tagname, int type, int index, struct sproto_type *s } } } - switch (type) { + switch (args->type) { case SPROTO_TINTEGER: { // notice: in lua 5.2, 52bit integer support (not 64) - lua_Integer v = *(uint64_t*)value; + lua_Integer v = *(uint64_t*)args->value; lua_pushinteger(L, v); break; } case SPROTO_TBOOLEAN: { - int v = *(uint64_t*)value; + int v = *(uint64_t*)args->value; lua_pushboolean(L,v); break; } case SPROTO_TSTRING: { - lua_pushlstring(L, value, length); + lua_pushlstring(L, args->value, args->length); break; } case SPROTO_TSTRUCT: { @@ -283,20 +307,47 @@ decode(void *ud, const char *tagname, int type, int index, struct sproto_type *s sub.deep = self->deep + 1; sub.array_index = 0; sub.array_tag = NULL; + if (args->mainindex >= 0) { + // This struct will set into a map, so mark the main index tag. + sub.mainindex_tag = args->mainindex; + lua_pushnil(L); + sub.key_index = lua_gettop(L); - r = sproto_decode(st, value, length, decode, &sub); - if (r < 0 || r != length) - return r; - lua_settop(L, sub.result_index); - break; + r = sproto_decode(args->subtype, args->value, args->length, decode, &sub); + if (r < 0 || r != args->length) + return r; + // assert(args->index > 0); + lua_pushvalue(L, sub.key_index); + if (lua_isnil(L, -1)) { + luaL_error(L, "Can't find main index (tag=%d) in [%s]", args->mainindex, args->tagname); + } + lua_pushvalue(L, sub.result_index); + lua_rawset(L, self->array_index); + lua_settop(L, sub.result_index-1); + return 0; + } else { + sub.mainindex_tag = -1; + sub.key_index = 0; + r = sproto_decode(args->subtype, args->value, args->length, decode, &sub); + if (r < 0 || r != args->length) + return r; + lua_settop(L, sub.result_index); + break; + } } default: luaL_error(L, "Invalid type"); } - if (index > 0) { - lua_rawseti(L, self->array_index, index); + if (args->index > 0) { + lua_rawseti(L, self->array_index, args->index); } else { - lua_setfield(L, self->result_index, tagname); + if (self->mainindex_tag == args->tagid) { + // This tag is marked, save the value to key_index + // assert(self->key_index > 0); + lua_pushvalue(L,-1); + lua_replace(L, self->key_index); + } + lua_setfield(L, self->result_index, args->tagname); } return 0; @@ -339,12 +390,14 @@ ldecode(lua_State *L) { if (!lua_istable(L, -1)) { lua_newtable(L); } - luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL); + luaL_checkstack(L, ENCODE_DEEPLEVEL*3 + 8, NULL); self.L = L; self.result_index = lua_gettop(L); self.array_index = 0; self.array_tag = NULL; self.deep = 0; + self.mainindex_tag = -1; + self.key_index = 0; r = sproto_decode(st, buffer, (int)sz, decode, &self); if (r < 0) { return luaL_error(L, "decode error"); diff --git a/lualib-src/sproto/sproto.c b/lualib-src/sproto/sproto.c index 67e0d0d0..910266da 100644 --- a/lualib-src/sproto/sproto.c +++ b/lualib-src/sproto/sproto.c @@ -17,6 +17,7 @@ struct field { int type; const char * name; struct sproto_type * st; + int key; }; struct sproto_type { @@ -188,6 +189,7 @@ import_field(struct sproto *s, struct field *f, const uint8_t * stream) { f->type = -1; f->name = NULL; f->st = NULL; + f->key = -1; sz = todword(stream); stream += SIZEOF_LENGTH; @@ -234,6 +236,9 @@ import_field(struct sproto *s, struct field *f, const uint8_t * stream) { if (value) array = SPROTO_TARRAY; break; + case 5: // key + f->key = value; + break; default: return NULL; } @@ -485,7 +490,11 @@ sproto_dump(struct sproto *s) { type_name = buildin[t]; } } - printf("\t%s (%d) %s%s\n", f->name, f->tag, array, type_name); + if (f->key >= 0) { + printf("\t%s (%d) %s%s(%d)\n", f->name, f->tag, array, type_name, f->key); + } else { + printf("\t%s (%d) %s%s\n", f->name, f->tag, array, type_name); + } } } printf("=== %d protocol ===\n", s->protocol_n); @@ -637,22 +646,37 @@ encode_uint64(uint64_t v, uint8_t * data, int size) { return fill_size(data, sizeof(v)); } +/* +//#define CB(tagname,type,index,subtype,value,length) cb(ud, tagname,type,index,subtype,value,length) + static int -encode_string(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int size) { +do_cb(sproto_callback cb, void *ud, const char *tagname, int type, int index, struct sproto_type *subtype, void *value, int length) { + if (subtype) { + if (type >= 0) { + printf("callback: tag=%s[%d], subtype[%s]:%d\n",tagname,index, subtype->name, type); + } else { + printf("callback: tag=%s[%d], subtype[%s]\n",tagname,index, subtype->name); + } + } else if (index > 0) { + printf("callback: tag=%s[%d]\n",tagname,index); + } else if (index == 0) { + printf("callback: tag=%s\n",tagname); + } else { + printf("callback: tag=%s [mainkey]\n",tagname); + } + return cb(ud, tagname,type,index,subtype,value,length); +} +#define CB(tagname,type,index,subtype,value,length) do_cb(cb,ud, tagname,type,index,subtype,value,length) +*/ + +static int +encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) { int sz; if (size < SIZEOF_LENGTH) return -1; - sz = cb(ud, f->name, SPROTO_TSTRING, 0, NULL, data+SIZEOF_LENGTH, size-SIZEOF_LENGTH); - return fill_size(data, sz); -} - -static int -encode_struct(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int size) { - int sz; - if (size < SIZEOF_LENGTH) { - return -1; - } - sz = cb(ud, f->name, SPROTO_TSTRUCT, 0, f->st, data+SIZEOF_LENGTH, size-SIZEOF_LENGTH); + args->value = data+SIZEOF_LENGTH; + args->length = size-SIZEOF_LENGTH; + sz = cb(args); return fill_size(data, sz); } @@ -672,7 +696,7 @@ uint32_to_uint64(int negative, uint8_t *buffer) { } static uint8_t * -encode_integer_array(sproto_callback cb, void *ud, struct field *f, uint8_t *buffer, int size) { +encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size) { uint8_t * header = buffer; int intlen; int index; @@ -688,7 +712,10 @@ encode_integer_array(sproto_callback cb, void *ud, struct field *f, uint8_t *buf uint64_t u64; uint32_t u32; } u; - sz = cb(ud, f->name, SPROTO_TINTEGER, index, f->st, &u, sizeof(u)); + args->value = &u; + args->length = sizeof(u); + args->index = index; + sz = cb(args); if (sz < 0) return NULL; if (sz == 0) @@ -749,27 +776,26 @@ encode_integer_array(sproto_callback cb, void *ud, struct field *f, uint8_t *buf } static int -encode_array(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int size) { +encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int size) { uint8_t * buffer; - int index; - int type; int sz; if (size < SIZEOF_LENGTH) return -1; size -= SIZEOF_LENGTH; - index = 1; buffer = data + SIZEOF_LENGTH; - type = f->type & ~SPROTO_TARRAY; - switch (type) { + switch (args->type) { case SPROTO_TINTEGER: - buffer = encode_integer_array(cb,ud,f,buffer,size); + buffer = encode_integer_array(cb,args,buffer,size); if (buffer == NULL) return -1; break; case SPROTO_TBOOLEAN: + args->index = 1; for (;;) { int v = 0; - int sz = cb(ud, f->name, type, index, f->st, &v, sizeof(v)); + args->value = &v; + args->length = sizeof(v); + sz = cb(args); if (sz < 0) return -1; if (sz == 0) @@ -779,16 +805,18 @@ encode_array(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int s buffer[0] = v ? 1: 0; size -= 1; buffer += 1; - index++; + ++args->index; } break; default: + args->index = 1; for (;;) { - int sz; if (size < SIZEOF_LENGTH) return -1; size -= SIZEOF_LENGTH; - sz = cb(ud, f->name, type, index, f->st, buffer+SIZEOF_LENGTH, size); + args->value = buffer+SIZEOF_LENGTH; + args->length = size; + sz = cb(args); if (sz < 0) return -1; if (sz == 0) @@ -796,7 +824,7 @@ encode_array(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int s fill_size(buffer, sz); buffer += SIZEOF_LENGTH+sz; size -=sz; - index ++; + ++args->index; } break; } @@ -808,6 +836,7 @@ encode_array(sproto_callback cb, void *ud, struct field *f, uint8_t *data, int s int sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback cb, void *ud) { + struct sproto_arg args; uint8_t * header = buffer; uint8_t * data; int header_sz = SIZEOF_HEADER + st->maxn * SIZEOF_FIELD; @@ -817,6 +846,7 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c int datasz; if (size < header_sz) return -1; + args.ud = ud; data = header + header_sz; size -= header_sz; index = 0; @@ -826,9 +856,16 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c int type = f->type; int value = 0; int sz = -1; + args.tagname = f->name; + args.tagid = f->tag; + args.subtype = f->st; + args.mainindex = f->key; if (type & SPROTO_TARRAY) { - sz = encode_array(cb,ud, f, data, size); + args.type = type & ~SPROTO_TARRAY; + sz = encode_array(cb, &args, data, size); } else { + args.type = type; + args.index = 0; switch(type) { case SPROTO_TINTEGER: case SPROTO_TBOOLEAN: { @@ -836,7 +873,9 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c uint64_t u64; uint32_t u32; } u; - sz = cb(ud, f->name, type, 0, NULL, &u, sizeof(u)); + args.value = &u; + args.length = sizeof(u); + sz = cb(&args); if (sz < 0) return -1; if (sz == 0) @@ -855,12 +894,9 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c } break; } + case SPROTO_TSTRUCT: case SPROTO_TSTRING: { - sz = encode_string(cb, ud, f, data, size); - break; - } - case SPROTO_TSTRUCT: { - sz = encode_struct(cb, ud, f, data, size); + sz = encode_object(cb, &args, data, size); break; } } @@ -904,9 +940,8 @@ sproto_encode(struct sproto_type *st, void * buffer, int size, sproto_callback c } static int -decode_array_object(sproto_callback cb, void *ud, struct field *f, uint8_t * stream, int sz) { +decode_array_object(sproto_callback cb, struct sproto_arg *args, uint8_t * stream, int sz) { uint32_t hsz; - int type = f->type & ~SPROTO_TARRAY; int index = 1; while (sz > 0) { if (sz < SIZEOF_LENGTH) @@ -916,7 +951,10 @@ decode_array_object(sproto_callback cb, void *ud, struct field *f, uint8_t * str sz -= SIZEOF_LENGTH; if (hsz > sz) return -1; - if (cb(ud, f->name, type, index, f->st, stream, hsz)) + args->index = index; + args->value = stream; + args->length = hsz; + if (cb(args)) return -1; sz -= hsz; stream += hsz; @@ -935,9 +973,9 @@ expand64(uint32_t v) { } static int -decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) { +decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) { uint32_t sz = todword(stream); - int type = f->type & ~SPROTO_TARRAY; + int type = args->type; int i; stream += SIZEOF_LENGTH; switch (type) { @@ -953,7 +991,10 @@ decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) { return -1; for (i=0;iname, SPROTO_TINTEGER, i+1, NULL, &value, sizeof(value)); + args->index = i+1; + args->value = &value; + args->length = sizeof(value); + cb(args); } } else if (len == sizeof(uint64_t)) { if (sz % sizeof(uint64_t) != 0) @@ -962,7 +1003,10 @@ decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) { uint64_t low = todword(stream + i*sizeof(uint64_t)); uint64_t hi = todword(stream + i*sizeof(uint64_t) + sizeof(uint32_t)); uint64_t value = low | hi << 32; - cb(ud, f->name, SPROTO_TINTEGER, i+1, NULL, &value, sizeof(value)); + args->index = i+1; + args->value = &value; + args->length = sizeof(value); + cb(args); } } else { return -1; @@ -972,12 +1016,15 @@ decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) { case SPROTO_TBOOLEAN: for (i=0;iname, SPROTO_TBOOLEAN, i+1, NULL, &value, sizeof(value)); + args->index = i+1; + args->value = &value; + args->length = sizeof(value); + cb(args); } break; case SPROTO_TSTRING: case SPROTO_TSTRUCT: - return decode_array_object(cb, ud, f, stream, sz); + return decode_array_object(cb, args, stream, sz); default: return -1; } @@ -986,6 +1033,7 @@ decode_array(sproto_callback cb, void *ud, struct field *f, uint8_t * stream) { int sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callback cb, void *ud) { + struct sproto_arg args; int total = size; uint8_t * stream; uint8_t * datastream; @@ -994,6 +1042,8 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba int tag; if (size < SIZEOF_HEADER) return -1; + // debug print + // printf("sproto_decode[%p] (%s)\n", ud, st->name); stream = (void *)data; fn = toword(stream); stream += SIZEOF_HEADER; @@ -1001,7 +1051,8 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba if (size < fn * SIZEOF_FIELD) return -1; datastream = stream + fn * SIZEOF_FIELD; - size -= fn * SIZEOF_FIELD ; + size -= fn * SIZEOF_FIELD; + args.ud = ud; tag = -1; for (i=0;iname; + args.tagid = f->tag; + args.type = f->type & ~SPROTO_TARRAY; + args.subtype = f->st; + args.index = 0; + args.mainindex = f->key; if (value < 0) { if (f->type & SPROTO_TARRAY) { - if (decode_array(cb, ud, f, currentdata)) { + if (decode_array(cb, &args, currentdata)) { return -1; } } else { @@ -1039,21 +1096,27 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba uint32_t sz = todword(currentdata); if (sz == sizeof(uint32_t)) { uint64_t v = expand64(todword(currentdata + SIZEOF_LENGTH)); - cb(ud, f->name, SPROTO_TINTEGER, 0, NULL, &v, sizeof(v)); + args.value = &v; + args.length = sizeof(v); + cb(&args); } else if (sz != sizeof(uint64_t)) { return -1; } else { uint32_t low = todword(currentdata + SIZEOF_LENGTH); uint32_t hi = todword(currentdata + SIZEOF_LENGTH + sizeof(uint32_t)); uint64_t v = (uint64_t)low | (uint64_t) hi << 32; - cb(ud, f->name, SPROTO_TINTEGER, 0, NULL, &v, sizeof(v)); + args.value = &v; + args.length = sizeof(v); + cb(&args); } break; } case SPROTO_TSTRING: case SPROTO_TSTRUCT: { uint32_t sz = todword(currentdata); - if (cb(ud, f->name, f->type, 0, f->st, currentdata+SIZEOF_LENGTH, sz)) + args.value = currentdata+SIZEOF_LENGTH; + args.length = sz; + if (cb(&args)) return -1; break; } @@ -1065,7 +1128,9 @@ sproto_decode(struct sproto_type *st, const void * data, int size, sproto_callba return -1; } else { uint64_t v = value; - cb(ud, f->name, f->type, 0, NULL, &v, sizeof(v)); + args.value = &v; + args.length = sizeof(v); + cb(&args); } } return total - size; diff --git a/lualib-src/sproto/sproto.h b/lualib-src/sproto/sproto.h index 3286a423..934e18f8 100644 --- a/lualib-src/sproto/sproto.h +++ b/lualib-src/sproto/sproto.h @@ -27,7 +27,19 @@ struct sproto_type * sproto_type(struct sproto *, const char * type_name); int sproto_pack(const void * src, int srcsz, void * buffer, int bufsz); int sproto_unpack(const void * src, int srcsz, void * buffer, int bufsz); -typedef int (*sproto_callback)(void *ud, const char *tagname, int type, int index, struct sproto_type *, void *value, int length); +struct sproto_arg { + void *ud; + const char *tagname; + int tagid; + int type; + struct sproto_type *subtype; + void *value; + int length; + int index; // array base 1 + int mainindex; // for map +}; + +typedef int (*sproto_callback)(const struct sproto_arg *args); int sproto_decode(struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud); int sproto_encode(struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud); diff --git a/lualib/sprotoparser.lua b/lualib/sprotoparser.lua index cf65e536..4761bcca 100644 --- a/lualib/sprotoparser.lua +++ b/lualib/sprotoparser.lua @@ -1,6 +1,40 @@ local lpeg = require "lpeg" local table = require "table" +local packbytes +local packvalue + +if _VERSION == "Lua 5.3" then + function packbytes(str) + return string.pack("=0 and id < 65536) + local a = id % 256 + local b = math.floor(id / 256) + return string.char(a) .. string.char(b) + end +end + local P = lpeg.P local S = lpeg.S local R = lpeg.R @@ -35,6 +69,7 @@ local word = alpha * alnum ^ 0 local name = C(word) local typename = C(word * ("." * word) ^ 0) local tag = R"09" ^ 1 / tonumber +local mainkey = "(" * blank0 * name * blank0 * ")" local function multipat(pat) return Ct(blank0 * (pat * blanks) ^ 0 * pat^0 * blank0) @@ -46,7 +81,7 @@ end local typedef = P { "ALL", - FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename)), + FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename * mainkey^0)), STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}", TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ), SUBPROTO = Ct((C"request" + C"response") * blanks * (name + V"STRUCT")), @@ -97,6 +132,11 @@ function convert.type(all, obj) field.array = true fieldtype = f[4] end + local mainkey = f[5] + if mainkey then + assert(field.array) + field.key = mainkey + end field.typename = fieldtype else assert(f.type == "type") -- nest type @@ -176,6 +216,7 @@ end type 2 : integer tag 3 : integer array 4 : boolean + key 5 : integer # If key exists, array must be true, and it's a map. } name 0 : string fields 1 : *field @@ -194,25 +235,18 @@ end } ]] -local function packbytes(str) - str = string.pack("