2022-05-26 13:05:04 +00:00
|
|
|
--[[
|
|
|
|
uuid generation
|
|
|
|
]]
|
|
|
|
|
|
|
|
local path = (...):gsub("uuid", "")
|
|
|
|
|
|
|
|
local uuid = {}
|
|
|
|
|
2023-01-09 15:11:53 +00:00
|
|
|
--(internal; use a provided random generator object, or not)
|
|
|
|
local function _random(rng, ...)
|
|
|
|
if rng then return rng:random(...) end
|
2023-01-09 15:25:26 +00:00
|
|
|
if love then return love.math.random(...) end
|
2023-01-09 15:11:53 +00:00
|
|
|
return math.random(...)
|
2022-05-26 13:05:04 +00:00
|
|
|
end
|
|
|
|
|
2023-01-09 15:02:32 +00:00
|
|
|
local uuid4_template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
2022-05-26 13:05:04 +00:00
|
|
|
|
|
|
|
--generate a UUID version 4 (random)
|
2023-01-09 15:06:07 +00:00
|
|
|
function uuid.uuid4(rng)
|
2023-01-09 15:23:11 +00:00
|
|
|
-- x should be 0x0-0xF, the single y should be 0x8-0xB
|
|
|
|
-- 4 should always just be 4 (denoting uuid version)
|
2023-01-09 15:41:02 +00:00
|
|
|
local out = uuid4_template:gsub("[xy]", function (c)
|
|
|
|
return string.format(
|
|
|
|
"%x",
|
|
|
|
c == "x" and _random(rng, 0x0, 0xF) or _random(rng, 0x8, 0xB)
|
|
|
|
)
|
2022-05-26 13:05:04 +00:00
|
|
|
end)
|
2023-01-09 15:23:11 +00:00
|
|
|
|
|
|
|
return out
|
2022-05-26 13:05:04 +00:00
|
|
|
end
|
|
|
|
|
2023-01-09 17:01:46 +00:00
|
|
|
-- crockford's base32 https://en.wikipedia.org/wiki/Base32
|
2023-01-09 16:51:12 +00:00
|
|
|
local _encoding = {
|
|
|
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
|
|
|
"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "M",
|
|
|
|
"N", "P", "Q", "R", "S", "T", "V", "W", "X", "Y", "Z"
|
|
|
|
}
|
|
|
|
|
|
|
|
--since ulid needs time since unix epoch with miliseconds, we can just
|
|
|
|
--use socket. if that's not loaded, they'll have to provide their own
|
|
|
|
local function _now(time_func, ...)
|
|
|
|
if package.loaded.socket then return package.loaded.socket.gettime(...) end
|
|
|
|
if require("socket") then return require("socket").gettime(...) end
|
|
|
|
if time_func then return time_func(...) end
|
|
|
|
error("assertion failed: socket can't be found and no time function provided")
|
|
|
|
end
|
|
|
|
|
|
|
|
--generate the time part of an ulid
|
|
|
|
local function _encode_time(time)
|
|
|
|
time = math.floor((time or _now()) * 1000)
|
|
|
|
|
|
|
|
local out = {}
|
|
|
|
|
|
|
|
for i = 10, 1, -1 do
|
|
|
|
local mod = time % #_encoding
|
|
|
|
out[i] = _encoding[mod + 1]
|
|
|
|
time = (time - mod) / #_encoding
|
|
|
|
end
|
|
|
|
|
|
|
|
return table.concat(out)
|
|
|
|
end
|
|
|
|
|
2023-01-09 17:01:46 +00:00
|
|
|
--generate the random part of an ulid
|
2023-01-09 16:51:12 +00:00
|
|
|
local function _encode_random(rng)
|
|
|
|
local out = {}
|
|
|
|
|
|
|
|
for i = 1, 10 do
|
|
|
|
out[i] = _encoding[math.floor(_random(rng) * #_encoding) + 1]
|
|
|
|
end
|
|
|
|
|
|
|
|
return table.concat(out)
|
|
|
|
end
|
|
|
|
|
2023-01-09 17:01:46 +00:00
|
|
|
--generate an ULID using this rng at this time
|
|
|
|
--see https://github.com/ulid/spec
|
2023-01-09 16:51:12 +00:00
|
|
|
--implementation based on https://github.com/Tieske/ulid.lua
|
2023-01-09 17:02:00 +00:00
|
|
|
function uuid.ulid(rng, time)
|
|
|
|
return _encode_time(time) .. _encode_random(rng)
|
2023-01-09 16:51:12 +00:00
|
|
|
end
|
|
|
|
|
2022-05-26 13:05:04 +00:00
|
|
|
return uuid
|