aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/shared.lua
diff options
context:
space:
mode:
authorGregory Anders <8965202+gpanders@users.noreply.github.com>2024-05-27 08:08:23 -0500
committerGitHub <noreply@github.com>2024-05-27 08:08:23 -0500
commit48251134ee59a3e2f0aeb89608fa820c21b25d4f (patch)
tree62856aa0110c3f3bcd169a19f2b2a3a31abbf422 /runtime/lua/vim/shared.lua
parentc4eb0b64bd4923a72fe737837cfe234c80fb539c (diff)
downloadrneovim-48251134ee59a3e2f0aeb89608fa820c21b25d4f.tar.gz
rneovim-48251134ee59a3e2f0aeb89608fa820c21b25d4f.tar.bz2
rneovim-48251134ee59a3e2f0aeb89608fa820c21b25d4f.zip
perf: add fast path to vim.validate (#28977)
For many small/simple functions (like those found in shared.lua), the runtime of vim.validate can far exceed the runtime of the function itself. Add an "overload" to vim.validate that uses a simple assertion pattern, rather than parsing a full "validation spec".
Diffstat (limited to 'runtime/lua/vim/shared.lua')
-rw-r--r--runtime/lua/vim/shared.lua76
1 files changed, 62 insertions, 14 deletions
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index e9e4326057..2641d1feb0 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -214,7 +214,7 @@ end
---@param t table<T, any> (table) Table
---@return T[] : List of keys
function vim.tbl_keys(t)
- vim.validate({ t = { t, 't' } })
+ vim.validate('t', t, 'table')
--- @cast t table<any,any>
local keys = {}
@@ -231,7 +231,7 @@ end
---@param t table<any, T> (table) Table
---@return T[] : List of values
function vim.tbl_values(t)
- vim.validate({ t = { t, 't' } })
+ vim.validate('t', t, 'table')
local values = {}
for _, v in
@@ -332,7 +332,7 @@ end
---@param value any Value to compare
---@return boolean `true` if `t` contains `value`
function vim.list_contains(t, value)
- vim.validate({ t = { t, 't' } })
+ vim.validate('t', t, 'table')
--- @cast t table<any,any>
for _, v in ipairs(t) do
@@ -350,7 +350,7 @@ end
---@param t table Table to check
---@return boolean `true` if `t` is empty
function vim.tbl_isempty(t)
- vim.validate({ t = { t, 't' } })
+ vim.validate('t', t, 'table')
return next(t) == nil
end
@@ -580,7 +580,7 @@ end
---@return fun(table: table<K, V>, index?: K):K, V # |for-in| iterator over sorted keys and their values
---@return T
function vim.spairs(t)
- assert(type(t) == 'table', ('expected table, got %s'):format(type(t)))
+ vim.validate('t', t, 'table')
--- @cast t table<any,any>
-- collect the keys
@@ -691,7 +691,7 @@ end
---@param t table Table
---@return integer : Number of non-nil values in table
function vim.tbl_count(t)
- vim.validate({ t = { t, 't' } })
+ vim.validate('t', t, 'table')
--- @cast t table<any,any>
local count = 0
@@ -723,7 +723,7 @@ end
---@param s string String to trim
---@return string String with whitespace removed from its beginning and end
function vim.trim(s)
- vim.validate({ s = { s, 's' } })
+ vim.validate('s', s, 'string')
return s:match('^%s*(.*%S)') or ''
end
@@ -733,7 +733,7 @@ end
---@param s string String to escape
---@return string %-escaped pattern string
function vim.pesc(s)
- vim.validate({ s = { s, 's' } })
+ vim.validate('s', s, 'string')
return (s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1'))
end
@@ -743,7 +743,8 @@ end
---@param prefix string Prefix to match
---@return boolean `true` if `prefix` is a prefix of `s`
function vim.startswith(s, prefix)
- vim.validate({ s = { s, 's' }, prefix = { prefix, 's' } })
+ vim.validate('s', s, 'string')
+ vim.validate('prefix', prefix, 'string')
return s:sub(1, #prefix) == prefix
end
@@ -753,7 +754,8 @@ end
---@param suffix string Suffix to match
---@return boolean `true` if `suffix` is a suffix of `s`
function vim.endswith(s, suffix)
- vim.validate({ s = { s, 's' }, suffix = { suffix, 's' } })
+ vim.validate('s', s, 'string')
+ vim.validate('suffix', suffix, 'string')
return #suffix == 0 or s:sub(-#suffix) == suffix
end
@@ -877,8 +879,30 @@ do
return true
end
- --- Validates a parameter specification (types and values). Specs are evaluated in alphanumeric
- --- order, until the first failure.
+ --- Validate function arguments.
+ ---
+ --- This function has two valid forms:
+ ---
+ --- 1. vim.validate(name: str, value: any, type: string, optional?: bool)
+ --- 2. vim.validate(spec: table)
+ ---
+ --- Form 1 validates that argument {name} with value {value} has the type
+ --- {type}. {type} must be a value returned by |lua-type()|. If {optional} is
+ --- true, then {value} may be null. This form is significantly faster and
+ --- should be preferred for simple cases.
+ ---
+ --- Example:
+ ---
+ --- ```lua
+ --- function vim.startswith(s, prefix)
+ --- vim.validate('s', s, 'string')
+ --- vim.validate('prefix', prefix, 'string')
+ --- ...
+ --- end
+ --- ```
+ ---
+ --- Form 2 validates a parameter specification (types and values). Specs are
+ --- evaluated in alphanumeric order, until the first failure.
---
--- Usage example:
---
@@ -930,8 +954,32 @@ do
--- only if the argument is valid. Can optionally return an additional
--- informative error message as the second returned value.
--- - msg: (optional) error string if validation fails
- function vim.validate(opt)
- local ok, err_msg = is_valid(opt)
+ --- @overload fun(name: string, val: any, expected: string, optional?: boolean)
+ function vim.validate(opt, ...)
+ local ok = false
+ local err_msg ---@type string?
+ local narg = select('#', ...)
+ if narg == 0 then
+ ok, err_msg = is_valid(opt)
+ elseif narg >= 2 then
+ -- Overloaded signature for fast/simple cases
+ local name = opt --[[@as string]]
+ local v, expected, optional = ... ---@type string, string, boolean?
+ local actual = type(v)
+
+ ok = (actual == expected) or (v == nil and optional == true)
+ if not ok then
+ err_msg = ('%s: expected %s, got %s%s'):format(
+ name,
+ expected,
+ actual,
+ v and (' (%s)'):format(v) or ''
+ )
+ end
+ else
+ error('invalid arguments')
+ end
+
if not ok then
error(err_msg, 2)
end