lua

package
v0.9.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package lua provides a public Go API for embedding the Lua 5.5 interpreter.

This package wraps the internal implementation behind a clean, stable API suitable for embedding Lua in Go applications. It follows the C Lua API conventions (stack-based value passing, pseudo-indices, protected calls) while providing Go-idiomatic error handling and type safety.

Quick Start

Create a Lua state, execute code, and close it:

L := lua.NewState()
defer L.Close()
if err := L.DoString(`print("hello from Lua")`); err != nil {
    log.Fatal(err)
}

Registering Go Functions

Go functions can be registered as Lua globals:

add := func(L *lua.State) int {
    a := L.CheckInteger(1)
    b := L.CheckInteger(2)
    L.PushInteger(a + b)
    return 1
}
L.PushFunction(add)
L.SetGlobal("add")

Or use the type-safe generic wrappers:

lua.Wrap2R(L, func(a, b int64) int64 { return a + b })
L.SetGlobal("add")

Modules

Register Go modules that Lua code can load with require():

lua.RegisterModule(L, "mylib", map[string]lua.Function{
    "hello": func(L *lua.State) int {
        L.PushString("world")
        return 1
    },
})

Built-in modules available via require():

  • "async" — coroutine-based async/await with Future and Scheduler
  • "channel" — Go-style channels for Lua (Channel)
  • "timer" — setTimeout/setInterval timers (TimerManager)
  • "http" — HTTP client (GET/POST with async support)
  • "json" — JSON encode/decode
  • "hotreload" — live code reload with state preservation (ReloadPlan)

Async / Coroutines

The async system provides Future-based concurrency:

sched := lua.NewScheduler(L)
L.DoString(`
    local async = require("async")
    async.go("return 42")  -- runs in background
`)
sched.Tick() // drive coroutines forward

Use Scheduler to manage async coroutines. Use Future for Go↔Lua async communication. Futures support Cancel and context propagation.

Hot-Reload

Replace module functions at runtime while preserving state:

result, err := L.ReloadModule("game.npc")
// result.Replaced = 5 functions updated
// All upvalue state (counters, caches) preserved

For fine-grained control, use the two-phase commit API:

plan, err := L.PrepareReload("mymod")  // read-only preparation
if plan.HasIncompatible() {
    plan.Abort()  // no changes
} else {
    plan.Commit() // atomic replacement
}

Sandboxing

Create sandboxed states with CPU limits and restricted libraries:

L := lua.NewSandboxState(lua.SandboxConfig{
    CPULimit: 100000, // max instructions
})

State Pool

For high-concurrency servers, reuse Lua states:

pool := lua.NewStatePool(lua.PoolConfig{MaxStates: 10})
L := pool.Get()
defer pool.Put(L)

Type Bridge

High-level type conversion between Go and Lua:

L.PushAny(map[string]any{"name": "Alice", "age": 30})
val := L.ToAny(-1) // map[string]any

var user User
L.ToStruct(-1, &user) // Lua table → Go struct

Stack-Based API

Values are passed between Go and Lua via a virtual stack. Push functions move values from Go to the stack; To/Check functions read values from the stack back to Go. Positive indices count from the bottom (1 = first), negative indices count from the top (-1 = top element).

Error Handling

Use State.DoString or State.DoFile for simple execution with Go error returns. For finer control, use State.Load + State.PCall which return status codes and leave error messages on the stack.

Memory Management

The interpreter uses Go's garbage collector. Call State.Close when done to release internal resources promptly.

Example
package main

import (
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()
	L.DoString(`print("hello from Lua")`)
}
Output:
hello from Lua

Index

Examples

Constants

View Source
const (
	HookEventCall     = state.HookCall     // function call
	HookEventReturn   = state.HookReturn   // function return
	HookEventLine     = state.HookLine     // new source line
	HookEventCount    = state.HookCount    // instruction count reached
	HookEventTailCall = state.HookTailCall // tail call
)

HookEvent constants for use with HookFunc callbacks.

View Source
const (
	// RegistryIndex is the pseudo-index for the Lua registry, a global table
	// used to store values that need to persist across function calls.
	RegistryIndex = -1001000

	// MultiRet signals that a function call should return all results,
	// used as the nResults argument to [State.Call] and [State.PCall].
	MultiRet = -1
)

Pseudo-indices and special constants.

View Source
const (
	// RIdxMainThread is the registry index of the main thread.
	RIdxMainThread = 3

	// RIdxGlobals is the registry index of the global environment table.
	RIdxGlobals = 2
)

Well-known registry keys for accessing standard values.

View Source
const (
	// RefNil is the reference returned by [State.Ref] when the value is nil.
	RefNil = -1

	// NoRef is the "no reference" sentinel, indicating an invalid reference.
	NoRef = -2
)

Reference constants for State.Ref and State.Unref.

View Source
const (
	OK        = 0 // no errors
	Yield     = 1 // coroutine yielded (from [State.Resume])
	ErrRun    = 2 // runtime error
	ErrSyntax = 3 // syntax error during compilation
	ErrMem    = 4 // memory allocation error
	ErrErr    = 5 // error while running the message handler
	ErrFile   = 6 // file I/O error (from [State.LoadFile])
)

Status codes returned by State.PCall, State.Resume, and related functions.

View Source
const (
	MaskCall  = 1 << 0 // call hook — triggered on every function call
	MaskRet   = 1 << 1 // return hook — triggered on every function return
	MaskLine  = 1 << 2 // line hook — triggered on every new source line
	MaskCount = 1 << 3 // count hook — triggered every N instructions
)

Hook event masks for State.SetHook. Combine with bitwise OR to set multiple hooks.

Variables

View Source
var ErrCancelled = errors.New("cancelled")

ErrCancelled is returned by Future.Result when the Future was cancelled.

View Source
var ErrChannelClosed = fmt.Errorf("channel is closed")

ErrChannelClosed is returned when attempting to send on a closed channel.

Functions

func GlobalModules

func GlobalModules() []string

GlobalModules returns a copy of all registered global module names. Thread-safe.

func LoadModules

func LoadModules(L *State, modules ...Module)

LoadModules loads multiple modules into a State by registering each module's Open method into package.preload. After this call, each module is available via require("name").

This is the per-State equivalent of RegisterGlobal. Use LoadModules when you want a module available only in specific States rather than globally.

func OpenAsync

func OpenAsync(L *State)

OpenAsync opens the "async" module and pushes it onto the stack. Registered globally via init(), so `require("async")` works automatically.

Lua API:

local async = require("async")
local future = async.go("return 42")        -- run code in a goroutine
local val, err = async.await(future)         -- yield until future resolves
local f = async.resolve(42)                  -- create an already-resolved future
local f = async.reject("oops")               -- create an already-rejected future

func OpenChannelLib

func OpenChannelLib(L *State)

OpenChannelLib opens the "channel" module and pushes it onto the stack. It is registered globally via init(), so `require("channel")` works automatically in any State.

Lua API:

local channel = require("channel")
local ch = channel.new(10)           -- buffered channel, size 10
channel.send(ch, "hello")            -- send (blocks if full)
local val, ok = channel.recv(ch)     -- receive (blocks if empty)
local ok = channel.try_send(ch, val) -- non-blocking send
local val, ok = channel.try_recv(ch) -- non-blocking receive
channel.close(ch)                    -- close channel
local n = channel.len(ch)            -- buffer length
local b = channel.is_closed(ch)      -- check if closed

func OpenHTTP

func OpenHTTP(L *State)

OpenHTTP opens the "http" module and pushes it onto the stack. It is registered globally via init(), so `require("http")` works automatically in any State.

Lua API:

local http = require("http")
local resp = http.get(url [, options])
local resp = http.post(url, options)
local resp = http.request(options)

Response table:

{
    status      = 200,           -- HTTP status code (integer)
    status_text = "200 OK",      -- full status text
    body        = "...",         -- response body as string
    headers     = {              -- response headers (lowercase keys)
        ["content-type"] = "application/json",
    },
}

On error, all functions return nil, error_string.

func OpenHotReload added in v0.8.0

func OpenHotReload(L *State)

OpenHotReload opens the "hotreload" module.

Lua API:

local hr = require("hotreload")
local result, err = hr.reload("modulename")
local plan, err = hr.prepare("modulename")
if plan then plan:commit() end

func OpenJSON

func OpenJSON(L *State)

OpenJSON opens the "json" module and pushes it onto the stack. It is registered globally via init(), so `require("json")` works automatically in any State.

Lua API:

local json = require("json")
local s = json.encode({name = "Alice", age = 30})
local t = json.decode('{"name":"Alice","age":30}')
local s = json.encode_pretty({name = "Alice"})

func OpenTimer

func OpenTimer(L *State)

OpenTimer opens the "timer" module and pushes it onto the stack. Registered globally via init(), so `require("timer")` works automatically.

Lua API:

local timer = require("timer")
local f = timer.delay(0.5)         -- returns Future, resolves after 500ms
local id = timer.after(1.0, fn)    -- calls fn after 1 second
local id = timer.every(0.1, fn)    -- calls fn every 100ms
timer.cancel(id)                   -- cancel a timer

func RegisterGlobal

func RegisterGlobal(name string, opener ModuleOpener)

RegisterGlobal registers a module opener in the global registry. Thread-safe. Typically called from package init() functions. When any State calls require("name"), the opener will be invoked if the module isn't found in package.loaded or package.preload.

Example:

func init() {
    lua.RegisterGlobal("json", func(L *lua.State) {
        L.NewTableFrom(map[string]any{})
        L.PushFunction(jsonEncode)
        L.SetField(-2, "encode")
        L.PushFunction(jsonDecode)
        L.SetField(-2, "decode")
    })
}

func RegisterModule

func RegisterModule(L *State, name string, funcs map[string]Function)

RegisterModule registers a set of Go functions as a Lua module that can be loaded via require(name). It sets package.preload[name] to an opener function that creates a table with the given functions.

Example:

RegisterModule(L, "mymod", map[string]lua.Function{
    "greet": greetFunc,
    "add":   addFunc,
})
// Lua: local m = require("mymod"); m.greet("world")
Example
package main

