From 72511ff0ac2d6b7bbf46d53861abed62080efba5 Mon Sep 17 00:00:00 2001 From: Terror Date: Tue, 2 Jul 2024 01:06:56 +1200 Subject: [PATCH] [Redbean] Add UuidV7 method (#1213) To Complete #1140 add UUID version 7 to Redbean --- test/tool/net/uuidv7_test.lua | 25 +++++++++++++ tool/net/definitions.lua | 4 +++ tool/net/help.txt | 5 ++- tool/net/lfuncs.c | 68 +++++++++++++++++++++++++++++++++++ tool/net/lfuncs.h | 1 + tool/net/redbean.c | 1 + 6 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 test/tool/net/uuidv7_test.lua diff --git a/test/tool/net/uuidv7_test.lua b/test/tool/net/uuidv7_test.lua new file mode 100644 index 000000000..063a9da94 --- /dev/null +++ b/test/tool/net/uuidv7_test.lua @@ -0,0 +1,25 @@ +-- Copyright 2024 Justine Alexandra Roberts Tunney +-- +-- Permission to use, copy, modify, and/or distribute this software for +-- any purpose with or without fee is hereby granted, provided that the +-- above copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +-- AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +-- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +-- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +-- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +-- PERFORMANCE OF THIS SOFTWARE. +for _ = 1, 1000 do + local uuid = UuidV7() + assert(#uuid == 36) + assert(string.sub(uuid, 9, 9) == "-") + assert(string.sub(uuid, 14, 14) == "-") + assert(string.sub(uuid, 15, 15) == "7") + assert(string.sub(uuid, 19, 19) == "-") + local y = string.sub(uuid, 20, 20) + assert(y == "8" or y == "9" or y == "a" or y == "b") + assert(string.sub(uuid, 24, 24) == "-") +end diff --git a/tool/net/definitions.lua b/tool/net/definitions.lua index f6fecffda..2424f9241 100644 --- a/tool/net/definitions.lua +++ b/tool/net/definitions.lua @@ -1981,6 +1981,10 @@ function Underlong(str) end --- @return string function UuidV4() end +--- Generate a uuid_v7 +--- @return string +function UuidV7() end + ---@param x integer ---@return integer # position of first bit set. --- Passing `0` will raise an error. Same as the Intel x86 instruction BSF. diff --git a/tool/net/help.txt b/tool/net/help.txt index 4ea0be1f8..f031a83ae 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -1063,7 +1063,10 @@ FUNCTIONS This function is not available in unsecure mode. UuidV4() -> str - Returns an uuid v4 string. + Returns a uuid v4 string. + + UuidV7() -> str + Returns a uuid v7 string. Fetch(url:str[,body:str|{method=value:str,body=value:str,headers=table,...}]) ├─→ status:int, {header:str=value:str,...}, body:str diff --git a/tool/net/lfuncs.c b/tool/net/lfuncs.c index e8d566d94..798099c7d 100644 --- a/tool/net/lfuncs.c +++ b/tool/net/lfuncs.c @@ -858,6 +858,74 @@ int LuaUuidV4(lua_State *L) { return 1; } +int LuaUuidV7(lua_State *L) { + //See https://www.rfc-editor.org/rfc/rfc9562.html + char bin[16], uuid_str[37]; + struct timespec ts = timespec_real(); + uint64_t unix_ts_ms = (uint64_t)((ts.tv_sec * 1000) + (ts.tv_nsec / 1000000)); + int fractional_ms = (int)floor((double)((double)(ts.tv_nsec - (ts.tv_nsec / 1000000) * 1000000)/1000000) * 4096) <<4; + uint64_t rand_b = _rand64(); + int rand_a = fractional_ms | (rand_b & 0x000000000000000f); //use the last 4 bits of rand_b + + bin[0] = unix_ts_ms >> 050; + bin[1] = unix_ts_ms >> 040; + bin[2] = unix_ts_ms >> 030; + bin[3] = unix_ts_ms >> 020; + bin[4] = unix_ts_ms >> 010; + bin[5] = unix_ts_ms >> 000; + bin[6] = rand_a >> 010; + bin[7] = rand_a >> 000; + bin[8] = rand_b >> 070; + bin[9] = rand_b >> 060; + bin[10] = rand_b >> 050; + bin[11] = rand_b >> 040; + bin[12] = rand_b >> 030; + bin[13] = rand_b >> 020; + bin[14] = rand_b >> 010; + bin[15] = rand_b >> 000; + + uuid_str[0] = "0123456789abcdef"[(bin[0] & 0xf0) >>4]; + uuid_str[1] = "0123456789abcdef"[(bin[0] & 0x0f)]; + uuid_str[2] = "0123456789abcdef"[(bin[1] & 0xf0) >>4]; + uuid_str[3] = "0123456789abcdef"[(bin[1] & 0x0f)]; + uuid_str[4] = "0123456789abcdef"[(bin[2] & 0xf0) >>4]; + uuid_str[5] = "0123456789abcdef"[(bin[2] & 0x0f)]; + uuid_str[6] = "0123456789abcdef"[(bin[3] & 0xf0) >>4]; + uuid_str[7] = "0123456789abcdef"[(bin[3] & 0x0f)]; + uuid_str[8] = '-'; + uuid_str[9] = "0123456789abcdef"[(bin[4] & 0xf0) >>4]; + uuid_str[10] = "0123456789abcdef"[(bin[4] & 0x0f)]; + uuid_str[11] = "0123456789abcdef"[(bin[5] & 0xf0) >>4]; + uuid_str[12] = "0123456789abcdef"[(bin[5] & 0x0f)]; + uuid_str[13] = '-'; + uuid_str[14] = '7'; + uuid_str[15] = "0123456789abcdef"[(bin[6] & 0xf0) >>4]; + uuid_str[16] = "0123456789abcdef"[(bin[6] & 0x0f)]; + uuid_str[17] = "0123456789abcdef"[(bin[7] & 0xf0) >>4]; + uuid_str[18] = '-'; + uuid_str[19] = "0123456789abcdef"[(0x8 | ((bin[7] & 0x0f) >>2))]; + uuid_str[20] = "0123456789abcdef"[(bin[7] & 0x03) | (bin[8] & 0xf0) >>6]; //See https://www.rfc-editor.org/rfc/rfc9562.html#version_field + uuid_str[21] = "0123456789abcdef"[(bin[8] & 0x0f)]; + uuid_str[22] = "0123456789abcdef"[(bin[9] & 0xf0) >>4]; + uuid_str[23] = '-'; + uuid_str[24] = "0123456789abcdef"[(bin[9] & 0x0f)]; + uuid_str[25] = "0123456789abcdef"[(bin[10] & 0xf0) >>4]; + uuid_str[26] = "0123456789abcdef"[(bin[10] & 0x0f)]; + uuid_str[27] = "0123456789abcdef"[(bin[11] & 0xf0) >>4]; + uuid_str[28] = "0123456789abcdef"[(bin[11] & 0x0f)]; + uuid_str[29] = "0123456789abcdef"[(bin[12] & 0xf0) >>4]; + uuid_str[30] = "0123456789abcdef"[(bin[12] & 0x0f)]; + uuid_str[31] = "0123456789abcdef"[(bin[13] & 0xf0) >>4]; + uuid_str[32] = "0123456789abcdef"[(bin[13] & 0x0f)]; + uuid_str[33] = "0123456789abcdef"[(bin[14] & 0xf0) >>4]; + uuid_str[34] = "0123456789abcdef"[(bin[14] & 0x0f)]; + uuid_str[35] = "0123456789abcdef"[(bin[15] & 0xf0) >>4]; + uuid_str[36] = '\0'; + + lua_pushfstring(L, uuid_str); + return 1; +} + static dontinline int LuaHasherImpl(lua_State *L, size_t k, int H(const void *, size_t, uint8_t *)) { size_t n; diff --git a/tool/net/lfuncs.h b/tool/net/lfuncs.h index ab82c4e95..7bc3fc748 100644 --- a/tool/net/lfuncs.h +++ b/tool/net/lfuncs.h @@ -91,6 +91,7 @@ int LuaSlurp(lua_State *); int LuaUncompress(lua_State *); int LuaUnderlong(lua_State *); int LuaUuidV4(lua_State *); +int LuaUuidV7(lua_State *); int LuaVisualizeControlCodes(lua_State *); void LuaPushUrlView(lua_State *, struct UrlView *); diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 8696121e9..c87122c49 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -5364,6 +5364,7 @@ static const luaL_Reg kLuaFuncs[] = { {"Uncompress", LuaUncompress}, // {"Underlong", LuaUnderlong}, // {"UuidV4", LuaUuidV4}, // + {"UuidV7", LuaUuidV7}, // {"VisualizeControlCodes", LuaVisualizeControlCodes}, // {"Write", LuaWrite}, // {"bin", LuaBin}, //