From dc7a7a0ed98e10f80c7ca5ce071300ada7922eab Mon Sep 17 00:00:00 2001
From: 1F616EMO~nya <root@1f616emo.xyz>
Date: Wed, 14 Aug 2024 00:39:50 +0800
Subject: [PATCH] Add `table.keyof()` (#14910)

---
 .luacheckrc                                |  2 +-
 builtin/common/misc_helpers.lua            | 10 ++++++++++
 builtin/common/tests/misc_helpers_spec.lua | 10 ++++++++++
 doc/lua_api.md                             |  4 ++++
 4 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/.luacheckrc b/.luacheckrc
index fcc04cab3..f184e6d59 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -20,7 +20,7 @@ read_globals = {
 	"PerlinNoise", "PerlinNoiseMap",
 
 	string = {fields = {"split", "trim"}},
-	table  = {fields = {"copy", "getn", "indexof", "insert_all"}},
+	table  = {fields = {"copy", "getn", "indexof", "keyof", "insert_all"}},
 	math   = {fields = {"hypot", "round"}},
 }
 
diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua
index 5e550348d..fb38c1b35 100644
--- a/builtin/common/misc_helpers.lua
+++ b/builtin/common/misc_helpers.lua
@@ -205,6 +205,16 @@ function table.indexof(list, val)
 	return -1
 end
 
+--------------------------------------------------------------------------------
+function table.keyof(tb, val)
+	for k, v in pairs(tb) do
+		if v == val then
+			return k
+		end
+	end
+	return nil
+end
+
 --------------------------------------------------------------------------------
 function string:trim()
 	return self:match("^%s*(.-)%s*$")
diff --git a/builtin/common/tests/misc_helpers_spec.lua b/builtin/common/tests/misc_helpers_spec.lua
index 65549c2e3..611c4b20f 100644
--- a/builtin/common/tests/misc_helpers_spec.lua
+++ b/builtin/common/tests/misc_helpers_spec.lua
@@ -166,6 +166,16 @@ describe("table", function()
 	it("indexof()", function()
 		assert.equal(1, table.indexof({"foo", "bar"}, "foo"))
 		assert.equal(-1, table.indexof({"foo", "bar"}, "baz"))
+		assert.equal(-1, table.indexof({[2] = "foo", [3] = "bar"}, "foo"))
+		assert.equal(-1, table.indexof({[1] = "foo", [3] = "bar"}, "bar"))
+	end)
+
+	it("keyof()", function()
+		assert.equal("a", table.keyof({a = "foo", b = "bar"}, "foo"))
+		assert.equal(nil, table.keyof({a = "foo", b = "bar"}, "baz"))
+		assert.equal(1, table.keyof({"foo", "bar"}, "foo"))
+		assert.equal(2, table.keyof({[2] = "foo", [3] = "bar"}, "foo"))
+		assert.equal(3, table.keyof({[1] = "foo", [3] = "bar"}, "bar"))
 	end)
 end)
 
diff --git a/doc/lua_api.md b/doc/lua_api.md
index 34e9c190a..836044a34 100644
--- a/doc/lua_api.md
+++ b/doc/lua_api.md
@@ -4025,6 +4025,10 @@ Helper functions
       the value `val` in the table `list`. Non-numerical indices are ignored.
       If `val` could not be found, `-1` is returned. `list` must not have
       negative indices.
+* `table.keyof(table, val)`: returns the key containing
+      the value `val` in the table `table`. If multiple keys contain `val`,
+      it is unspecified which key will be returned.
+      If `val` could not be found, `nil` is returned.
 * `table.insert_all(table, other_table)`:
     * Appends all values in `other_table` to `table` - uses `#table + 1` to
       find new indices.