import (
	"fmt"
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	lua.RegisterModule(L, "greet", map[string]lua.Function{
		"hello": func(L *lua.State) int {
			name := L.CheckString(1)
			L.PushString(fmt.Sprintf("Hello, %s!", name))
			return 1
		},
	})

	L.DoString(`
		local g = require("greet")
		print(g.hello("World"))
	`)
}
Output:
Hello, World!

func UnregisterGlobal

func UnregisterGlobal(name string)

UnregisterGlobal removes a module from the global registry. Thread-safe.

func UpvalueIndex

func UpvalueIndex(i int) int

UpvalueIndex returns the pseudo-index for the i-th upvalue (1-based). Use this inside a Function to access closure upvalues.

func Wrap0

func Wrap0(L *State, fn func())

Wrap0 wraps func() as a Lua function (no args, no return).

func Wrap0E

func Wrap0E(L *State, fn func() error)

Wrap0E wraps func() error as a Lua function (no args, error return).

func Wrap0R

func Wrap0R[R any](L *State, fn func() R)

Wrap0R wraps func() R as a Lua function (no args, 1 return).

func Wrap1

func Wrap1[A any](L *State, fn func(A))

Wrap1 wraps func(A) as a Lua function.

func Wrap1E

func Wrap1E[A, R any](L *State, fn func(A) (R, error))

Wrap1E wraps func(A) (R, error) as a Lua function.

func Wrap1R

func Wrap1R[A, R any](L *State, fn func(A) R)

Wrap1R wraps func(A) R as a Lua function.

Example
package main

import (
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	lua.Wrap1R(L, func(n int) int { return n * n })
	L.SetGlobal("square")

	L.DoString(`print(square(7))`)
}
Output:
49

func Wrap2

func Wrap2[A, B any](L *State, fn func(A, B))

Wrap2 wraps func(A, B) as a Lua function.

func Wrap2E

func Wrap2E[A, B, R any](L *State, fn func(A, B) (R, error))

Wrap2E wraps func(A, B) (R, error) as a Lua function.

func Wrap2R

func Wrap2R[A, B, R any](L *State, fn func(A, B) R)

Wrap2R wraps func(A, B) R as a Lua function.

Example
package main

import (
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	lua.Wrap2R(L, func(a, b int) int { return a + b })
	L.SetGlobal("add")

	L.DoString(`print(add(3, 4))`)
}
Output:
7

func Wrap3

func Wrap3[A, B, C any](L *State, fn func(A, B, C))

Wrap3 wraps func(A, B, C) as a Lua function.

func Wrap3R

func Wrap3R[A, B, C, R any](L *State, fn func(A, B, C) R)

Wrap3R wraps func(A, B, C) R as a Lua function.

Types

type ArithOp

type ArithOp int

ArithOp is the arithmetic operation type for State.Arith.

const (
	OpAdd  ArithOp = 0  // + addition
	OpSub  ArithOp = 1  // - subtraction
	OpMul  ArithOp = 2  // * multiplication
	OpMod  ArithOp = 3  // % modulo
	OpPow  ArithOp = 4  // ^ exponentiation
	OpDiv  ArithOp = 5  // / float division
	OpIDiv ArithOp = 6  // // floor division
	OpBAnd ArithOp = 7  // & bitwise AND
	OpBOr  ArithOp = 8  // | bitwise OR
	OpBXor ArithOp = 9  // ~ bitwise XOR
	OpShl  ArithOp = 10 // << left shift
	OpShr  ArithOp = 11 // >> right shift
	OpUnm  ArithOp = 12 // - (unary minus)
	OpBNot ArithOp = 13 // ~ (bitwise NOT, unary)
)

Arithmetic and bitwise operations for State.Arith.

type Channel

type Channel struct {
	// contains filtered or unexported fields
}

Channel is a thread-safe communication channel between Lua States or between Go and Lua. It wraps a Go channel with Lua-friendly API.

Channels carry any values; when used from Lua, values are converted via the PushAny/ToAny bridge automatically.

A Channel can be shared across goroutines and across Lua States safely because the underlying Go chan is inherently thread-safe, and the closed flag is protected by a RWMutex.

func NewChannel

func NewChannel(bufSize int) *Channel

NewChannel creates a new Channel with the given buffer size. bufSize 0 creates an unbuffered (synchronous) channel.

func (*Channel) Close

func (c *Channel) Close()

Close closes the channel. Further sends will return ErrChannelClosed. Closing an already-closed channel is a no-op.

func (*Channel) IsClosed

func (c *Channel) IsClosed() bool

IsClosed returns whether the channel has been closed.

func (*Channel) Len

func (c *Channel) Len() int

Len returns the number of elements currently buffered in the channel.

func (*Channel) Recv

func (c *Channel) Recv() (any, bool)

Recv receives a value from the channel. Blocks until a value is available. Returns (value, true) on success, or (nil, false) if the channel is closed and empty.

func (*Channel) RecvTimeout

func (c *Channel) RecvTimeout(timeout time.Duration) (any, bool)

RecvTimeout receives with a timeout. Returns (value, true) if received; (nil, false) if timeout or closed.

func (*Channel) Send

func (c *Channel) Send(value any) (retErr error)

Send sends a value into the channel. Blocks until received (if unbuffered) or until buffer has space. Returns ErrChannelClosed if the channel has been closed.

Note: Send does NOT hold the mutex during the blocking channel send because that would deadlock with Close on unbuffered/full channels. Instead it checks the closed flag first, then uses recover to catch any panic from sending on a concurrently-closed Go channel.

func (*Channel) TryRecv

func (c *Channel) TryRecv() (any, bool, bool)

TryRecv attempts to receive without blocking. Returns (value, true, true) if a value was received. Returns (nil, true, false) if the channel is closed and drained. Returns (nil, false, true) if the channel is open but empty.

func (*Channel) TrySend

func (c *Channel) TrySend(value any) (sent bool)

TrySend attempts to send without blocking. Returns true if the value was sent, false if the channel is full or closed. Safe to call concurrently with Close.

type Closeable added in v0.9.9

type Closeable = io.Closer

Closeable is any Go resource that can be closed. Matches io.Closer.

type CompareOp

type CompareOp int

CompareOp is the comparison operation type for State.Compare.

const (
	OpEQ CompareOp = 0 // == (may invoke __eq metamethod)
	OpLT CompareOp = 1 // <  (may invoke __lt metamethod)
	OpLE CompareOp = 2 // <= (may invoke __le metamethod)
)

Comparison operations for State.Compare.

type CoroutineHandle added in v0.5.1

type CoroutineHandle struct {
	// contains filtered or unexported fields
}

CoroutineHandle is a handle to a spawned coroutine, used for cancellation.

func (*CoroutineHandle) ID added in v0.5.1

func (h *CoroutineHandle) ID() int

ID returns the handle's unique identifier.

type DebugInfo

type DebugInfo struct {
	Source          string // source of the chunk (e.g. "@filename.lua" or "=stdin")
	ShortSrc        string // short source for error messages (max 60 chars)
	LineDefined     int    // line where the function definition starts
	LastLineDefined int    // line where the function definition ends
	CurrentLine     int    // current line being executed
	Name            string // function name (if known)
	NameWhat        string // "global", "local", "method", "field", or ""
	What            string // "Lua", "C", or "main"
	NUps            int    // number of upvalues
	NParams         int    // number of fixed parameters
	IsVararg        bool   // true if the function is variadic
	IsTailCall      bool   // true if this is a tail call
	ExtraArgs       int    // number of extra arguments (vararg)
	FTransfer       int    // index of first transferred value (for call/return hooks)
	NTransfer       int    // number of transferred values (for call/return hooks)
	// contains filtered or unexported fields
}

DebugInfo holds debug information about a function activation record. Returned by State.GetStack and filled by State.GetInfo.

Not all fields are filled by every call. The "what" parameter to State.GetInfo controls which fields are populated:

  • 'n': Name, NameWhat
  • 'S': Source, ShortSrc, What, LineDefined, LastLineDefined
  • 'l': CurrentLine
  • 'u': NUps, NParams, IsVararg
  • 'f': pushes the function onto the stack
  • 'r': FTransfer, NTransfer
  • 't': IsTailCall, ExtraArgs

type Executor

type Executor struct {
	// contains filtered or unexported fields
}

Executor manages async Lua execution using a pool of States.

Thread-safe: Executor.Submit can be called from any goroutine. Each submitted Task runs in its own goroutine with an exclusively-owned Lua State obtained from the underlying StatePool.

func NewExecutor

func NewExecutor(config ExecutorConfig) *Executor

NewExecutor creates a new async Lua executor.

func (*Executor) Pending

func (e *Executor) Pending() int64

Pending returns the number of tasks currently executing.

func (*Executor) Results

func (e *Executor) Results() <-chan Result

Results returns the channel on which execution results are delivered.

func (*Executor) Shutdown

func (e *Executor) Shutdown()

Shutdown gracefully shuts down the executor. It waits for all pending tasks to complete, then closes the pool and the results channel.

func (*Executor) Submit

func (e *Executor) Submit(task Task) bool

Submit submits a task for async execution. Returns immediately. Results arrive on the Executor.Results channel. Returns false if the executor has been shut down.

type ExecutorConfig

type ExecutorConfig struct {
	// PoolConfig configures the underlying [StatePool].
	PoolConfig PoolConfig

	// ResultBuffer is the size of the results channel buffer.
	// Default: 64.
	ResultBuffer int
}

ExecutorConfig configures an Executor.

type FuncPair added in v0.8.0

type FuncPair struct {
	Name       string
	Compatible bool   // true if upvalue layout is compatible
	Reason     string // reason for incompatibility (if any)
	// contains filtered or unexported fields
}

FuncPair represents a matched pair of old and new functions.

type Function

type Function func(L *State) int

Function is the signature for Go functions callable from Lua.

The function receives the Lua state and returns the number of results it pushed onto the stack. Arguments passed from Lua are on the stack at positive indices starting from 1.

Example:

greet := func(L *lua.State) int {
    name := L.CheckString(1)
    L.PushString("Hello, " + name + "!")
    return 1
}

func WrapSafe added in v0.9.9

func WrapSafe(fn Function) Function

WrapSafe wraps a Go function so that Go panics are converted to Lua errors. Use this when registering Go functions that might panic.

Example:

