package luajit /* #include #include #include #include static int get_table_length(lua_State *L, int index) { return lua_objlen(L, index); } */ import "C" import ( "strconv" "sync" ) var tablePool = sync.Pool{ New: func() interface{} { return make(map[string]interface{}) }, } // TableValue represents any value that can be stored in a Lua table type TableValue interface { ~string | ~float64 | ~bool | ~int | ~map[string]interface{} | ~[]float64 | ~[]interface{} } func (s *State) GetTableLength(index int) int { return int(C.get_table_length(s.L, C.int(index))) } // getTableFromPool gets a map from the pool and ensures it's empty func getTableFromPool() map[string]interface{} { table := tablePool.Get().(map[string]interface{}) // Clear any existing entries for k := range table { delete(table, k) } return table } // putTableToPool returns a map to the pool func putTableToPool(table map[string]interface{}) { tablePool.Put(table) } // PushTable pushes a Go map onto the Lua stack as a table func (s *State) PushTable(table map[string]interface{}) error { s.CreateTable(0, len(table)) for k, v := range table { if err := s.PushValue(v); err != nil { return err } s.SetField(-2, k) } // If this is a pooled table, return it if _, hasEmptyKey := table[""]; len(table) == 1 && hasEmptyKey { putTableToPool(table) } return nil } // ToTable converts a Lua table to a Go map func (s *State) ToTable(index int) (map[string]interface{}, error) { absIdx := s.absIndex(index) table := getTableFromPool() // Check if it's an array-like table length := s.GetTableLength(absIdx) if length > 0 { array := make([]float64, length) isArray := true // Try to convert to array for i := 1; i <= length; i++ { s.PushNumber(float64(i)) s.GetTable(absIdx) if s.GetType(-1) != TypeNumber { isArray = false s.Pop(1) break } array[i-1] = s.ToNumber(-1) s.Pop(1) } if isArray { putTableToPool(table) // Return unused table to pool result := getTableFromPool() result[""] = array return result, nil } } // Handle regular table s.PushNil() for C.lua_next(s.L, C.int(absIdx)) != 0 { key := "" valueType := C.lua_type(s.L, -2) if valueType == C.LUA_TSTRING { key = s.ToString(-2) } else if valueType == C.LUA_TNUMBER { key = strconv.FormatFloat(s.ToNumber(-2), 'g', -1, 64) } value, err := s.ToValue(-1) if err != nil { s.Pop(1) putTableToPool(table) // Return table to pool on error return nil, err } // Handle nested array case if m, ok := value.(map[string]interface{}); ok { if arr, ok := m[""]; ok { value = arr } } table[key] = value s.Pop(1) } return table, nil } // NewTable creates a new table and pushes it onto the stack func (s *State) NewTable() { C.lua_createtable(s.L, 0, 0) } // SetTable sets a table field func (s *State) SetTable(index int) { C.lua_settable(s.L, C.int(index)) } // GetTable gets a table field func (s *State) GetTable(index int) { C.lua_gettable(s.L, C.int(index)) } func (s *State) CreateTable(narr, nrec int) { C.lua_createtable(s.L, C.int(narr), C.int(nrec)) }