aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/private/helpers.c
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2023-08-07 14:42:25 +0200
committerGitHub <noreply@github.com>2023-08-07 14:42:25 +0200
commit3a21c3afe61e5bb76f4b81c1a961b2558e2c8f0a (patch)
tree02d894cf470742f02a1d69e05078562abd7f4762 /src/nvim/api/private/helpers.c
parentef44e597294e4d0d9128ef69b6aa7481a54e17cb (diff)
parent51c754b62e795c49cfcf9df3ab492bdd53c61482 (diff)
downloadrneovim-3a21c3afe61e5bb76f4b81c1a961b2558e2c8f0a.tar.gz
rneovim-3a21c3afe61e5bb76f4b81c1a961b2558e2c8f0a.tar.bz2
rneovim-3a21c3afe61e5bb76f4b81c1a961b2558e2c8f0a.zip
Merge pull request #24524 from bfredl/typed_keys
refactor(api): use typed keysets
Diffstat (limited to 'src/nvim/api/private/helpers.c')
-rw-r--r--src/nvim/api/private/helpers.c87
1 files changed, 83 insertions, 4 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index d0c8ab4dd4..bbc87422d0 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -16,6 +16,7 @@
#include "nvim/api/private/converter.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/private/validate.h"
#include "nvim/ascii.h"
#include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h"
@@ -915,17 +916,84 @@ free_exit:
return (HlMessage)KV_INITIAL_VALUE;
}
-bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err)
+// see also nlua_pop_keydict for the lua specific implementation
+bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error *err)
{
for (size_t i = 0; i < dict.size; i++) {
String k = dict.items[i].key;
- Object *field = hashy(rv, k.data, k.size);
+ KeySetLink *field = hashy(k.data, k.size);
if (!field) {
api_set_error(err, kErrorTypeValidation, "Invalid key: '%.*s'", (int)k.size, k.data);
return false;
}
- *field = dict.items[i].value;
+ if (field->opt_index >= 0) {
+ OptKeySet *ks = (OptKeySet *)retval;
+ ks->is_set_ |= (1ULL << field->opt_index);
+ }
+
+ char *mem = ((char *)retval + field->ptr_off);
+ Object *value = &dict.items[i].value;
+ if (field->type == kObjectTypeNil) {
+ *(Object *)mem = *value;
+ } else if (field->type == kObjectTypeInteger) {
+ VALIDATE_T(field->str, kObjectTypeInteger, value->type, {
+ return false;
+ });
+ *(Integer *)mem = value->data.integer;
+ } else if (field->type == kObjectTypeFloat) {
+ Float *val = (Float *)mem;
+ if (value->type == kObjectTypeInteger) {
+ *val = (Float)value->data.integer;
+ } else {
+ VALIDATE_T(field->str, kObjectTypeFloat, value->type, {
+ return false;
+ });
+ *val = value->data.floating;
+ }
+ } else if (field->type == kObjectTypeBoolean) {
+ // caller should check HAS_KEY to override the nil behavior, or GET_BOOL_OR_TRUE
+ // to directly use true when nil
+ *(Boolean *)mem = api_object_to_bool(*value, field->str, false, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
+ } else if (field->type == kObjectTypeString) {
+ VALIDATE_T(field->str, kObjectTypeString, value->type, {
+ return false;
+ });
+ *(String *)mem = value->data.string;
+ } else if (field->type == kObjectTypeArray) {
+ VALIDATE_T(field->str, kObjectTypeArray, value->type, {
+ return false;
+ });
+ *(Array *)mem = value->data.array;
+ } else if (field->type == kObjectTypeDictionary) {
+ Dictionary *val = (Dictionary *)mem;
+ // allow empty array as empty dict for lua (directly or via lua-client RPC)
+ if (value->type == kObjectTypeArray && value->data.array.size == 0) {
+ *val = (Dictionary)ARRAY_DICT_INIT;
+ } else if (value->type == kObjectTypeDictionary) {
+ *val = value->data.dictionary;
+ } else {
+ api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type));
+ return false;
+ }
+ } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
+ || field->type == kObjectTypeTabpage) {
+ if (value->type == kObjectTypeInteger || value->type == field->type) {
+ *(handle_T *)mem = (handle_T)value->data.integer;
+ } else {
+ api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type));
+ return false;
+ }
+ } else if (field->type == kObjectTypeLuaRef) {
+ api_set_error(err, kErrorTypeValidation, "Invalid key: '%.*s' is only allowed from Lua",
+ (int)k.size, k.data);
+ return false;
+ } else {
+ abort();
+ }
}
return true;
@@ -934,7 +1002,18 @@ bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err
void api_free_keydict(void *dict, KeySetLink *table)
{
for (size_t i = 0; table[i].str; i++) {
- api_free_object(*(Object *)((char *)dict + table[i].ptr_off));
+ char *mem = ((char *)dict + table[i].ptr_off);
+ if (table[i].type == kObjectTypeNil) {
+ api_free_object(*(Object *)mem);
+ } else if (table[i].type == kObjectTypeString) {
+ api_free_string(*(String *)mem);
+ } else if (table[i].type == kObjectTypeArray) {
+ api_free_array(*(Array *)mem);
+ } else if (table[i].type == kObjectTypeDictionary) {
+ api_free_dictionary(*(Dictionary *)mem);
+ } else if (table[i].type == kObjectTypeLuaRef) {
+ api_free_luaref(*(LuaRef *)mem);
+ }
}
}