L.PushFunction(lua.WrapSafe(func(L *lua.State) int {
    // If this panics, Lua gets an error instead of a crash
    data := mustParse(L.CheckString(1))
    L.PushAny(data)
    return 1
}))
L.SetGlobal("parse")

type Future

type Future struct {
	// contains filtered or unexported fields
}

Future represents the result of an async operation. Thread-safe: can be resolved from any goroutine.

func NewFuture

func NewFuture() *Future

NewFuture creates a new unresolved Future.

func NewFutureWithContext added in v0.7.1

func NewFutureWithContext(parent context.Context) (*Future, context.Context)

NewFutureWithContext creates a Future with an associated context. The returned context is derived from parent and will be cancelled when the Future completes (Resolve, Reject, or Cancel). Use this context in Go goroutines to support cancellation of in-flight operations (HTTP requests, IO, etc.).

Example:

future, ctx := lua.NewFutureWithContext(parentCtx)
go func() {
    req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        future.Reject(err)
        return
    }
    future.Resolve(body)
}()

func (*Future) Cancel added in v0.5.1

func (f *Future) Cancel()

Cancel cancels the Future. Waiters are notified with ErrCancelled. Thread-safe. No-op if already done.

func (*Future) IsCancelled added in v0.5.1

func (f *Future) IsCancelled() bool

IsCancelled returns true if the Future was cancelled.

func (*Future) IsDone

func (f *Future) IsDone() bool

IsDone returns whether the Future has been resolved or rejected.

func (*Future) Reject

func (f *Future) Reject(err error)

Reject completes the Future with an error. Thread-safe. Only the first Resolve/Reject takes effect.

func (*Future) Resolve

func (f *Future) Resolve(value any)

Resolve completes the Future with a value. Thread-safe. Can be called from any goroutine. Only the first call takes effect; subsequent calls are no-ops.

func (*Future) Result

func (f *Future) Result() (any, error)

Result returns the value and error. Only meaningful after IsDone() == true.

func (*Future) Wait

func (f *Future) Wait() <-chan struct{}

Wait returns a channel that closes when the Future completes. If the Future is already done, the returned channel is already closed.

type GCWhat

type GCWhat int

GCWhat is the GC operation type for State.GC.

const (
	GCStop      GCWhat = 0  // stop the garbage collector
	GCRestart   GCWhat = 1  // restart the garbage collector
	GCCollect   GCWhat = 2  // perform a full collection cycle
	GCCount     GCWhat = 3  // return total memory in use (KBytes)
	GCCountB    GCWhat = 4  // return remainder bytes of memory in use
	GCStep      GCWhat = 5  // perform an incremental GC step
	GCIsRunning GCWhat = 9  // return 1 if GC is running, 0 if stopped
	GCGen       GCWhat = 10 // switch to generational GC mode
	GCInc       GCWhat = 11 // switch to incremental GC mode
)

Garbage collection operations for State.GC.

type HookFunc

type HookFunc func(L *State, event int, currentLine int)

HookFunc is the callback type for debug hooks set via State.SetHook.

The callback receives the Lua state, the hook event (one of the HookEvent* constants), and the current source line number (-1 for non-line events). Inside the callback you may inspect the call stack via State.GetStack and State.GetInfo, but you must not yield or raise errors.

type Module

type Module interface {
	// Name returns the module name used in require().
	Name() string
	// Open registers the module into the given Lua State.
	// It should push exactly one value (the module table) onto the stack.
	Open(L *State)
}

Module is the standard interface for go-lua extension modules. Third-party libraries implement this to be loadable via LoadModules.

Example:

type JSONModule struct{}
func (JSONModule) Name() string { return "json" }
func (JSONModule) Open(L *lua.State) {
    L.NewTableFrom(map[string]any{})
    L.PushFunction(jsonEncode)
    L.SetField(-2, "encode")
}

type ModuleOpener

type ModuleOpener func(L *State)

ModuleOpener is a function that opens/registers a module into a Lua State. It should push exactly one value (the module table) onto the stack and return 1. Typically called automatically when require("name") triggers the global registry searcher.

type PoolConfig

type PoolConfig struct {
	// MaxStates is the maximum number of States in the pool.
	// When the pool is full, [StatePool.Put] closes excess States.
	// Default: 8.
	MaxStates int

	// InitFunc is called on each new State after creation.
	// Use it to register modules, set globals, configure sandbox, etc.
	// If nil, States are created with [NewState] defaults.
	InitFunc func(L *State)

	// Sandbox, if non-nil, creates sandboxed States via [NewSandboxState]
	// instead of regular ones.
	Sandbox *SandboxConfig
}

PoolConfig configures a StatePool.

type PoolStats

type PoolStats struct {
	Available int // States currently idle in the pool.
	Created   int // Total States created over the pool's lifetime.
	MaxStates int // Configured maximum pool size.
}

PoolStats contains statistics about a StatePool.

type RefTracker added in v0.9.9

type RefTracker struct {
	// contains filtered or unexported fields
}

RefTracker tracks Lua registry references for leak detection. Use during development/testing to find Ref() calls without matching Unref().

Example:

tracker := lua.NewRefTracker()
ref := tracker.Ref(L, lua.RegistryIndex)
// ... use ref ...
tracker.Unref(L, lua.RegistryIndex, ref)

// At shutdown:
leaks := tracker.Leaks()
if len(leaks) > 0 {
    t.Errorf("ref leaks:\n%s", strings.Join(leaks, "\n"))
}

func NewRefTracker added in v0.9.9

func NewRefTracker() *RefTracker

NewRefTracker creates a new RefTracker.

func (*RefTracker) Count added in v0.9.9

func (t *RefTracker) Count() int

Count returns the number of currently active (unfreed) references.

func (*RefTracker) Leaks added in v0.9.9

func (t *RefTracker) Leaks() []string

Leaks returns a list of leaked references (Ref'd but never Unref'd). Each entry includes the caller location where Ref was called.

func (*RefTracker) Ref added in v0.9.9

func (t *RefTracker) Ref(L *State, idx int) int

Ref creates a registry reference and tracks it. Use instead of L.Ref(RegistryIndex).

func (*RefTracker) Reset added in v0.9.9

func (t *RefTracker) Reset()

Reset clears all tracking state.

func (*RefTracker) Unref added in v0.9.9

func (t *RefTracker) Unref(L *State, idx int, ref int)

Unref frees a registry reference and removes it from tracking. Use instead of L.Unref(RegistryIndex, ref).

type ReloadPlan added in v0.8.0

type ReloadPlan struct {
	Module   string     // module name
	Pairs    []FuncPair // matched old↔new function pairs
	Added    []string   // new functions not in old module
	Removed  []string   // old functions not in new module
	Warnings []string   // non-fatal warnings
	// contains filtered or unexported fields
}

ReloadPlan represents a prepared hot-reload operation. Created by PrepareReload, executed by Commit.

Note: The new module's init code has already been executed during PrepareReload. The plan controls only whether function replacements are applied (Commit) or discarded (Abort). Side effects from the new module's init code cannot be rolled back by Abort.

func (*ReloadPlan) Abort added in v0.8.0

func (p *ReloadPlan) Abort()

Abort discards the reload plan without modifying any state.

func (*ReloadPlan) Commit added in v0.8.0

func (p *ReloadPlan) Commit() *ReloadResult

Commit executes the reload plan. All compatible functions have their proto swapped and upvalues transferred. Incompatible functions are skipped. Returns the result summary.

func (*ReloadPlan) HasIncompatible added in v0.8.0

func (p *ReloadPlan) HasIncompatible() bool

HasIncompatible returns true if any function pair is incompatible.

func (*ReloadPlan) IncompatibleCount added in v0.8.0

func (p *ReloadPlan) IncompatibleCount() int

IncompatibleCount returns the number of incompatible function pairs.

type ReloadResult added in v0.8.0

type ReloadResult struct {
	Module   string
	Replaced int // functions successfully replaced
	Skipped  int // incompatible functions skipped
	Added    int // new functions added to module
	Removed  int // functions removed from old but not new (left in place)
	Warnings []string
}

ReloadResult reports the outcome of a hot-reload operation.

type Result

type Result struct {
	// ID matches the [Task.ID] that produced this result.
	ID string

	// Value is the return value (from [Task.Func], or nil for [Task.Code]).
	Value any

	// Error is non-nil if the Lua execution failed.
	Error error
}

Result is the outcome of an async Lua Task.

type SandboxConfig

type SandboxConfig struct {
	// MemoryLimit is the maximum memory in bytes (0 = no limit).
	MemoryLimit int64

	// CPULimit is the maximum number of VM instructions (0 = no limit).
	CPULimit int64

	// AllowIO controls whether the io and os libraries are available.
	// Default false = no io/os access.
	AllowIO bool

	// AllowDebug controls whether the debug library is available.
	// Default false = no debug access.
	AllowDebug bool

	// AllowPackage controls whether the package/require library is available.
	// Default false = no module loading.
	AllowPackage bool

	// ExtraLibs is a map of additional libraries to register.
	// These are registered after the standard libraries.
	ExtraLibs map[string]Function
}

SandboxConfig configures a sandboxed Lua state created by NewSandboxState.

type Scheduler

type Scheduler struct {
	L *State

	OnError func(err error) // called when a coroutine errors during Tick
	// contains filtered or unexported fields
}

Scheduler manages async coroutines within a single Lua State. NOT thread-safe — must be used from a single goroutine (the main/event loop goroutine).

func NewScheduler

func NewScheduler(L *State) *Scheduler

NewScheduler creates a new Scheduler for the given State.

func (*Scheduler) Cancel added in v0.5.1

func (s *Scheduler) Cancel(h *CoroutineHandle)

Cancel cancels a coroutine by its handle. Removes it from pending, unrefs, and cancels its future.

func (*Scheduler) Destroy added in v0.5.1

func (s *Scheduler) Destroy()

Destroy cancels all pending coroutines and releases their registry references. Call this when shutting down or hot-reloading. Safe to call from within an OnError callback during Tick.

func (*Scheduler) Pending

func (s *Scheduler) Pending() int

Pending returns the number of pending coroutines.

func (*Scheduler) Spawn

func (s *Scheduler) Spawn(L *State) (*CoroutineHandle, error)

