diff options
author | bfredl <bjorn.linse@gmail.com> | 2023-08-01 14:01:19 +0200 |
---|---|---|
committer | bfredl <bjorn.linse@gmail.com> | 2023-08-07 13:11:15 +0200 |
commit | 7bc93e0e2f246dd78026a3472d929a0fe450f70d (patch) | |
tree | 9e5b99830c3f08e0ffd75c7a0533b39033490a5b /src/nvim/api/private/helpers.c | |
parent | c01e624b0762b24a4988bf9474a57d5b6278d180 (diff) | |
download | rneovim-7bc93e0e2f246dd78026a3472d929a0fe450f70d.tar.gz rneovim-7bc93e0e2f246dd78026a3472d929a0fe450f70d.tar.bz2 rneovim-7bc93e0e2f246dd78026a3472d929a0fe450f70d.zip |
refactor(api): use typed keysets
Initially this is just for geting rid of boilerplate,
but eventually the types could get exposed as metadata
Diffstat (limited to 'src/nvim/api/private/helpers.c')
-rw-r--r-- | src/nvim/api/private/helpers.c | 87 |
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); + } } } |