diff --git a/lualib-src/sproto/README.md b/lualib-src/sproto/README.md index e5011fc9..7a2ab977 100644 --- a/lualib-src/sproto/README.md +++ b/lualib-src/sproto/README.md @@ -104,7 +104,7 @@ local sprotocore = require "sproto.core" -- optional * `sproto.new(spbin)` creates a sproto object by a schema binary string (generates by parser). * `sprotocore.newproto(spbin)` creates a sproto c object by a schema binary string (generates by parser). * `sproto.sharenew(spbin)` share a sproto object from a sproto c object (generates by sprotocore.newproto). -* `sproto.parse(schema)` creares a sproto object by a schema text string (by calling parser.parse) +* `sproto.parse(schema)` creates a sproto object by a schema text string (by calling parser.parse) * `sproto:exist_type(typename)` detect whether a type exist in sproto object. * `sproto:encode(typename, luatable)` encodes a lua table with typename into a binary string. * `sproto:decode(typename, blob [,sz])` decodes a binary string generated by sproto.encode with typename. If blob is a lightuserdata (C ptr), sz (integer) is needed. @@ -217,7 +217,7 @@ Types * **string** : string * **binary** : binary string (it's a sub type of string) * **integer** : integer, the max length of an integer is signed 64bit. It can be a fixed-point number with specified precision. -* **double** : double, floating-point number. +* **double** : double precision floating-point number, satisfy [the IEEE 754 standard](https://en.wikipedia.org/wiki/Double-precision_floating-point_format). * **boolean** : true or false You can add * before the typename to declare an array. @@ -230,7 +230,7 @@ User defined type can be any name in alphanumeric characters except the build-in * Where are double or real types? -I have been using Google protocol buffers for many years in many projects, and I found the real types were seldom used. If you really need it, you can use string to serialize the double numbers. When you need decimal, you can specify the fixed-point presision. +I have been using Google protocol buffers for many years in many projects, and I found the real types were seldom used. If you really need it, you can use string to serialize the double numbers. When you need decimal, you can specify the fixed-point precision. **NOTE** : `double` is supported now. @@ -263,6 +263,7 @@ For integer array, an additional byte (4 or 8) to indicate the value is 32bit or Read the examples below to see more details. Notice: If the tag is not declared in schema, the decoder will simply ignore the field for protocol version compatibility. +Notice more: all examples are tested in `test_wire_protocol.lua`, update `test_wire_protocol.lua` when update examples. ``` .Person { @@ -277,6 +278,9 @@ Notice: If the tag is not declared in schema, the decoder will simply ignore the bools 1 : *boolean number 2 : integer bignumber 3 : integer + double 4 : double + doubles 5 : *double + fpn 6 : integer(2) } ``` @@ -405,6 +409,39 @@ A0 86 01 00 (100000, 32bit integer) 00 1C F4 AB FD FF FF FF (-10000000000, 64bit integer) ``` +Example 7: +``` +data { + double = 0.01171875, + doubles = {0.01171875, 23, 4} +} + +03 00 (fn = 3) +07 00 (skip id = 3) +00 00 (id = 4, value in data part) +00 00 (id = 5, value in data part) + +08 00 00 00 (sizeof number, data part) +00 00 00 00 00 00 88 3f (0.01171875, 64bit double) + +19 00 00 00 (sizeof doubles) +08 (sizeof double) +00 00 00 00 00 00 88 3f (0.01171875, 64bit double) +00 00 00 00 00 00 37 40 (23, 64bit double) +00 00 00 00 00 00 10 40 (4, 64bit double) +``` + +Example 8: +``` +data { + fpn = 1.82, +} + +02 00 (fn = 2) +0b 00 (skip id = 5) +6e 01 (id = 6, value = 0x16e/2 - 1 = 182) +``` + 0 Packing ======= diff --git a/lualib-src/sproto/lsproto.c b/lualib-src/sproto/lsproto.c index 605ec0c1..74b5397e 100644 --- a/lualib-src/sproto/lsproto.c +++ b/lualib-src/sproto/lsproto.c @@ -84,14 +84,16 @@ lua_seti(lua_State *L, int index, lua_Integer n) { #if defined(SPROTO_WEAK_TYPE) static int64_t tointegerx (lua_State *L, int idx, int *isnum) { - int64_t v; - if (lua_isnumber(L, idx)) { - v = (int64_t)(round(lua_tonumber(L, idx))); - if (isnum) *isnum = 1; - return v; - } else { - return lua_tointegerx(L, idx, isnum); + int _isnum = 0; + int64_t v = lua_tointegerx(L, idx, &_isnum); + if (!_isnum){ + double num = lua_tonumberx(L, idx, &_isnum); + if(_isnum) { + v = (int64_t)llround(num); + } } + if(isnum) *isnum = _isnum; + return v; } static int @@ -613,7 +615,7 @@ getbuffer(lua_State *L, int index, size_t *sz) { /* lightuserdata sproto_type string source / (lightuserdata , integer) - return table + return table, sz(decoded bytes) */ static int ldecode(lua_State *L) { diff --git a/lualib-src/sproto/sproto.c b/lualib-src/sproto/sproto.c index 47d1527b..edaf37f6 100644 --- a/lualib-src/sproto/sproto.c +++ b/lualib-src/sproto/sproto.c @@ -898,7 +898,7 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz buffer = encode_integer_array(cb,args,buffer,size, &noarray); if (buffer == NULL) return -1; - + if (noarray) { return 0; } @@ -1088,26 +1088,33 @@ expand64(uint32_t v) { return value; } +static int +decode_empty_array(sproto_callback cb, struct sproto_arg *args) { + // It's empty array, call cb with index == -1 to create the empty array. + args->index = -1; + args->value = NULL; + args->length = 0; + return cb(args); +} + static int decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) { uint32_t sz = todword(stream); int type = args->type; int i; if (sz == 0) { - // It's empty array, call cb with index == -1 to create the empty array. - args->index = -1; - args->value = NULL; - args->length = 0; - cb(args); - return 0; - } + return decode_empty_array(cb, args); + } stream += SIZEOF_LENGTH; switch (type) { case SPROTO_TDOUBLE: case SPROTO_TINTEGER: { + if (--sz == 0) { + // An empty array but with a len prefix + return decode_empty_array(cb, args); + } int len = *stream; ++stream; - --sz; if (len == SIZEOF_INT32) { if (sz % SIZEOF_INT32 != 0) return -1;