Spawn creates a new coroutine from the function at the top of L's stack and starts executing it. If it yields (via await), it's added to the pending list. The function is popped from the stack. Returns a CoroutineHandle that can be used to cancel the coroutine.

func (*Scheduler) Tick

func (s *Scheduler) Tick() int

Tick checks all pending coroutines and resumes any whose Future is done. Returns the number of still-pending coroutines. Call this in your event loop / main loop. Uses double-buffering to avoid per-frame allocation.

func (*Scheduler) WaitAll

func (s *Scheduler) WaitAll(timeout time.Duration) error

WaitAll blocks until all pending coroutines complete, polling with Tick. Useful for testing. Returns error on timeout.

type StackRef

type StackRef struct {
	Index int
}

StackRef references a value on the Lua stack by index. When passed to State.PushAny, it calls State.PushValue(ref.Index) to copy the stack value. This allows mixing Go values and Lua stack values in maps passed to State.NewTableFrom / State.SetFields.

Example:

L.NewTableFrom(map[string]any{
    "name":  "Select",
    "props": lua.StackRef{Index: 1},  // copies stack index 1
})

type State

type State struct {
	// contains filtered or unexported fields
}

State is the main Lua interpreter state. It wraps the internal API state and provides a clean public interface.

func NewBareState

func NewBareState() *State

NewBareState creates a new Lua state without loading standard libraries. Use this when you need full control over which libraries are available.

func NewSandboxState

func NewSandboxState(config SandboxConfig) *State

NewSandboxState creates a new Lua state with restricted capabilities.

By default only safe libraries are loaded: a restricted base library (without dofile, loadfile, load, require), string, table, math, utf8, and coroutine. The io, os, debug, and package libraries are excluded unless explicitly enabled via SandboxConfig.

If [SandboxConfig.CPULimit] is set, a CPU instruction limit is applied via State.SetCPULimit.

If [SandboxConfig.MemoryLimit] is set and the state supports memory limiting, it will be applied.

Example:

L := lua.NewSandboxState(lua.SandboxConfig{
    CPULimit: 1_000_000, // max 1M instructions
})
defer L.Close()
err := L.DoString(untrustedCode)
Example
package main

import (
	"fmt"

	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewSandboxState(lua.SandboxConfig{
		MemoryLimit: 10 * 1024 * 1024, // 10MB
		CPULimit:    100_000,          // 100K instructions
	})
	defer L.Close()

	// Safe to execute untrusted code — io/os/debug are blocked.
	err := L.DoString(`print("Hello from sandbox!")`)
	if err != nil {
		fmt.Println("Error:", err)
	}

	// Dangerous functions are removed.
	err = L.DoString(`io.open("secret.txt")`)
	if err != nil {
		fmt.Println("io blocked:", err != nil)
	}
}
Output:
Hello from sandbox!
io blocked: true

func NewState

func NewState() *State

NewState creates a new Lua state with all standard libraries loaded.

func (*State) AbsIndex

func (L *State) AbsIndex(idx int) int

AbsIndex converts a potentially negative index to an absolute index.

func (*State) ArgCheck

func (L *State) ArgCheck(cond bool, arg int, extraMsg string)

ArgCheck checks a condition for argument arg. If cond is false, raises an error with extraMsg.

func (*State) ArgError

func (L *State) ArgError(arg int, extraMsg string) int

ArgError raises an error for argument arg with the given message. This function does not return.

func (*State) ArgExpected

func (L *State) ArgExpected(cond bool, arg int, tname string)

ArgExpected checks that argument arg satisfies a condition. If cond is false, raises a type error with tname.

func (*State) Arith

func (L *State) Arith(op ArithOp)

Arith performs an arithmetic or bitwise operation on the values at the top of the stack. For binary operations, pops two operands; for unary, pops one. Pushes the result.

func (*State) CPUInstructionsUsed

func (L *State) CPUInstructionsUsed() int64

CPUInstructionsUsed returns the approximate number of VM instructions executed since the last State.SetCPULimit or State.ResetCPUCounter call. The value is approximate because the count hook fires every N instructions (default 1000), not on every single instruction.

func (*State) Call

func (L *State) Call(nArgs, nResults int)

Call calls a function in unprotected mode. nArgs arguments are on the stack above the function. nResults is the number of expected results (or MultiRet for all).

func (*State) CallRef

func (L *State) CallRef(ref int, nArgs, nResults int) error

CallRef retrieves a function from the registry by reference ID and calls it in protected mode. nArgs arguments must already be on the stack. Returns nil on success (nResults on stack), or a Go error. Returns an error if the ref does not point to a function.

Example:

L.PushAny(eventData) // push 1 arg
err := L.CallRef(refID, 1, 0)

func (*State) CallSafe

func (L *State) CallSafe(nArgs, nResults int) error

CallSafe calls a function in protected mode and returns a Go error on failure. The function and nArgs arguments must already be on the stack (same as PCall). On success, nResults results are on the stack and err is nil. On failure, the error message is popped from the stack and returned as a Go error.

Example:

L.PushFunction(fn)
L.PushAny(arg)
err := L.CallSafe(1, 1)
if err != nil { log.Fatal(err) }
Example
package main

import (
	"fmt"

	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	L.DoString(`
		function divide(a, b)
			if b == 0 then error("division by zero") end
			return a / b
		end
	`)

	// Successful call.
	L.GetGlobal("divide")
	L.PushInteger(10)
	L.PushInteger(2)
	err := L.CallSafe(2, 1)
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	val, _ := L.ToNumber(-1)
	L.Pop(1)
	fmt.Printf("result: %g\n", val)

	// Failing call — error is returned as a Go error.
	L.GetGlobal("divide")
	L.PushInteger(10)
	L.PushInteger(0)
	err = L.CallSafe(2, 1)
	fmt.Println("caught error:", err != nil)
}
Output:
result: 5
caught error: true

func (*State) CheckAny

func (L *State) CheckAny(idx int)

CheckAny checks that there is an argument at idx (any type). Raises a Lua error if the index is not valid.

func (*State) CheckInteger

func (L *State) CheckInteger(idx int) int64

CheckInteger checks that the argument at idx is an integer and returns it. Raises a Lua error if the check fails.

func (*State) CheckNumber

func (L *State) CheckNumber(idx int) float64

CheckNumber checks that the argument at idx is a number and returns it. Raises a Lua error if the check fails.

func (*State) CheckOption

func (L *State) CheckOption(idx int, def string, opts []string) int

CheckOption checks that the argument at idx is a string matching one of the options. Returns the index of the matched option. If def is non-empty and the argument is nil/absent, uses def.

func (*State) CheckStack

func (L *State) CheckStack(n int) bool

CheckStack ensures that the stack has space for at least n extra elements. Returns false if it cannot fulfill the request.

func (*State) CheckString

func (L *State) CheckString(idx int) string

CheckString checks that the argument at idx is a string and returns it. Raises a Lua error if the check fails.

func (*State) CheckType

func (L *State) CheckType(idx int, tp Type)

CheckType checks that the argument at idx has the given type. Raises a Lua error if the check fails.

func (*State) CheckUdata

func (L *State) CheckUdata(idx int, tname string)

CheckUdata checks that the value at idx is a userdata with metatable matching registry[tname]. Raises a type error if not.

func (*State) CheckUserdata

func (L *State) CheckUserdata(n int) any

CheckUserdata checks that the argument at position n is a userdata (full or light) and returns the Go value stored inside it. Raises a Lua error if the argument is not a userdata.

func (*State) ClearHookFields

func (L *State) ClearHookFields()

ClearHookFields clears all hook fields. Deprecated: Use SetHook(nil, 0, 0) instead.

func (*State) Close

func (L *State) Close()

Close releases all resources associated with the Lua state.

func (*State) CloseSlot

func (L *State) CloseSlot(idx int)

CloseSlot closes the to-be-closed slot at the given index and sets its value to nil. The index must be the last active to-be-closed variable. Mirrors: lua_closeslot in lapi.c

func (*State) CloseThread

func (L *State) CloseThread(from *State) int

CloseThread resets a thread (coroutine), closing all pending to-be-closed variables and putting the thread in a dead/closed state. Returns a status code. Mirrors: lua_closethread in lapi.c

func (*State) Compare

func (L *State) Compare(idx1, idx2 int, op CompareOp) bool

Compare compares two values using the given comparison operation. May trigger __eq, __lt, or __le metamethods.

func (*State) Concat

func (L *State) Concat(n int)

Concat concatenates the n values at the top of the stack, pops them, and pushes the result. May trigger __concat metamethod.

func (*State) Context

func (L *State) Context() context.Context

Context returns the associated context.Context, or context.Background if none was set. Reads from the internal api.State so the context is accessible even from wrapFunction-created State wrappers.

func (*State) Copy

func (L *State) Copy(fromIdx, toIdx int)

Copy copies the value at fromIdx to toIdx.

func (*State) CreateTable

func (L *State) CreateTable(nArr, nRec int)

CreateTable pushes a new table with pre-allocated space for nArr array elements and nRec hash elements.

func (*State) DeleteUserValue

func (L *State) DeleteUserValue(key string)

DeleteUserValue removes a previously stored user value.

func (*State) DoFile

func (L *State) DoFile(filename string) error

DoFile loads and executes a Lua file. Returns nil on success, or an error.

func (*State) DoString

func (L *State) DoString(code string) error

DoString loads and executes a Lua string. Returns nil on success, or an error.

Example
package main

import (
	"fmt"
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()
	err := L.DoString(`result = 2 + 3`)
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	L.GetGlobal("result")
	val, _ := L.ToInteger(-1)
	fmt.Println(val)
}
Output:
5

func (*State) Dump

func (L *State) Dump(strip bool) []byte

Dump dumps the Lua function at the top of the stack as a binary chunk. If strip is true, debug information is removed. Returns the binary chunk bytes, or nil if the value is not a Lua function. Mirrors: lua_dump in lapi.c

func (*State) Error

func (L *State) Error() int

Error raises a Lua error with the value at the top of the stack as the error object. This function does not return.

func (*State) Errorf

func (L *State) Errorf(format string, args ...interface{}) int

Errorf raises a formatted Lua error. This function does not return.

func (*State) FileSystem

func (L *State) FileSystem() fs.FS

