LuaJIT-to-Go/types.go
Sky Johnson f4bfff470f massive rewrite
fix go func mallocs
add helper utils
2025-05-31 17:42:58 -05:00

367 lines
7.4 KiB
Go

package luajit
/*
#include <lua.h>
*/
import "C"
import (
"fmt"
"strconv"
)
// LuaType represents Lua value types
type LuaType int
const (
TypeNone LuaType = -1
TypeNil LuaType = 0
TypeBoolean LuaType = 1
TypeLightUserData LuaType = 2
TypeNumber LuaType = 3
TypeString LuaType = 4
TypeTable LuaType = 5
TypeFunction LuaType = 6
TypeUserData LuaType = 7
TypeThread LuaType = 8
)
func (t LuaType) String() string {
switch t {
case TypeNone:
return "none"
case TypeNil:
return "nil"
case TypeBoolean:
return "boolean"
case TypeLightUserData:
return "lightuserdata"
case TypeNumber:
return "number"
case TypeString:
return "string"
case TypeTable:
return "table"
case TypeFunction:
return "function"
case TypeUserData:
return "userdata"
case TypeThread:
return "thread"
default:
return "unknown"
}
}
// ConvertValue converts a value to the requested type with comprehensive type conversion
func ConvertValue[T any](value any) (T, bool) {
var zero T
if value == nil {
return zero, false
}
if result, ok := value.(T); ok {
return result, true
}
switch any(zero).(type) {
case string:
return convertToString[T](value)
case int:
return convertToInt[T](value)
case float64:
return convertToFloat[T](value)
case bool:
return convertToBool[T](value)
case []int:
return convertToIntSlice[T](value)
case []string:
return convertToStringSlice[T](value)
case []bool:
return convertToBoolSlice[T](value)
case []float64:
return convertToFloatSlice[T](value)
case []any:
return convertToAnySlice[T](value)
case map[string]string:
return convertToStringMap[T](value)
case map[string]int:
return convertToIntMap[T](value)
case map[int]any:
return convertToIntKeyMap[T](value)
case map[string]any:
return convertToAnyMap[T](value)
}
return zero, false
}
func convertToString[T any](value any) (T, bool) {
var zero T
switch v := value.(type) {
case float64:
if v == float64(int(v)) {
return any(strconv.Itoa(int(v))).(T), true
}
return any(fmt.Sprintf("%g", v)).(T), true
case int:
return any(strconv.Itoa(v)).(T), true
case bool:
return any(strconv.FormatBool(v)).(T), true
}
return zero, false
}
func convertToInt[T any](value any) (T, bool) {
var zero T
switch v := value.(type) {
case float64:
return any(int(v)).(T), true
case string:
if i, err := strconv.Atoi(v); err == nil {
return any(i).(T), true
}
case bool:
if v {
return any(1).(T), true
}
return any(0).(T), true
}
return zero, false
}
func convertToFloat[T any](value any) (T, bool) {
var zero T
switch v := value.(type) {
case int:
return any(float64(v)).(T), true
case string:
if f, err := strconv.ParseFloat(v, 64); err == nil {
return any(f).(T), true
}
case bool:
if v {
return any(1.0).(T), true
}
return any(0.0).(T), true
}
return zero, false
}
func convertToBool[T any](value any) (T, bool) {
var zero T
switch v := value.(type) {
case string:
switch v {
case "true", "yes", "1":
return any(true).(T), true
case "false", "no", "0":
return any(false).(T), true
}
case int:
return any(v != 0).(T), true
case float64:
return any(v != 0).(T), true
}
return zero, false
}
func convertToIntSlice[T any](value any) (T, bool) {
var zero T
switch v := value.(type) {
case []float64:
result := make([]int, len(v))
for i, f := range v {
result[i] = int(f)
}
return any(result).(T), true
case []any:
result := make([]int, 0, len(v))
for _, item := range v {
if i, ok := ConvertValue[int](item); ok {
result = append(result, i)
} else {
return zero, false
}
}
return any(result).(T), true
}
return zero, false
}
func convertToStringSlice[T any](value any) (T, bool) {
var zero T
if v, ok := value.([]any); ok {
result := make([]string, 0, len(v))
for _, item := range v {
if s, ok := ConvertValue[string](item); ok {
result = append(result, s)
} else {
return zero, false
}
}
return any(result).(T), true
}
return zero, false
}
func convertToBoolSlice[T any](value any) (T, bool) {
var zero T
if v, ok := value.([]any); ok {
result := make([]bool, 0, len(v))
for _, item := range v {
if b, ok := ConvertValue[bool](item); ok {
result = append(result, b)
} else {
return zero, false
}
}
return any(result).(T), true
}
return zero, false
}
func convertToFloatSlice[T any](value any) (T, bool) {
var zero T
switch v := value.(type) {
case []int:
result := make([]float64, len(v))
for i, n := range v {
result[i] = float64(n)
}
return any(result).(T), true
case []any:
result := make([]float64, 0, len(v))
for _, item := range v {
if f, ok := ConvertValue[float64](item); ok {
result = append(result, f)
} else {
return zero, false
}
}
return any(result).(T), true
}
return zero, false
}
func convertToAnySlice[T any](value any) (T, bool) {
var zero T
switch v := value.(type) {
case []int:
result := make([]any, len(v))
for i, n := range v {
result[i] = n
}
return any(result).(T), true
case []string:
result := make([]any, len(v))
for i, s := range v {
result[i] = s
}
return any(result).(T), true
case []bool:
result := make([]any, len(v))
for i, b := range v {
result[i] = b
}
return any(result).(T), true
case []float64:
result := make([]any, len(v))
for i, f := range v {
result[i] = f
}
return any(result).(T), true
}
return zero, false
}
func convertToStringMap[T any](value any) (T, bool) {
var zero T
if v, ok := value.(map[string]any); ok {
result := make(map[string]string, len(v))
for k, val := range v {
if s, ok := ConvertValue[string](val); ok {
result[k] = s
} else {
return zero, false
}
}
return any(result).(T), true
}
return zero, false
}
func convertToIntMap[T any](value any) (T, bool) {
var zero T
if v, ok := value.(map[string]any); ok {
result := make(map[string]int, len(v))
for k, val := range v {
if i, ok := ConvertValue[int](val); ok {
result[k] = i
} else {
return zero, false
}
}
return any(result).(T), true
}
return zero, false
}
func convertToIntKeyMap[T any](value any) (T, bool) {
var zero T
if v, ok := value.(map[string]any); ok {
result := make(map[int]any, len(v))
for k, val := range v {
if i, err := strconv.Atoi(k); err == nil {
result[i] = val
} else {
return zero, false
}
}
return any(result).(T), true
}
return zero, false
}
func convertToAnyMap[T any](value any) (T, bool) {
var zero T
switch v := value.(type) {
case map[string]string:
result := make(map[string]any, len(v))
for k, s := range v {
result[k] = s
}
return any(result).(T), true
case map[string]int:
result := make(map[string]any, len(v))
for k, i := range v {
result[k] = i
}
return any(result).(T), true
case map[int]any:
result := make(map[string]any, len(v))
for k, val := range v {
result[strconv.Itoa(k)] = val
}
return any(result).(T), true
}
return zero, false
}
// GetTypedValue gets a value from the state with type conversion
func GetTypedValue[T any](s *State, index int) (T, bool) {
value, err := s.ToValue(index)
if err != nil {
var zero T
return zero, false
}
return ConvertValue[T](value)
}
// GetGlobalTyped gets a global variable with type conversion
func GetGlobalTyped[T any](s *State, name string) (T, bool) {
s.GetGlobal(name)
defer s.Pop(1)
return GetTypedValue[T](s, -1)
}