util.hashring: Support associating arbitrary data with nodes
In this API, a 'node' is always a simple text string. Sometimes the caller may
have a more complex structure representing a node, but the hash ring is really
only concerned with the node's name.
This API change allows :add_nodes() to take a table of `node_name = value`
pairs, as well as the simple array of node names previously accepted.
The 'value' of the selected node is returned as a new second result from
:get_node().
If no value is passed when a node is added, it defaults to `true` (as before,
but this was never previously exposed).
local enum ptr_error
"invalid-table"
"invalid-path"
end
local function unescape_token(escaped_token : string) : string
local unescaped = escaped_token:gsub("~1", "/"):gsub("~0", "~")
return unescaped
end
local function resolve_json_pointer(ref : table, path : string) : any, ptr_error
local ptr_len = #path+1
for part, pos in path:gmatch("/([^/]*)()") do
local token = unescape_token(part)
if not ref is table then
return nil
end
local idx = next(ref)
local new_ref : any
if idx is string then
new_ref = ref[token]
elseif idx is integer then
local i = tonumber(token)
if token == "-" then i = #ref + 1 end
new_ref = ref[i+1]
else
return nil, "invalid-table"
end
if pos as integer == ptr_len then
return new_ref
elseif new_ref is table then
ref = new_ref
elseif not ref is table then
return nil, "invalid-path"
end
end
return ref
end
return {
resolve = resolve_json_pointer,
}