FileSystem returns the current filesystem, or nil for the real OS filesystem.

func (*State) ForEach

func (L *State) ForEach(idx int, fn func(*State) bool)

ForEach iterates over all key-value pairs in the table at idx. For each pair, the callback receives the State with key at -2 and value at -1. The callback must NOT pop the key or value — ForEach handles cleanup. If the callback returns false, iteration stops early.

Example:

L.ForEach(-1, func(L *lua.State) bool {
    k, _ := L.ToString(-2)
    v := L.ToAny(-1)
    fmt.Println(k, v)
    return true // continue
})
Example
package main

import (
	"fmt"

	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	// ForEach works well with ordered integer-keyed tables.
	L.DoString(`items = {"apple", "banana", "cherry"}`)
	L.GetGlobal("items")

	L.ForEach(-1, func(L *lua.State) bool {
		idx, _ := L.ToInteger(-2)
		val, _ := L.ToString(-1)
		fmt.Printf("%d: %s\n", idx, val)
		return true // continue iteration
	})
	L.Pop(1)
}
Output:
1: apple
2: banana
3: cherry

func (*State) GC

func (L *State) GC(what GCWhat, args ...int) int

GC performs a garbage collection operation specified by what.

func (*State) GCCollect

func (L *State) GCCollect()

GCCollect runs a full garbage collection cycle.

func (*State) GCStepAPI

func (L *State) GCStepAPI() bool

GCStepAPI runs a bounded incremental GC step. Returns true if a full GC cycle completed during this step.

func (*State) GCTotalBytes

func (L *State) GCTotalBytes() int64

GCTotalBytes returns the total number of bytes tracked by the Lua GC.

func (*State) GetField

func (L *State) GetField(idx int, key string) Type

GetField pushes t[key] where t is the value at idx. Returns the type of the pushed value.

func (*State) GetFieldAny

func (L *State) GetFieldAny(idx int, key string) any

GetFieldAny reads t[key] and converts it to a Go value using ToAny. Returns nil if the field is nil.

func (*State) GetFieldBool

func (L *State) GetFieldBool(idx int, key string) bool

GetFieldBool reads t[key] as a bool where t is the value at idx. Returns false if the field is nil or false.

func (*State) GetFieldInt

func (L *State) GetFieldInt(idx int, key string) int64

GetFieldInt reads t[key] as an int64 where t is the value at idx. Returns 0 if the field is nil or not convertible to an integer.

func (*State) GetFieldNumber

func (L *State) GetFieldNumber(idx int, key string) float64

GetFieldNumber reads t[key] as a float64 where t is the value at idx. Returns 0 if the field is nil or not convertible to a number.

func (*State) GetFieldRef

func (L *State) GetFieldRef(idx int, key string) int

GetFieldRef reads t[key] and if it's a function, stores it in the Lua registry and returns the reference ID. Returns RefNil if the field is not a function. The caller is responsible for calling L.Unref(RegistryIndex, ref) when the reference is no longer needed.

func (*State) GetFieldString

func (L *State) GetFieldString(idx int, key string) string

GetFieldString reads t[key] as a string where t is the value at idx. Returns "" if the field is nil or not convertible to a string. This is equivalent to: L.GetField(idx, key); s, _ := L.ToString(-1); L.Pop(1)

Example
package main

import (
	"fmt"

	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	L.DoString(`person = {name = "Alice", city = "Tokyo"}`)
	L.GetGlobal("person")

	name := L.GetFieldString(-1, "name")
	city := L.GetFieldString(-1, "city")
	fmt.Println(name, "lives in", city)
	L.Pop(1)
}
Output:
Alice lives in Tokyo

func (*State) GetGCMode

func (L *State) GetGCMode() string

GetGCMode returns the current GC mode ("incremental" or "generational").

func (*State) GetGCParam

func (L *State) GetGCParam(name string) int64

GetGCParam returns the current value of a GC parameter by name. Known parameters: "pause", "stepmul", "stepsize", "minormul", "majorminor", "minormajor".

func (*State) GetGlobal

func (L *State) GetGlobal(name string) Type

GetGlobal pushes the value of the global variable name. Returns the type of the pushed value.

func (*State) GetHook

func (L *State) GetHook() (HookFunc, int, int)

GetHook returns the current hook function, mask, and count. Returns (nil, 0, 0) if no hook is set via the public API.

func (*State) GetI

func (L *State) GetI(idx int, n int64) Type

GetI pushes t[n] where t is the value at idx. Returns the type of the pushed value.

func (*State) GetIUserValue

func (L *State) GetIUserValue(idx int, n int) Type

GetIUserValue pushes the n-th user value of the userdata at idx onto the stack. Returns the type of the pushed value, or TypeNone if invalid.

func (*State) GetInfo

func (L *State) GetInfo(what string, ar *DebugInfo) bool

GetInfo fills debug info fields specified by the what string. Characters in what select which fields to fill:

  • 'n': Name, NameWhat
  • 'S': Source, ShortSrc, What, LineDefined, LastLineDefined
  • 'l': CurrentLine
  • 'u': NUps, NParams, IsVararg
  • 'f': pushes the function onto the stack
  • 'r': FTransfer, NTransfer
  • 't': IsTailCall, ExtraArgs

func (*State) GetLocal

func (L *State) GetLocal(ar *DebugInfo, n int) string

GetLocal pushes the value of local variable n of the function at the given debug level. Returns the variable name, or "" if not found.

func (*State) GetMetafield

func (L *State) GetMetafield(idx int, field string) bool

GetMetafield pushes the metamethod field from the metatable of the value at idx. Returns true if found, false if not (nothing pushed).

func (*State) GetMetatable

func (L *State) GetMetatable(idx int) bool

GetMetatable pushes the metatable of the value at idx. Returns false if the value has no metatable (nothing pushed).

func (*State) GetStack

func (L *State) GetStack(level int) (*DebugInfo, bool)

GetStack fills a DebugInfo for the given call level. Level 0 is the current running function, level 1 is the function that called the current one, etc. Returns (info, true) on success, (nil, false) if the level is invalid.

func (*State) GetSubTable

func (L *State) GetSubTable(idx int, fname string) bool

GetSubTable ensures that t[fname] is a table, creating it if needed. t is at idx. Pushes the subtable. Returns true if it already existed.

func (*State) GetTable

func (L *State) GetTable(idx int) Type

GetTable pushes t[k] where t is the value at idx and k is the value at the top of the stack. Pops the key. Returns the type of the pushed value. May trigger __index metamethod.

func (*State) GetTop

func (L *State) GetTop() int

GetTop returns the index of the top element (= number of elements on the stack).

func (*State) GetUpvalue

func (L *State) GetUpvalue(funcIdx, n int) (string, bool)

GetUpvalue pushes the value of upvalue n of the closure at funcIdx. Returns (name, true) if the upvalue exists, ("", false) otherwise.

func (*State) HasCallFrames

func (L *State) HasCallFrames() bool

HasCallFrames returns true if the thread has call frames above the base.

func (*State) HookActive

func (L *State) HookActive() bool

HookActive returns true if any hooks are set.

func (*State) HookCount

func (L *State) HookCount() int

HookCount returns the base hook count (for count hooks).

func (*State) HookMask

func (L *State) HookMask() int

HookMask returns the current hook mask.

func (*State) Insert

func (L *State) Insert(idx int)

Insert moves the top element to idx, shifting elements above.

func (*State) IsBoolean

func (L *State) IsBoolean(idx int) bool

IsBoolean returns true if the value at idx is a boolean.

func (*State) IsCFunction

func (L *State) IsCFunction(idx int) bool

IsCFunction returns true if the value at idx is a Go function.

func (*State) IsFunction

func (L *State) IsFunction(idx int) bool

IsFunction returns true if the value at idx is a function (Lua or Go).

func (*State) IsGCRunning

func (L *State) IsGCRunning() bool

IsGCRunning returns true if the GC is not stopped.

func (*State) IsInteger

func (L *State) IsInteger(idx int) bool

IsInteger returns true if the value at idx is an integer.

func (*State) IsNil

func (L *State) IsNil(idx int) bool

IsNil returns true if the value at idx is nil.

func (*State) IsNone

func (L *State) IsNone(idx int) bool

IsNone returns true if the index is not valid.

func (*State) IsNoneOrNil

func (L *State) IsNoneOrNil(idx int) bool

IsNoneOrNil returns true if the index is not valid or the value is nil.

func (*State) IsNumber

func (L *State) IsNumber(idx int) bool

IsNumber returns true if the value at idx is a number or a string convertible to a number.

func (*State) IsString

func (L *State) IsString(idx int) bool

IsString returns true if the value at idx is a string or a number (numbers are always convertible to strings).

func (*State) IsTable

func (L *State) IsTable(idx int) bool

IsTable returns true if the value at idx is a table.

func (*State) IsUserdata

func (L *State) IsUserdata(idx int) bool

IsUserdata returns true if the value at idx is a userdata (full or light).

func (*State) IsYieldable

func (L *State) IsYieldable() bool

IsYieldable returns true if the running coroutine can yield.

func (*State) Len

func (L *State) Len(idx int)

Len pushes the length of the value at idx onto the stack. May trigger __len metamethod.

func (*State) LenI

func (L *State) LenI(idx int) int64

LenI returns the length of the value at idx as an integer. May trigger __len metamethod. Raises an error if the result is not an integer.

func (*State) Load

func (L *State) Load(code string, name string, mode string) int

Load loads a Lua chunk from a string without executing it. Pushes the compiled chunk as a function on success. Returns a status code.

func (*State) LoadFile

func (L *State) LoadFile(filename string, mode string) int

LoadFile loads a Lua file without executing it. Pushes the compiled chunk as a function on success. Returns a status code (OK on success, or an error code). On error, an error message is pushed onto the stack.

The mode parameter controls what kind of chunks can be loaded: "t" for text only, "b" for binary only, "bt" for both (default if empty).

func (*State) MemoryUsed

func (L *State) MemoryUsed() int64

MemoryUsed returns the current Lua-level memory usage in bytes.

func (*State) NewLib

func (L *State) NewLib(funcs map[string]Function)

NewLib creates a new table and registers functions into it.

func (*State) NewMetatable

func (L *State) NewMetatable(tname string) bool

