Problem
qd.pairs and the __newindex materialization path in lua/quickdecode.lua currently walk the object cursor from the start on every step. For an object with N keys, full enumeration is O(N²).
This is acceptable for the primary use case — read a handful of known keys — but becomes a bottleneck when encoding a fully-materialized object with many keys.
Proposal
Add a stateful iterator to the FFI surface:
// include/lua_quick_decode.h
typedef struct qjd_iter qjd_iter;
// Allocate an iterator positioned at the first key of the object/array at `path`.
// Returns NULL on OOM or if `path` does not point to an object/array.
qjd_iter *qjd_iter_init(const qjd_doc *doc, const char *path, size_t path_len);
// Advance to next entry. Returns QJD_OK while entries remain, QJD_NOT_FOUND when exhausted.
// On QJD_OK, *key_ptr / *key_len are set for object keys (NULL/0 for arrays).
// Value type and value getters operate on the current position via a companion cursor.
qjd_err qjd_iter_next(qjd_iter *it,
const char **key_ptr, size_t *key_len,
qjd_type *type_out);
void qjd_iter_free(qjd_iter *it);
The LuaJIT wrapper would use this to provide an O(N) qd.pairs on objects.
Notes
qjd_iter holds a Cursor (idx_start, idx_end) that advances by one key/value pair per qjd_iter_next call — no re-scan from the root.
- Must still wrap the body in
catch_unwind per the FFI panic barrier convention in src/ffi.rs.
- Existing
qd.pairs / qd.ipairs semantics stay unchanged at the Lua level; the iterator is an implementation detail.
- The
__newindex materialization path in the lazy-table API is the secondary beneficiary.
Problem
qd.pairsand the__newindexmaterialization path inlua/quickdecode.luacurrently walk the object cursor from the start on every step. For an object with N keys, full enumeration is O(N²).This is acceptable for the primary use case — read a handful of known keys — but becomes a bottleneck when encoding a fully-materialized object with many keys.
Proposal
Add a stateful iterator to the FFI surface:
The LuaJIT wrapper would use this to provide an O(N)
qd.pairson objects.Notes
qjd_iterholds aCursor(idx_start,idx_end) that advances by one key/value pair perqjd_iter_nextcall — no re-scan from the root.catch_unwindper the FFI panic barrier convention insrc/ffi.rs.qd.pairs/qd.ipairssemantics stay unchanged at the Lua level; the iterator is an implementation detail.__newindexmaterialization path in the lazy-table API is the secondary beneficiary.