Files

177 lines
4.7 KiB
Go
Raw Permalink Normal View History

2020-09-15 19:52:54 -05:00
package binding
import (
"fmt"
"reflect"
"runtime"
2022-04-04 21:01:00 +10:00
"strings"
2020-09-15 19:52:54 -05:00
)
// isStructPtr returns true if the value given is a
// pointer to a struct
func isStructPtr(value interface{}) bool {
return reflect.ValueOf(value).Kind() == reflect.Ptr &&
reflect.ValueOf(value).Elem().Kind() == reflect.Struct
}
// isFunction returns true if the given value is a function
func isFunction(value interface{}) bool {
return reflect.ValueOf(value).Kind() == reflect.Func
}
// isStruct returns true if the value given is a struct
2020-09-15 19:52:54 -05:00
func isStruct(value interface{}) bool {
return reflect.ValueOf(value).Kind() == reflect.Struct
}
2021-01-27 21:12:17 +11:00
func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
2020-09-15 19:52:54 -05:00
// Create result placeholder
var result []*BoundMethod
// Check type
if !isStructPtr(value) {
if isStruct(value) {
name := reflect.ValueOf(value).Type().Name()
return nil, fmt.Errorf("%s is a struct, not a pointer to a struct", name)
}
if isFunction(value) {
name := runtime.FuncForPC(reflect.ValueOf(value).Pointer()).Name()
return nil, fmt.Errorf("%s is a function, not a pointer to a struct. Wails v2 has deprecated the binding of functions. Please wrap your functions up in a struct and bind a pointer to that struct.", name)
}
return nil, fmt.Errorf("not a pointer to a struct.")
2020-09-15 19:52:54 -05:00
}
// Process Struct
structType := reflect.TypeOf(value)
structValue := reflect.ValueOf(value)
2022-04-04 21:01:00 +10:00
structTypeString := structType.String()
baseName := structTypeString[1:]
2020-09-15 19:52:54 -05:00
// Process Methods
for i := 0; i < structType.NumMethod(); i++ {
methodDef := structType.Method(i)
methodName := methodDef.Name
fullMethodName := baseName + "." + methodName
method := structValue.MethodByName(methodName)
2021-01-27 21:12:17 +11:00
methodReflectName := runtime.FuncForPC(methodDef.Func.Pointer()).Name()
if b.exemptions.Contains(methodReflectName) {
continue
}
2020-09-15 19:52:54 -05:00
// Create new method
boundMethod := &BoundMethod{
Name: fullMethodName,
Inputs: nil,
Outputs: nil,
Comments: "",
Method: method,
}
// Iterate inputs
methodType := method.Type()
inputParamCount := methodType.NumIn()
var inputs []*Parameter
for inputIndex := 0; inputIndex < inputParamCount; inputIndex++ {
input := methodType.In(inputIndex)
thisParam := newParameter("", input)
thisInput := input
if thisInput.Kind() == reflect.Slice {
thisInput = thisInput.Elem()
}
// Process struct pointer params
if thisInput.Kind() == reflect.Ptr {
if thisInput.Elem().Kind() == reflect.Struct {
typ := thisInput.Elem()
a := reflect.New(typ)
s := reflect.Indirect(a).Interface()
2022-04-04 21:01:00 +10:00
name := typ.Name()
2022-04-05 08:26:54 +10:00
packageName := getPackageName(thisInput.String())
2022-04-04 21:01:00 +10:00
b.AddStructToGenerateTS(packageName, name, s)
}
}
// Process struct params
if thisInput.Kind() == reflect.Struct {
a := reflect.New(thisInput)
s := reflect.Indirect(a).Interface()
2022-04-04 21:01:00 +10:00
name := thisInput.Name()
2022-04-05 08:26:54 +10:00
packageName := getPackageName(thisInput.String())
2022-04-04 21:01:00 +10:00
b.AddStructToGenerateTS(packageName, name, s)
}
2020-09-15 19:52:54 -05:00
inputs = append(inputs, thisParam)
}
boundMethod.Inputs = inputs
// Iterate outputs
2020-11-15 09:25:38 +11:00
// TODO: Determine what to do about limiting return types
// especially around errors.
2020-09-15 19:52:54 -05:00
outputParamCount := methodType.NumOut()
var outputs []*Parameter
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
output := methodType.Out(outputIndex)
thisParam := newParameter("", output)
thisOutput := output
if thisOutput.Kind() == reflect.Slice {
thisOutput = thisOutput.Elem()
}
// Process struct pointer params
if thisOutput.Kind() == reflect.Ptr {
if thisOutput.Elem().Kind() == reflect.Struct {
typ := thisOutput.Elem()
a := reflect.New(typ)
s := reflect.Indirect(a).Interface()
2022-04-04 21:01:00 +10:00
name := typ.Name()
2022-04-05 08:26:54 +10:00
packageName := getPackageName(thisOutput.String())
2022-04-04 21:01:00 +10:00
b.AddStructToGenerateTS(packageName, name, s)
}
}
// Process struct params
if thisOutput.Kind() == reflect.Struct {
a := reflect.New(thisOutput)
s := reflect.Indirect(a).Interface()
2022-04-04 21:01:00 +10:00
name := thisOutput.Name()
2022-04-05 08:26:54 +10:00
packageName := getPackageName(thisOutput.String())
2022-04-04 21:01:00 +10:00
b.AddStructToGenerateTS(packageName, name, s)
}
2020-09-15 19:52:54 -05:00
outputs = append(outputs, thisParam)
}
boundMethod.Outputs = outputs
// Save method in result
result = append(result, boundMethod)
}
return result, nil
}
2022-04-05 08:26:54 +10:00
func getPackageName(in string) string {
result := strings.Split(in, ".")[0]
result = strings.ReplaceAll(result, "[]", "")
result = strings.ReplaceAll(result, "*", "")
return result
}
func getSplitReturn(in string) (string, string) {
result := strings.Split(in, ".")
return result[0], result[1]
}
func hasElements(typ reflect.Type) bool {
kind := typ.Kind()
return kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map
}