This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Lua Lanes is a portable, message-passing multithreading library for Lua, implemented as a C++20 shared library (lanes_core.dll/.so) with a Lua wrapper (lanes.lua). It allows running multiple independent Lua states in parallel threads. Supported Lua versions: 5.1, 5.2, 5.3, 5.4, 5.5, and LuaJIT.
The primary build system is GNU Make (MSYS/MinGW on Windows). There is also a Visual Studio solution (Lanes.sln) and a CMakeLists.txt.
# Build lanes_core shared library only (default)
make
# Build C++ unit tests
make build_unit_tests
# Build deep_userdata_example side module
make build_DUE
# Build and run all unit tests
make run_unit_tests
# Debug build (unoptimized)
make debug
# Clean all build artifacts
make clean
# LuaRocks build
luarocks makeOn Mac OS X, building requires explicit C++20 flags:
luarocks make CC="env MACOSX_DEPLOYMENT_TARGET=13.3 gcc" LD="env MACOSX_DEPLOYMENT_TARGET=13.3 gcc" CFLAGS="-O2 -fPIC -std=c++20"# Run all integration tests
make test
# Run a single test by name (e.g., basic, linda_perf, cancel, timer)
make basic
make linda_perf
make cancel# Build and run all unit tests
make run_unit_tests
# List available test cases
unit_tests/UnitTests.exe --list-tests
# Run a specific test case
LUA_CPATH="./src/?.dll;./deep_userdata_example/?.dll" LUA_PATH="./src/?.lua;./tests/?.lua" unit_tests/UnitTests.exe -s scripted_tests.lane.tasking_cancelling
# Debug a specific unit test
make debug_unit_testsUnit test Lua scripts live in unit_tests/scripts/ organized by category: lane/, linda/, misc/, coro/.
The library consists of two components that must work together:
src/lanes.lua— Lua-side wrapper; usersrequire "lanes"which in turnrequire "lanes_core".src/lanes_core.dll/.so— C++20 compiled module; the actual implementation.
Universe (universe.hpp) — Process-wide singleton, stored as a full userdata in the master Lua state. Holds everything shared across all lanes: keeper states, lane tracker, allocator, configuration, timer Linda, and the selfdestruct chain. Retrieved via Universe::Get(L_).
Lane (lane.hpp) — One instance per Lua thread. Wraps a std::thread and two lua_States (S = master state, L = running state; differ only in coroutine mode). Status progression: Pending → Running/Waiting/Suspended → Done/Error/Cancelled.
Linda (linda.hpp) — Inter-lane communication primitive, implemented as deep userdata. Has a keeper state for queued message storage, plus readHappened/writeHappened condition variables.
Keeper / Keepers (keeper.hpp) — Dedicated Lua states acting as mailboxes for Linda send/receive operations. Keepers are mutex-protected; keeper_call() routes operations into a keeper state.
DeepPrelude / DeepFactory (deep.hpp) — The "deep userdata" system enabling objects to be shared (not copied) across lanes. External modules can implement DeepFactory to expose their own shared userdata types. A deep object stores a refcount and a pointer to its factory.
InterCopyContext (intercopycontext.hpp) — Handles cross-state value copying. Manages the lookup table mechanism that allows functions and registered userdata to be looked up by name in the destination state rather than copied as bytecode.
tools.hpp/cpp— Function lookup tables (kLookupRegKey), bytecode serialization,requireserialization.threading.hpp/cpp— Platform threading abstraction;threading_osx.hfor macOS specifics.allocator.hpp/cpp— Custom allocator support;ProtectedAllocatorwraps an allocator with a mutex.cancel.hpp/cpp— Cancellation request types and hook-based cancellation.tracker.hpp/cpp— Lane lifecycle tracking (forlanes.track_lanes()).state.hpp/cpp— Lua state creation and initialization helpers.compat.hpp/cpp— Cross-version Lua API compatibility helpers.macros_and_utils.hpp— Stack-check debug macros (STACK_CHECK_START_REL,STACK_CHECK).unique.hpp—Unique<>strong-typedef template;DECLARE_UNIQUE_TYPE/DECLARE_UNIQUE_ARITHMETIC_TYPEmacros.uniquekey.hpp—UniqueKey/RegistryUniqueKeytypes using xxh64 hashes to avoid registry key collisions.stackindex.hpp— DefinesStackIndex,TableIndex,UserValueIndex,UserValueCountUnique types.lindafactory.hpp/cpp— ConcreteDeepFactorysubclass forLinda; singletonLindaFactory::Instance.luaerrors.hpp—raise_lua_error/raise_luaL_errorwrappers; use these instead oflua_error/luaL_errordirectly.debugspew.hpp— Debug-spew tracing controlled byUSE_DEBUG_SPEW();DebugSpewIndentScopemanages indent depth.
When a lane calls linda:send(key, value):
- The value is inter-copied via
InterCopyContextinto the keeper state. keeper_call(keepercall_send, ...)runs inside the keeper's mutex.- Waiting receivers are notified via
Linda::writeHappened.
From lanesconf.h (authoritative source):
| Category | Convention |
|---|---|
| Indentation | Spaces only |
| Constants | k prefix + uppercase (e.g., kUniverseLightRegKey) |
| Function arguments | _ suffix (e.g., lua_State* L_) |
| Local variables | _ prefix + uppercase (e.g., _universe) |
| Static file-level variables | s prefix + uppercase |
| Static file-level functions | Uppercase start |
| Class/struct/enum types | Uppercase start |
| Static class members/methods | Uppercase start |
| Regular class members/methods | Lowercase start |
| Named lambda captures | Lowercase start |
| External API | In lanes namespace |
Registry keys use xxh64 hashes (generated at https://www.pelock.com/products/hash-calculator) to prevent name collisions across modules.
DECLARE_UNIQUE_TYPE(Name, BaseType) (unique.hpp) creates strong typedefs to prevent accidental implicit conversions (e.g., KeeperIndex, DestState).
DECLARE_UNIQUE_ARITHMETIC_TYPE(Name, BaseType) (unique.hpp) does the same but additionally enables arithmetic operators (++, --, etc.) via the kUniqueIsArithmetic<TAG> trait specialization. Use this for index/counter types that need increment/decrement (e.g., StackIndex, TableIndex, UserValueIndex).
[[nodiscard]] is used extensively on return values that must be checked. Style-wise, it is placed on its own line before function signatures.