NewMetatable creates a new metatable in the registry with the given name. If the registry already has a table with that name, pushes it and returns false. Otherwise creates a new table, stores it, and returns true.

func (*State) NewTable

func (L *State) NewTable()

NewTable pushes a new empty table onto the stack.

func (*State) NewTableFrom

func (L *State) NewTableFrom(fields map[string]any)

NewTableFrom creates a new table, fills it with the given fields, and leaves it on top of the stack. Values are pushed using PushAny.

Example
package main

import (
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	L.NewTableFrom(map[string]any{
		"host": "localhost",
		"port": 8080,
	})
	L.SetGlobal("config")

	L.DoString(`print(config.host .. ":" .. config.port)`)
}
Output:
localhost:8080

func (*State) NewThread

func (L *State) NewThread() *State

NewThread creates a new Lua thread (coroutine), pushes it onto the stack, and returns a *State representing the new thread.

func (*State) NewUserdata

func (L *State) NewUserdata(size int, nUV int)

NewUserdata creates a new full userdata with nUV user values and pushes it onto the stack. The size parameter is ignored (Go manages memory). Returns a handle that can be used with SetUserdataValue.

func (*State) Next

func (L *State) Next(idx int) bool

Next pops a key and pushes the next key–value pair from the table at idx. Returns false when the traversal is complete (nothing pushed).

func (*State) OptInteger

func (L *State) OptInteger(idx int, def int64) int64

OptInteger returns the integer at idx, or def if the argument is nil/absent.

func (*State) OptNumber

func (L *State) OptNumber(idx int, def float64) float64

OptNumber returns the number at idx, or def if the argument is nil/absent.

func (*State) OptString

func (L *State) OptString(idx int, def string) string

OptString returns the string at idx, or def if the argument is nil/absent.

func (*State) PCall

func (L *State) PCall(nArgs, nResults, msgHandler int) int

PCall calls a function in protected mode. Returns a status code: OK on success, or an error code. If msgHandler is non-zero, it is the stack index of a message handler.

func (*State) Pop

func (L *State) Pop(n int)

Pop removes n elements from the top of the stack.

func (*State) PrepareReload added in v0.8.0

func (L *State) PrepareReload(moduleName string) (*ReloadPlan, error)

PrepareReload compiles and loads new module code, creating a reload plan. This is Phase 1 of the two-phase commit — the old module table remains in package.loaded and no function replacements occur until Commit().

IMPORTANT: This method executes the new module's initialization code via require(). Any side effects in the module's init code (global writes, I/O, registry modifications, etc.) will persist even if Abort() is called afterward. Only the function replacement step is deferred to Commit().

Returns error if the module is not loaded or compilation/loading fails. On failure, the old module is fully restored in package.loaded.

func (*State) PushAny

func (L *State) PushAny(value any)

PushAny pushes any Go value onto the Lua stack, automatically selecting the appropriate Lua type:

Go type              → Lua type
nil                  → nil
bool                 → boolean
int, int8..int64     → integer
uint, uint8..uint64  → integer (or number if > math.MaxInt64)
float32, float64     → number
string               → string
[]byte               → string
[]T                  → table (array, 1-indexed)
map[string]T         → table (hash)
map[K]V              → table (hash, keys converted via fmt.Sprint)
Function             → function
struct               → table (exported fields, using `lua` tag or lowercase name)
*struct              → same as struct (dereferences pointer)
StackRef             → copies stack value at ref.Index (via PushValue)
any other            → light userdata

Nested values are handled recursively.

Example
package main

import (
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	// Push a Go map as a Lua table.
	L.PushAny(map[string]any{
		"name": "Alice",
		"age":  30,
	})
	L.SetGlobal("user")

	L.DoString(`print(user.name, user.age)`)
}
Output:
Alice	30

func (*State) PushBoolean

func (L *State) PushBoolean(b bool)

PushBoolean pushes a boolean value onto the stack.

func (*State) PushCloseableResource added in v0.9.9

func (L *State) PushCloseableResource(resource Closeable)

PushCloseableResource pushes a Go resource with both __gc AND __close support. This allows Lua 5.5's <close> syntax:

local conn <close> = db.open(...)
-- conn:close() called automatically when leaving scope

Also has __gc as a safety net if <close> is not used.

func (*State) PushClosure

func (L *State) PushClosure(f Function, n int)

PushClosure pushes a Go function as a closure with n upvalues. The upvalues must be on the stack before calling this function.

func (*State) PushFString

func (L *State) PushFString(format string, args ...interface{}) string

PushFString pushes a formatted string onto the stack and returns it.

func (*State) PushFail

func (L *State) PushFail()

PushFail pushes a "fail" value (nil in Lua 5.5).

func (*State) PushFunction

func (L *State) PushFunction(f Function)

PushFunction pushes a Go function as a light C function (no upvalues).

Example
package main

import (
	"fmt"
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	add := func(L *lua.State) int {
		a := L.CheckInteger(1)
		b := L.CheckInteger(2)
		L.PushInteger(a + b)
		return 1
	}
	L.PushFunction(add)
	L.SetGlobal("add")

	L.DoString(`result = add(10, 32)`)
	L.GetGlobal("result")
	val, _ := L.ToInteger(-1)
	fmt.Println(val)
}
Output:
42

func (*State) PushGlobalTable

func (L *State) PushGlobalTable()

PushGlobalTable pushes the global table onto the stack.

func (*State) PushGoFunc

func (L *State) PushGoFunc(fn any)

PushGoFunc pushes an arbitrary Go function onto the Lua stack as a Lua-callable function. Parameters are read from the Lua stack via reflection and return values are pushed back automatically.

Supported parameter types: string, bool, int/int8/../int64, uint/uint8/../uint64, float32/float64, map[string]any, []any, any (interface{}), structs (via ToStruct), *struct.

Supported return types: same as parameters, plus error. If the last return is error and non-nil, a Lua error is raised. If the last return is error and nil, it is not pushed.

If Lua passes fewer args than the function expects, missing parameters receive their Go zero value.

Example:

L.PushGoFunc(func(name string, age int) string {
    return fmt.Sprintf("Hello %s, age %d", name, age)
})
L.SetGlobal("greet")
// Lua: greet("world", 42) → "Hello world, age 42"
Example
package main

import (
	"strings"

	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	// Register a Go function — no manual stack manipulation needed.
	L.PushGoFunc(func(name string, times int) string {
		return strings.Repeat(name+" ", times)
	})
	L.SetGlobal("repeat_name")

	L.DoString(`print(repeat_name("hello", 3))`)
}
Output:
hello hello hello
Example (Error)
package main

import (
	"fmt"

	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	L.PushGoFunc(func(n int) (int, error) {
		if n < 0 {
			return 0, fmt.Errorf("negative number: %d", n)
		}
		return n * n, nil
	})
	L.SetGlobal("square")

	L.DoString(`
		print(square(5))
		local ok, err = pcall(square, -3)
		print(ok, err)
	`)
}
Output:
25
false	negative number: -3

func (*State) PushInteger

func (L *State) PushInteger(n int64)

PushInteger pushes an integer value onto the stack.

func (*State) PushLightUserdata

func (L *State) PushLightUserdata(p interface{})

PushLightUserdata pushes a light userdata (Go value without metatable support).

func (*State) PushNil

func (L *State) PushNil()

PushNil pushes a nil value onto the stack.

func (*State) PushNumber

func (L *State) PushNumber(n float64)

PushNumber pushes a floating-point number onto the stack.

func (*State) PushResource added in v0.9.9

func (L *State) PushResource(resource Closeable)

PushResource pushes a Go resource as userdata with a __gc metamethod. When Lua's GC collects this userdata, the resource's Close() is called. This prevents Go resource leaks when Lua code forgets to close explicitly.

The metatable is named "go.resource" and provides:

  • __gc: calls resource.Close()
  • close: explicit close (idempotent)

Example:

conn := db.Open(...)
L.PushResource(conn)
L.SetGlobal("conn")
// conn.Close() will be called when GC collects it or Lua calls conn:close()

func (*State) PushString

func (L *State) PushString(s string) string

PushString pushes a string onto the stack and returns it.

func (*State) PushThread

func (L *State) PushThread() bool

PushThread pushes the running thread onto its own stack. Returns true if the thread is the main thread.

func (*State) PushUserdata

func (L *State) PushUserdata(value any)

PushUserdata creates a new full userdata wrapping a Go value and pushes it onto the stack. This is a convenience wrapper around NewUserdata + SetUserdataValue for the common case of storing a single Go value.

func (*State) PushValue

func (L *State) PushValue(idx int)

PushValue pushes a copy of the element at idx onto the stack.

func (*State) RawEqual

func (L *State) RawEqual(idx1, idx2 int) bool

RawEqual compares two values for equality without metamethods.

func (*State) RawGet

func (L *State) RawGet(idx int) Type

RawGet pushes t[k] without invoking metamethods. t is at idx, k is at top. Pops the key.

func (*State) RawGetI

func (L *State) RawGetI(idx int, n int64) Type

RawGetI pushes t[n] without invoking metamethods.

func (*State) RawGetP

func (L *State) RawGetP(idx int, p uintptr) Type

RawGetP does t[p] where p is a light userdata pointer key. Pushes the result. Returns the type of the result. Mirrors: lua_rawgetp in lapi.c

func (*State) RawLen

func (L *State) RawLen(idx int) int64

RawLen returns the raw length of the value at idx (no __len metamethod).

func (*State) RawSet

func (L *State) RawSet(idx int)

RawSet does t[k] = v without invoking metamethods. t is at idx, k at top-1, v at top. Pops key and value.

func (*State) RawSetI

func (L *State) RawSetI(idx int, n int64)

RawSetI does t[n] = v without invoking metamethods. t is at idx, v at top. Pops the value.

func (*State) RawSetP

func (L *State) RawSetP(idx int, p uintptr)

RawSetP does t[p] = v where p is a light userdata pointer key. v is the value at the top of the stack (popped). Mirrors: lua_rawsetp in lapi.c

func (*State) Ref

func (L *State) Ref(t int) int

Ref creates a reference in the table at idx. Pops the top value and stores it, returning an integer key. If the value is nil, returns RefNil and pops without storing.

