aboutsummaryrefslogtreecommitdiff
path: root/src/cjson/lua_cjson.c
diff options
context:
space:
mode:
authorMichael Lingelbach <m.j.lbach@gmail.com>2021-09-23 13:39:47 -0400
committerMichael Lingelbach <m.j.lbach@gmail.com>2021-09-26 00:35:55 -0700
commit30fed27241cc2a8f930212375f994a7fa6c99008 (patch)
tree37e5ebc68bfbc835021640fda72be82c0074506d /src/cjson/lua_cjson.c
parent8decc9f52d7dbd8eeed3afdf86f800b3677d25ab (diff)
downloadrneovim-30fed27241cc2a8f930212375f994a7fa6c99008.tar.gz
rneovim-30fed27241cc2a8f930212375f994a7fa6c99008.tar.bz2
rneovim-30fed27241cc2a8f930212375f994a7fa6c99008.zip
feat(lua): expose lua-cjson as vim.json
* add vim.json.encode and vim.json.decode * use vim.NIL instead of cjson.null * resolve strict-prototypes warnings * The following benchmark shows an approximately 2.5x (750 ms vs 300 ms) improvement in deserialization performance over vim.fn.json_decode on a medium package.json ```lua local uv = vim.loop local function readfile(path) return end local json_url = "https://raw.githubusercontent.com/rust-analyzer/rust-analyzer/b24c8d5c89ee93d1172b4127564f5da3b0c88dad/editors/code/package.json" io.popen(string.format('curl -v -f -L -O %q &> /dev/null', json_url)) local json_string = io.open('package.json'):read '*a' uv.update_time() local start = uv.hrtime() for i = 1,1000 do vim.fn.json_decode(json_string) end uv.update_time() print(string.format("Deserialization time vim.fn.json_decode: %s ms", (uv.hrtime() - start) * (1e-6))) uv.update_time() local start = uv.hrtime() for i = 1,1000 do vim.json.decode(json_string) end uv.update_time() print(string.format("Deserialization time vim.json.decode: %s ms", (uv.hrtime() - start) * (1e-6))) ``` Co-Authored-By: Björn Linse <bjorn.linse@gmail.com>
Diffstat (limited to 'src/cjson/lua_cjson.c')
-rw-r--r--src/cjson/lua_cjson.c41
1 files changed, 30 insertions, 11 deletions
diff --git a/src/cjson/lua_cjson.c b/src/cjson/lua_cjson.c
index 0c41cabac4..92d07963bd 100644
--- a/src/cjson/lua_cjson.c
+++ b/src/cjson/lua_cjson.c
@@ -44,6 +44,9 @@
#include <lua.h>
#include <lauxlib.h>
+#include "nvim/lua/executor.h"
+
+#include "lua_cjson.h"
#include "strbuf.h"
#include "fpconv.h"
@@ -79,7 +82,7 @@
#define DEFAULT_DECODE_INVALID_NUMBERS 1
#define DEFAULT_ENCODE_KEEP_BUFFER 1
#define DEFAULT_ENCODE_NUMBER_PRECISION 14
-#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 1
+#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 0
#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1
@@ -741,6 +744,7 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
{
int len;
int as_array = 0;
+ int as_empty_dict = 0;
int has_metatable;
switch (lua_type(l, -1)) {
@@ -763,10 +767,17 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
has_metatable = lua_getmetatable(l, -1);
if (has_metatable) {
+
+ nlua_pushref(l, nlua_empty_dict_ref);
+ if (lua_rawequal(l, -2, -1)) {
+ as_empty_dict = true;
+ } else {
+ lua_pop(l, 1);
lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
lua_rawget(l, LUA_REGISTRYINDEX);
as_array = lua_rawequal(l, -1, -2);
- lua_pop(l, 2);
+ }
+ lua_pop(l, 2);
}
if (as_array) {
@@ -775,7 +786,7 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
} else {
len = lua_array_length(l, cfg, json);
- if (len > 0 || (len == 0 && !cfg->encode_empty_table_as_object)) {
+ if (len > 0 || (len == 0 && !cfg->encode_empty_table_as_object && !as_empty_dict)) {
json_append_array(l, cfg, current_depth, json, len);
} else {
if (has_metatable) {
@@ -798,12 +809,20 @@ static void json_append_data(lua_State *l, json_config_t *cfg,
strbuf_append_mem(json, "null", 4);
break;
case LUA_TLIGHTUSERDATA:
- if (lua_touserdata(l, -1) == NULL) {
- strbuf_append_mem(json, "null", 4);
- } else if (lua_touserdata(l, -1) == &json_array) {
+ if (lua_touserdata(l, -1) == &json_array) {
json_append_array(l, cfg, current_depth, json, 0);
}
break;
+ case LUA_TUSERDATA:
+ nlua_pushref(l, nlua_nil_ref);
+ bool is_nil = lua_rawequal(l, -2, -1);
+ lua_pop(l, 1);
+ if (is_nil) {
+ strbuf_append_mem(json, "null", 4);
+ break;
+ } else {
+ FALLTHROUGH;
+ }
default:
/* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD,
* and LUA_TLIGHTUSERDATA) cannot be serialised */
@@ -1258,6 +1277,8 @@ static void json_parse_object_context(lua_State *l, json_parse_t *json)
/* Handle empty objects */
if (token.type == T_OBJ_END) {
+ nlua_pushref(l, nlua_empty_dict_ref); \
+ lua_setmetatable(l, -2); \
json_decode_ascend(json);
return;
}
@@ -1360,9 +1381,7 @@ static void json_process_value(lua_State *l, json_parse_t *json,
json_parse_array_context(l, json);
break;;
case T_NULL:
- /* In Lua, setting "t[k] = nil" will delete k from the table.
- * Hence a NULL pointer lightuserdata object is used instead */
- lua_pushlightuserdata(l, NULL);
+ nlua_pushref(l, nlua_nil_ref);
break;;
default:
json_throw_parse_error(l, json, "value", token);
@@ -1464,7 +1483,7 @@ static int json_protect_conversion(lua_State *l)
}
/* Return cjson module table */
-static int lua_cjson_new(lua_State *l)
+int lua_cjson_new(lua_State *l)
{
luaL_Reg reg[] = {
{ "encode", json_encode },
@@ -1517,7 +1536,7 @@ static int lua_cjson_new(lua_State *l)
compat_luaL_setfuncs(l, reg, 1);
/* Set cjson.null */
- lua_pushlightuserdata(l, NULL);
+ nlua_pushref(l, nlua_nil_ref);
lua_setfield(l, -2, "null");
/* Set cjson.empty_array_mt */