karmada/pkg/resourceinterpreter/configurableinterpreter/luavm/lua_convert.go

105 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package luavm
import (
"encoding/json"
"fmt"
"reflect"
lua "github.com/yuin/gopher-lua"
"k8s.io/apimachinery/pkg/conversion"
luajson "layeh.com/gopher-json"
)
// ConvertLuaResultInto convert lua result to obj
func ConvertLuaResultInto(luaResult lua.LValue, obj interface{}) error {
t, err := conversion.EnforcePtr(obj)
if err != nil {
return fmt.Errorf("obj is not pointer")
}
// For example, `GetReplicas` returns requirement with empty:
// {
// nodeClaim: {},
// resourceRequest: {
// cpu: "100m"
// }
// }
// Luajson encodes it to
// {"nodeClaim": [], "resourceRequest": {"cpu": "100m"}}
//
// While go json fails to unmarshal `[]` to ReplicaRequirements.NodeClaim object.
// ReplicaRequirements object.
//
// Here we handle it as follows:
// 1. Walk the object (lua table), delete the key with empty value (`nodeClaim` in this example):
// {
// resourceRequest: {
// cpu: "100m"
// }
// }
// 2. Encode the object with luajson to be:
// {"resourceRequest": {"cpu": "100m"}}
// 4. Finally, unmarshal the new json to object, get
// {
// resourceRequest: {
// cpu: "100m"
// }
// }
isEmptyDic := func(v *lua.LTable) bool {
count := 0
v.ForEach(func(lua.LValue, lua.LValue) {
count++
})
return count == 0
}
var walkValue func(v lua.LValue)
walkValue = func(v lua.LValue) {
if t, ok := v.(*lua.LTable); ok {
t.ForEach(func(key lua.LValue, value lua.LValue) {
if tt, ok := value.(*lua.LTable); ok {
if isEmptyDic(tt) {
// set nil to delete key
t.RawSetH(key, lua.LNil)
} else {
walkValue(value)
}
}
})
}
}
walkValue(luaResult)
jsonBytes, err := luajson.Encode(luaResult)
if err != nil {
return fmt.Errorf("json Encode obj eroor %v", err)
}
// for lua an empty object by json encode be [] not {}
if t.Kind() == reflect.Struct && len(jsonBytes) > 1 && jsonBytes[0] == '[' {
jsonBytes[0], jsonBytes[len(jsonBytes)-1] = '{', '}'
}
err = json.Unmarshal(jsonBytes, obj)
if err != nil {
return fmt.Errorf("can not unmarshal %v to %#v%v", string(jsonBytes), obj, err)
}
return nil
}
// ConvertLuaResultToInt convert lua result to int.
func ConvertLuaResultToInt(luaResult lua.LValue) (int32, error) {
if luaResult.Type() != lua.LTNumber {
return 0, fmt.Errorf("result type %#v is not number", luaResult.Type())
}
return int32(luaResult.(lua.LNumber)), nil
}
// ConvertLuaResultToBool convert lua result to bool.
func ConvertLuaResultToBool(luaResult lua.LValue) (bool, error) {
if luaResult.Type() != lua.LTBool {
return false, fmt.Errorf("result type %#v is not bool", luaResult.Type())
}
return bool(luaResult.(lua.LBool)), nil
}