diff --git a/lualib-src/sproto/lsproto.c b/lualib-src/sproto/lsproto.c index c7708fed..3eb32163 100644 --- a/lualib-src/sproto/lsproto.c +++ b/lualib-src/sproto/lsproto.c @@ -166,10 +166,16 @@ encode(const struct sproto_arg *args) { lua_Integer v; lua_Integer vh; int isnum; - v = lua_tointegerx(L, -1, &isnum); - if(!isnum) { - return luaL_error(L, ".%s[%d] is not an integer (Is a %s)", - args->tagname, args->index, lua_typename(L, lua_type(L, -1))); + if (args->extra) { + // It's decimal. + lua_Number vn = lua_tonumber(L, -1); + v = (lua_Integer)(vn * args->extra + 0.5); + } else { + v = lua_tointegerx(L, -1, &isnum); + if(!isnum) { + return luaL_error(L, ".%s[%d] is not an integer (Is a %s)", + args->tagname, args->index, lua_typename(L, lua_type(L, -1))); + } } lua_pop(L,1); // notice: in lua 5.2, lua_Integer maybe 52bit @@ -332,8 +338,15 @@ decode(const struct sproto_arg *args) { switch (args->type) { case SPROTO_TINTEGER: { // notice: in lua 5.2, 52bit integer support (not 64) - lua_Integer v = *(uint64_t*)args->value; - lua_pushinteger(L, v); + if (args->extra) { + lua_Integer v = *(uint64_t*)args->value; + lua_Number vn = (lua_Number)v; + vn /= args->extra; + lua_pushnumber(L, vn); + } else { + lua_Integer v = *(uint64_t*)args->value; + lua_pushinteger(L, v); + } break; } case SPROTO_TBOOLEAN: { @@ -660,7 +673,7 @@ ldefault(lua_State *L) { return 1; } -int +LUAMOD_API int luaopen_sproto_core(lua_State *L) { #ifdef luaL_checkversion luaL_checkversion(L); diff --git a/lualib-src/sproto/sproto.c b/lualib-src/sproto/sproto.c index 9b23af49..416f1006 100644 --- a/lualib-src/sproto/sproto.c +++ b/lualib-src/sproto/sproto.c @@ -18,6 +18,7 @@ struct field { const char * name; struct sproto_type * st; int key; + int extra; }; struct sproto_type { @@ -177,6 +178,18 @@ import_string(struct sproto *s, const uint8_t * stream) { return buffer; } +static int +calc_pow(int base, int n) { + int r; + if (n == 0) + return 1; + r = calc_pow(base * base , n / 2); + if (n&1) { + r *= base; + } + return r; +} + static const uint8_t * import_field(struct sproto *s, struct field *f, const uint8_t * stream) { uint32_t sz; @@ -190,6 +203,7 @@ import_field(struct sproto *s, struct field *f, const uint8_t * stream) { f->name = NULL; f->st = NULL; f->key = -1; + f->extra = 0; sz = todword(stream); stream += SIZEOF_LENGTH; @@ -222,12 +236,18 @@ import_field(struct sproto *s, struct field *f, const uint8_t * stream) { f->type = value; break; case 2: // type index - if (value >= s->type_n) - return NULL; // invalid type index - if (f->type >= 0) - return NULL; - f->type = SPROTO_TSTRUCT; - f->st = &s->type[value]; + if (f->type == SPROTO_TINTEGER) { + f->extra = calc_pow(10, value); + } else if (f->type == SPROTO_TSTRING) { + f->extra = value; // string if 0 ; binary is 1 + } else { + if (value >= s->type_n) + return NULL; // invalid type index + if (f->type >= 0) + return NULL; + f->type = SPROTO_TSTRUCT; + f->st = &s->type[value]; + } break; case 3: // tag f->tag = value; @@ -463,11 +483,6 @@ sproto_release(struct sproto * s) { void sproto_dump(struct sproto *s) { int i,j; - static const char * buildin[] = { - "integer", - "boolean", - "string", - }; printf("=== %d types ===\n", s->type_n); for (i=0;itype_n;i++) { struct sproto_type *t = &s->type[i]; @@ -476,25 +491,45 @@ sproto_dump(struct sproto *s) { char array[2] = { 0, 0 }; const char * type_name = NULL; struct field *f = &t->f[j]; + int type = f->type & ~SPROTO_TARRAY; if (f->type & SPROTO_TARRAY) { array[0] = '*'; } else { array[0] = 0; } - { - int t = f->type & ~SPROTO_TARRAY; - if (t == SPROTO_TSTRUCT) { - type_name = f->st->name; - } else { - assert(tst->name; + } else { + switch(type) { + case SPROTO_TINTEGER: + if (f->extra) { + type_name = "decimal"; + } else { + type_name = "integer"; + } + break; + case SPROTO_TBOOLEAN: + type_name = "boolean"; + break; + case SPROTO_TSTRING: + if (f->extra == SPROTO_TSTRING_BINARY) + type_name = "binary"; + else + type_name = "string"; + break; + default: + type_name = "invalid"; + break; } } - 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("\t%s (%d) %s%s", f->name, f->tag, array, type_name); + if (type == SPROTO_TINTEGER && f->extra > 0) { + printf("(%d)", f->extra); } + if (f->key >= 0) { + printf("[%d]", f->key); + } + printf("\n"); } } printf("=== %d protocol ===\n", s->protocol_n); @@ -884,6 +919,7 @@ sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_call args.tagid = f->tag; args.subtype = f->st; args.mainindex = f->key; + args.extra = f->extra; if (type & SPROTO_TARRAY) { args.type = type & ~SPROTO_TARRAY; sz = encode_array(cb, &args, data, size); @@ -1116,6 +1152,7 @@ sproto_decode(const struct sproto_type *st, const void * data, int size, sproto_ args.subtype = f->st; args.index = 0; args.mainindex = f->key; + args.extra = f->extra; if (value < 0) { if (f->type & SPROTO_TARRAY) { if (decode_array(cb, &args, currentdata)) { diff --git a/lualib-src/sproto/sproto.h b/lualib-src/sproto/sproto.h index c38a12c0..cf40497b 100644 --- a/lualib-src/sproto/sproto.h +++ b/lualib-src/sproto/sproto.h @@ -9,11 +9,16 @@ struct sproto_type; #define SPROTO_REQUEST 0 #define SPROTO_RESPONSE 1 +// type (sproto_arg.type) #define SPROTO_TINTEGER 0 #define SPROTO_TBOOLEAN 1 #define SPROTO_TSTRING 2 #define SPROTO_TSTRUCT 3 +// sub type of string (sproto_arg.extra) +#define SPROTO_TSTRING_STRING 0 +#define SPROTO_TSTRING_BINARY 1 + #define SPROTO_CB_ERROR -1 #define SPROTO_CB_NIL -2 #define SPROTO_CB_NOARRAY -3 @@ -41,6 +46,7 @@ struct sproto_arg { int length; int index; // array base 1 int mainindex; // for map + int extra; // SPROTO_TINTEGER: decimal ; SPROTO_TSTRING 0:utf8 string 1:binary }; typedef int (*sproto_callback)(const struct sproto_arg *args); diff --git a/lualib/sprotoparser.lua b/lualib/sprotoparser.lua index 03524ac0..898a1cbc 100644 --- a/lualib/sprotoparser.lua +++ b/lualib/sprotoparser.lua @@ -70,6 +70,7 @@ local name = C(word) local typename = C(word * ("." * word) ^ 0) local tag = R"09" ^ 1 / tonumber local mainkey = "(" * blank0 * name * blank0 * ")" +local decimal = "(" * blank0 * C(tag) * blank0 * ")" local function multipat(pat) return Ct(blank0 * (pat * blanks) ^ 0 * pat^0 * blank0) @@ -81,7 +82,7 @@ end local typedef = P { "ALL", - FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^-1 * typename * mainkey^0)), + FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^-1 * typename * (mainkey + decimal)^0)), STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}", TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ), SUBPROTO = Ct((C"request" + C"response") * blanks * (typename + V"STRUCT")), @@ -134,8 +135,12 @@ function convert.type(all, obj) end local mainkey = f[5] if mainkey then - assert(field.array) - field.key = mainkey + if fieldtype == "integer" then + field.decimal = mainkey + else + assert(field.array) + field.key = mainkey + end end field.typename = fieldtype else @@ -167,6 +172,7 @@ local buildin_types = { integer = 0, boolean = 1, string = 2, + binary = 2, -- binary is a sub type of string } local function checktype(types, ptype, t) @@ -275,7 +281,11 @@ local function packfield(f) table.insert(strtbl, "\0\0") -- name (tag = 0, ref an object) if f.buildin then table.insert(strtbl, packvalue(f.buildin)) -- buildin (tag = 1) - table.insert(strtbl, "\1\0") -- skip (tag = 2) + if f.extra then + table.insert(strtbl, packvalue(f.extra)) -- f.buildin can be integer or string + else + table.insert(strtbl, "\1\0") -- skip (tag = 2) + end table.insert(strtbl, packvalue(f.tag)) -- tag (tag = 3) else table.insert(strtbl, "\1\0") -- skip (tag = 1) @@ -299,8 +309,12 @@ local function packtype(name, t, alltypes) tmp.array = f.array tmp.name = f.name tmp.tag = f.tag + tmp.extra = f.decimal tmp.buildin = buildin_types[f.typename] + if f.typename == "binary" then + tmp.extra = 1 -- binary is sub type of string + end local subtype if not tmp.buildin then subtype = assert(alltypes[f.typename])