diff --git a/LUA_API.rst b/LUA_API.rst
index 0b6ae863b..f40b786d2 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -121,6 +121,12 @@ or as a result of calling the ``_field()`` method.
They behave as structs with one field ``value`` of the right type.
+To make working with numeric buffers easier, they also allow
+numeric indices. Note that other than excluding negative values
+no bound checking is performed, since buffer length is not available.
+Index 0 is equivalent to the ``value`` field.
+
+
Struct references
-----------------
diff --git a/Lua API.html b/Lua API.html
index 2df8a7f22..3edcfd274 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -453,6 +453,10 @@ that don't fit any of the other reference types. Such
references can only appear as a value of a pointer field,
or as a result of calling the _field() method.
To make working with numeric buffers easier, they also allow
+numeric indices. Note that other than excluding negative values
+no bound checking is performed, since buffer length is not available.
+Index 0 is equivalent to the value field.
diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp
index c58c25d11..8548c5d0a 100644
--- a/library/LuaTypes.cpp
+++ b/library/LuaTypes.cpp
@@ -635,6 +635,28 @@ static int meta_struct_next(lua_State *state)
return 2;
}
+/**
+ * Field lookup for primitive refs: behave as a quasi-array with numeric indices.
+ */
+static type_identity *find_primitive_field(lua_State *state, int field, const char *mode, uint8_t **ptr)
+{
+ if (lua_type(state, field) == LUA_TNUMBER)
+ {
+ int idx = lua_tointeger(state, field);
+ if (idx < 0)
+ field_error(state, 2, "negative index", mode);
+
+ lua_rawgetp(state, UPVAL_METATABLE, &DFHACK_IDENTITY_FIELD_TOKEN);
+ auto id = (type_identity *)lua_touserdata(state, -1);
+ lua_pop(state, 1);
+
+ *ptr += int(id->byte_size()) * idx;
+ return id;
+ }
+
+ return (type_identity*)find_field(state, field, mode);
+}
+
/**
* Metamethod: __index for primitives, i.e. simple object references.
* Fields point to identity, or NULL for metafields.
@@ -642,7 +664,7 @@ static int meta_struct_next(lua_State *state)
static int meta_primitive_index(lua_State *state)
{
uint8_t *ptr = get_object_addr(state, 1, 2, "read");
- auto type = (type_identity*)find_field(state, 2, "read");
+ auto type = find_primitive_field(state, 2, "read", &ptr);
if (!type)
return 1;
type->lua_read(state, 2, ptr);
@@ -655,7 +677,7 @@ static int meta_primitive_index(lua_State *state)
static int meta_primitive_newindex(lua_State *state)
{
uint8_t *ptr = get_object_addr(state, 1, 2, "write");
- auto type = (type_identity*)find_field(state, 2, "write");
+ auto type = find_primitive_field(state, 2, "write", &ptr);
if (!type)
field_error(state, 2, "builtin property or method", "write");
type->lua_write(state, 2, ptr, 3);