func (*State) ReloadModule added in v0.8.0

func (L *State) ReloadModule(name string) (*ReloadResult, error)

ReloadModule is a convenience function that prepares and commits in one step. If preparation fails, returns error (no state modified). Incompatible functions are skipped (partial update).

Example
package main

import (
	"fmt"
	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	// Load initial module
	L.DoString(`
		package.preload["mymod"] = function()
			local M = {}
			local count = 0
			function M.inc() count = count + 1; return count end
			function M.get() return count end
			return M
		end
	`)
	L.DoString(`
		local m = require("mymod")
		m.inc(); m.inc(); m.inc()
	`)

	// Update module (inc now adds 10)
	L.DoString(`
		package.preload["mymod"] = function()
			local M = {}
			local count = 0
			function M.inc() count = count + 10; return count end
			function M.get() return count end
			return M
		end
	`)

	result, _ := L.ReloadModule("mymod")
	fmt.Printf("replaced: %d\n", result.Replaced)

	// State preserved, new behavior active
	L.DoString(`
		local m = require("mymod")
		print("count:", m.get())  -- preserved: 3
		m.inc()
		print("after inc:", m.get())  -- 3 + 10 = 13
	`)
}
Output:
replaced: 2
count:	3
after inc:	13

func (*State) Remove

func (L *State) Remove(idx int)

Remove removes the element at idx, shifting elements above it down.

func (*State) Replace

func (L *State) Replace(idx int)

Replace replaces the value at idx with the top element, popping the top.

func (*State) Require

func (L *State) Require(modname string, openf Function, global bool)

Require loads a module. If the module is already in package.loaded, pushes the cached value. Otherwise calls openf to load it. If global is true, also sets it as a global.

func (*State) ResetCPUCounter

func (L *State) ResetCPUCounter()

ResetCPUCounter resets the instruction counter to 0 without changing the limit. This is useful when reusing a state across multiple script executions so that each execution starts with a fresh budget.

func (*State) Resume

func (L *State) Resume(from *State, nArgs int) (int, int)

Resume starts or resumes a coroutine. from is the calling coroutine (or nil). Returns (status, nresults). Status is OK when finished, or Yield when suspended.

func (*State) Rotate

func (L *State) Rotate(idx, n int)

Rotate rotates the stack elements between idx and the top by n positions.

func (*State) SafeCall added in v0.9.9

func (L *State) SafeCall(nArgs, nResults int) error

SafeCall calls the function at the top of the stack in protected mode. Unlike PCall, it automatically:

  1. Uses debug.traceback as the message handler (full Lua stack trace on error)
  2. Recovers from Go panics in the called function (converts to Lua error)

On success, returns nil and leaves nResults on the stack. On error, returns an error with the full Lua traceback and pops the error message.

Example:

L.GetGlobal("myfunction")
L.PushString("arg1")
err := L.SafeCall(1, 0)
if err != nil {
    log.Printf("Lua error:\n%s", err)
}

func (*State) SafeCallFunc added in v0.9.9

func (L *State) SafeCallFunc(fn Function, nResults int) error

SafeCallFunc is a convenience that pushes a Go function, calls it with SafeCall, and returns any error. Useful for calling Go functions that might panic.

Example:

err := L.SafeCallFunc(func(L *lua.State) int {
    // This might panic
    result := riskyOperation()
    L.PushAny(result)
    return 1
}, 0)

func (*State) SetCPULimit

func (L *State) SetCPULimit(limit int64)

SetCPULimit sets the maximum number of Lua VM instructions this state may execute. When the limit is reached the currently running Lua code receives a Lua error: "CPU limit exceeded: <limit> instructions".

Set limit=0 to remove the CPU limit and clear the count hook installed by a previous call (unless a context is still active via State.SetContext, in which case the context-only hook remains).

Internally this uses the debug hook mechanism with MaskCount. Setting a CPU limit will override any previously set count hook. Line and call hooks set via State.SetHook are NOT affected — only the count component changes.

When used together with State.SetContext, both checks are combined into a single hook for efficiency.

Example:

L.SetCPULimit(1_000_000) // allow at most ~1 million instructions
err := L.DoString(`while true do end`) // will error

func (*State) SetContext

func (L *State) SetContext(ctx context.Context)

SetContext associates a Go context.Context with this Lua state. When the context is cancelled or times out, the currently running Lua code receives a Lua error: "context cancelled: <reason>".

Internally this uses the debug hook mechanism with MaskCount, the same mechanism used by State.SetCPULimit. The combined hook checks both context cancellation and CPU limits on every interval (default 1000 instructions). Setting a context will reinstall the hook to include the context check; any previously set count hook is replaced.

Pass nil to remove the context association and its hook (unless a CPU limit is still active, in which case the CPU-only hook remains).

Example:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
L.SetContext(ctx)
err := L.DoString(`while true do end`) // will error after ~5 seconds

func (*State) SetField

func (L *State) SetField(idx int, key string)

SetField does t[key] = v where t is at idx and v is at the top of the stack. Pops the value.

func (*State) SetFields

func (L *State) SetFields(idx int, fields map[string]any)

SetFields sets multiple fields on the table at idx. Values are pushed using PushAny (supports all Go types). Equivalent to calling PushAny(v); SetField(idx, k) for each entry.

func (*State) SetFileSystem

func (L *State) SetFileSystem(fsys fs.FS)

SetFileSystem sets a custom fs.FS for Lua file operations. When set, State.LoadFile, State.DoFile, and the package.searchers Lua-file searcher will read from this FS instead of the real filesystem.

This enables loading Lua scripts from Go's embed.FS, in-memory filesystems, or any other fs.FS implementation:

//go:embed lua/*
var luaFS embed.FS
sub, _ := fs.Sub(luaFS, "lua")
L.SetFileSystem(sub)
L.DoString(`require("mymodule")`)  // loads from embedded FS

Set to nil to revert to the real OS filesystem (default).

func (*State) SetFuncs

func (L *State) SetFuncs(funcs map[string]Function, nUp int)

SetFuncs registers functions from a map into the table at the top of the stack. nUp is the number of upvalues (must be on the stack above the table).

func (*State) SetGCMode

func (L *State) SetGCMode(mode string) string

SetGCMode sets the GC mode and returns the previous mode.

func (*State) SetGCParam

func (L *State) SetGCParam(name string, value int64) int64

SetGCParam sets a GC parameter and returns the previous value.

func (*State) SetGCStopped

func (L *State) SetGCStopped(stopped bool)

SetGCStopped sets or clears the GC stopped flag.

func (*State) SetGlobal

func (L *State) SetGlobal(name string)

SetGlobal pops a value and sets it as the global variable name.

func (*State) SetHook

func (L *State) SetHook(f HookFunc, mask, count int)

SetHook sets the debug hook function with the given mask and count. mask is a combination of MaskCall, MaskRet, MaskLine, MaskCount. count is the instruction count for count hooks (0 to disable count hooks). Pass nil as f to remove the current hook.

Example:

L.SetHook(func(L *lua.State, event int, line int) {
    if event == lua.HookEventLine {
        fmt.Printf("executing line %d\n", line)
    }
}, lua.MaskLine, 0)

func (*State) SetHookFields

func (L *State) SetHookFields(mask, count int)

SetHookFields sets the hook mask and count on the state. Deprecated: Use State.SetHook instead for a complete hook API.

func (*State) SetHookMarker

func (L *State) SetHookMarker()

SetHookMarker sets a non-nil marker to indicate hooks are active. Deprecated: Use State.SetHook instead.

func (*State) SetI

func (L *State) SetI(idx int, n int64)

SetI does t[n] = v where t is at idx and v is at the top of the stack. Pops the value.

func (*State) SetIUserValue

func (L *State) SetIUserValue(idx int, n int) bool

SetIUserValue sets the n-th user value of the userdata at idx to the value at the top of the stack. Pops the value. Returns false if the operation fails.

func (*State) SetLocal

func (L *State) SetLocal(ar *DebugInfo, n int) string

SetLocal sets the value of local variable n from the top of the stack. Returns the variable name, or "" if not found.

func (*State) SetMemoryLimit

func (L *State) SetMemoryLimit(limit int64) int64

SetMemoryLimit sets the maximum memory (in bytes) that Lua objects can use. 0 means no limit. Returns the previous limit. When the limit is exceeded, Lua code receives an "out of memory" error that can be caught by pcall/xpcall.

func (*State) SetMetatable

func (L *State) SetMetatable(idx int)

SetMetatable pops a table from the stack and sets it as the metatable of the value at idx.

func (*State) SetTable

func (L *State) SetTable(idx int)

SetTable does t[k] = v where t is at idx, k is at top-1, v is at top. Pops both the key and value. May trigger __newindex metamethod.

func (*State) SetTop

func (L *State) SetTop(idx int)

SetTop sets the stack top to idx. If the new top is larger than the old one, new elements are filled with nil. If idx is 0, all stack elements are removed.

func (*State) SetUpvalue

func (L *State) SetUpvalue(funcIdx, n int) (string, bool)

SetUpvalue sets upvalue n of the closure at funcIdx from the top of the stack. Returns (name, true) if the upvalue exists, ("", false) otherwise.

func (*State) SetUserValue

func (L *State) SetUserValue(key string, value any)

SetUserValue stores an arbitrary Go value associated with the given key. This allows embedding applications to attach per-State data without global variables. Keys are arbitrary strings. Values can be any Go type. The value is stored on the internal State and survives wrapFunction.

func (*State) SetUserdataValue

func (L *State) SetUserdataValue(idx int, v any)

SetUserdataValue sets the Go value stored in the full userdata at idx.

func (*State) SetWarnF

func (L *State) SetWarnF(f WarnFunction, ud interface{})

SetWarnF sets the warning handler function. Mirrors: lua_setwarnf in lapi.c

func (*State) SetWriter

func (L *State) SetWriter(w io.Writer)

SetWriter sets a custom writer for Lua print() and io.write() output. If w is nil, output reverts to os.Stdout (the default). The writer is stored on the internal api.State so it survives wrapFunction which creates fresh pkg/lua.State wrappers sharing the same api.State.

func (*State) Status

func (L *State) Status() int

Status returns the status of the coroutine.

func (*State) StringToNumber

func (L *State) StringToNumber(s string) int

StringToNumber tries to convert a string to a number and pushes it. Returns the string length + 1 on success, 0 on failure.

func (*State) TestUdata

func (L *State) TestUdata(idx int, tname string) bool

TestUdata checks if the value at idx is a userdata with metatable matching registry[tname]. Returns true if it matches.

func (*State) ToAny

func (L *State) ToAny(idx int) any

ToAny reads the value at the given stack index and returns it as a Go value:

Lua type    → Go type
nil         → nil (interface{})
boolean     → bool
integer     → int64
number      → float64
string      → string
table       → []any (sequential integer keys 1..n) or map[string]any
userdata    → the stored Go value (via [State.UserdataValue])
function    → nil (cannot convert)
thread      → nil (cannot convert)

Table detection: if the table has exactly n entries and all keys are integers 1..n, it is returned as []any. Otherwise it is returned as map[string]any with non-string keys converted via strconv or fmt.

Example
package main

import (
	"fmt"

	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	L.DoString(`t = {name = "Bob", score = 95}`)
	L.GetGlobal("t")
	val := L.ToAny(-1)
	m := val.(map[string]any)
	fmt.Println(m["name"], m["score"])
	L.Pop(1)
}
Output:
Bob 95

func (*State) ToBoolean

func (L *State) ToBoolean(idx int) bool

ToBoolean converts the value at idx to a boolean. Returns false for nil and false, true for everything else.

func (*State) ToClose

func (L *State) ToClose(idx int)

ToClose marks the value at the given index as a to-be-closed variable. Like a local variable declared with <close>, the value's __close metamethod will be called when it goes out of scope. Mirrors: lua_toclose in lapi.c

func (*State) ToInteger

func (L *State) ToInteger(idx int) (int64, bool)

ToInteger converts the value at idx to an integer. Returns (value, true) on success, (0, false) if the value is not an integer or a float with an exact integer representation.

func (*State) ToMap

func (L *State) ToMap(idx int) (map[string]any, bool)

ToMap reads the value at idx as a map[string]any. Returns (map, true) if the value is a table with string keys, (nil, false) otherwise (including pure-array tables or non-table values). This is a typed convenience wrapper around ToAny for the common case.

func (*State) ToNumber

func (L *State) ToNumber(idx int) (float64, bool)

ToNumber converts the value at idx to a floating-point number. Returns (value, true) on success, (0, false) if not convertible.

func (*State) ToPointer

func (L *State) ToPointer(idx int) string

ToPointer returns a string representation of the pointer value at idx. Useful for debugging.

func (*State) ToString

func (L *State) ToString(idx int) (string, bool)

ToString converts the value at idx to a string. Returns (value, true) for strings and numbers (coerced in place), ("", false) for other types.

func (*State) ToStruct

func (L *State) ToStruct(idx int, dest any) error

ToStruct reads a Lua table at the given stack index into a Go struct. The dest argument must be a non-nil pointer to a struct.

Field mapping uses the `lua` struct tag if present, otherwise the field name with its first letter lowercased. Fields tagged with `lua:"-"` are skipped. Unexported fields are always skipped.

Supported field types: string, bool, all int/uint/float variants, and nested slices/maps (via State.ToAny).

Example:

type Config struct {
    Host  string  `lua:"host"`
    Port  int64   `lua:"port"`
    Debug bool    `lua:"debug"`
}
var cfg Config
err := L.ToStruct(-1, &cfg)
Example
package main

import (
	"fmt"

	"github.com/akzj/go-lua/pkg/lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	type Config struct {
		Host string `lua:"host"`
		Port int    `lua:"port"`
	}

	L.DoString(`config = {host = "localhost", port = 8080}`)
	L.GetGlobal("config")

	var cfg Config
	L.ToStruct(-1, &cfg)
	fmt.Println(cfg.Host, cfg.Port)
	L.Pop(1)
}
Output:
localhost 8080

func (*State) ToThread

func (L *State) ToThread(idx int) *State

ToThread converts the value at idx to a *State (thread). Returns nil if the value is not a thread.

func (*State) TolString

func (L *State) TolString(idx int) string

TolString converts the value at idx to a string, using __tostring metamethod if present. Pushes the result and returns it.

func (*State) Type

func (L *State) Type(idx int) Type

Type returns the type of the value at the given index.

func (*State) TypeError

func (L *State) TypeError(arg int, tname string) int

TypeError raises a type error for argument arg. This function does not return.

func (*State) TypeName

func (L *State) TypeName(tp Type) string

TypeName returns the name of the given type.

func (*State) Unref

func (L *State) Unref(t int, ref int)

Unref frees a reference in the table at idx.

func (*State) UpvalueId

func (L *State) UpvalueId(funcIdx, n int) interface{}

UpvalueId returns a unique identifier for upvalue n of the closure at funcIdx.

func (*State) UpvalueJoin

func (L *State) UpvalueJoin(funcIdx1, n1, funcIdx2, n2 int)

UpvalueJoin makes the n1-th upvalue of funcIdx1 refer to n2-th of funcIdx2.

func (*State) UserValue

func (L *State) UserValue(key string) any

UserValue retrieves a Go value previously stored with SetUserValue. Returns nil if the key was never set.

func (*State) UserdataValue

func (L *State) UserdataValue(idx int) any

UserdataValue returns the Go value stored in the userdata at idx. Returns nil if the value is not a full userdata or light userdata.

func (*State) Warning

func (L *State) Warning(msg string, tocont bool)

Warning emits a warning message. If tocont is true, the message is to be continued by the next call to Warning. Mirrors: lua_warning in lapi.c

func (*State) Where

func (L *State) Where(level int)

Where pushes a string "source:line: " for the given call level.

func (*State) Writer

func (L *State) Writer() io.Writer

Writer returns the current output writer. Returns os.Stdout if none was set.

func (*State) XMove

func (L *State) XMove(to *State, n int)

XMove moves n values from L's stack to to's stack.

func (*State) Yield

func (L *State) Yield(nResults int) int

Yield yields the current coroutine. nResults values on the stack are passed back to the resume caller.

func (*State) YieldK

func (L *State) YieldK(nResults int, ctx int, k Function) int

YieldK yields with a continuation function.

type StatePool

type StatePool struct {
	// contains filtered or unexported fields
}

StatePool manages a pool of reusable Lua State values.

Thread-safe: StatePool.Get and StatePool.Put can be called from any goroutine. Each State returned by Get is exclusively owned by the caller until Put is called — States are never shared between goroutines.

func NewStatePool

func NewStatePool(config PoolConfig) *StatePool

NewStatePool creates a new State pool with the given configuration.

func (*StatePool) Close

func (p *StatePool) Close()

Close closes all States in the pool and prevents further use. After Close, StatePool.Get will still create new States, but StatePool.Put will close them immediately.

func (*StatePool) Get

func (p *StatePool) Get() *State

Get retrieves a State from the pool, or creates a new one if the pool is empty. The returned State is exclusively owned by the caller until StatePool.Put is called.

func (*StatePool) Put

func (p *StatePool) Put(L *State)

Put returns a State to the pool for reuse. If the pool is full or closed, the State is closed instead.

The caller must not use L after calling Put.

func (*StatePool) Stats

func (p *StatePool) Stats() PoolStats

Stats returns a snapshot of pool statistics.

type Task

type Task struct {
	// ID identifies this task (for correlating results).
	ID string

	// Code is the Lua source code to execute.
	// Either Code or Func must be set (not both).
	Code string

	// Func is a function to run with a Lua State.
	// Use this for complex operations that need direct State access.
	// Either Code or Func must be set (not both).
	Func func(L *State) (any, error)
}

Task represents a unit of Lua work to be executed asynchronously by an Executor.

type Timer

type Timer struct {
	ID       int64
	Interval time.Duration
	Repeat   bool
	Callback int // Lua registry reference to the callback function
	NextFire time.Time
	Canceled bool
}

Timer represents a scheduled timer managed by TimerManager.

type TimerManager

type TimerManager struct {
	// contains filtered or unexported fields
}

TimerManager manages all active timers for a Lua State. NOT thread-safe for Tick (must be called from the same goroutine as Lua). The mutex protects cancel operations which may come from any goroutine.

func GetTimerManager

func GetTimerManager(L *State) *TimerManager

GetTimerManager returns the TimerManager for a State, creating one if needed. This is the public API for host applications that need to call Tick() in their event loop.

func NewTimerManager

func NewTimerManager() *TimerManager

NewTimerManager creates a new TimerManager.

func (*TimerManager) Add

func (tm *TimerManager) Add(t *Timer) int64

Add registers a timer and returns its ID.

func (*TimerManager) Cancel

func (tm *TimerManager) Cancel(id int64)

Cancel marks a timer as canceled.

func (*TimerManager) Pending

func (tm *TimerManager) Pending() int

Pending returns the number of active (non-canceled) timers.

func (*TimerManager) Tick

func (tm *TimerManager) Tick(L *State) int

Tick checks all timers and fires expired ones. Calls the Lua callback for each expired timer via PCall. Must be called from the same goroutine that owns the Lua State. Returns the number of remaining active timers.

type Type

type Type int

Type represents a Lua value type, corresponding to the LUA_T* constants in the C Lua API.

const (
	TypeNil           Type = 0  // LUA_TNIL — the nil value
	TypeBoolean       Type = 1  // LUA_TBOOLEAN — true or false
	TypeLightUserdata Type = 2  // LUA_TLIGHTUSERDATA — raw Go interface{} without metatable
	TypeNumber        Type = 3  // LUA_TNUMBER — integer or floating-point number
	TypeString        Type = 4  // LUA_TSTRING — immutable string
	TypeTable         Type = 5  // LUA_TTABLE — associative array
	TypeFunction      Type = 6  // LUA_TFUNCTION — Lua or Go function
	TypeUserdata      Type = 7  // LUA_TUSERDATA — full userdata with metatable support
	TypeThread        Type = 8  // LUA_TTHREAD — coroutine
	TypeNone          Type = -1 // LUA_TNONE — invalid or absent stack index
)

Lua value types. These match the C Lua LUA_T* constants.

type WarnFunction

type WarnFunction func(ud interface{}, msg string, tocont bool)

WarnFunction is the type for warning handler functions.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL