github.com/AlpineAIO/wails/v2@v2.0.0-beta.32.0.20240505041856-1047a8fa5fef/internal/binding/boundMethod.go (about)

     1  package binding
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  )
     8  
     9  // BoundMethod defines all the data related to a Go method that is
    10  // bound to the Wails application
    11  type BoundMethod struct {
    12  	Name     string        `json:"name"`
    13  	Inputs   []*Parameter  `json:"inputs,omitempty"`
    14  	Outputs  []*Parameter  `json:"outputs,omitempty"`
    15  	Comments string        `json:"comments,omitempty"`
    16  	Method   reflect.Value `json:"-"`
    17  }
    18  
    19  // InputCount returns the number of inputs this bound method has
    20  func (b *BoundMethod) InputCount() int {
    21  	return len(b.Inputs)
    22  }
    23  
    24  // OutputCount returns the number of outputs this bound method has
    25  func (b *BoundMethod) OutputCount() int {
    26  	return len(b.Outputs)
    27  }
    28  
    29  // ParseArgs method converts the input json into the types expected by the method
    30  func (b *BoundMethod) ParseArgs(args []json.RawMessage) ([]interface{}, error) {
    31  	result := make([]interface{}, b.InputCount())
    32  	if len(args) != b.InputCount() {
    33  		return nil, fmt.Errorf("received %d arguments to method '%s', expected %d", len(args), b.Name, b.InputCount())
    34  	}
    35  	for index, arg := range args {
    36  		typ := b.Inputs[index].reflectType
    37  		inputValue := reflect.New(typ).Interface()
    38  		err := json.Unmarshal(arg, inputValue)
    39  		if err != nil {
    40  			return nil, err
    41  		}
    42  		if inputValue == nil {
    43  			result[index] = reflect.Zero(typ).Interface()
    44  		} else {
    45  			result[index] = reflect.ValueOf(inputValue).Elem().Interface()
    46  		}
    47  	}
    48  	return result, nil
    49  }
    50  
    51  // Call will attempt to call this bound method with the given args
    52  func (b *BoundMethod) Call(args []interface{}) (interface{}, error) {
    53  	// Check inputs
    54  	expectedInputLength := len(b.Inputs)
    55  	actualInputLength := len(args)
    56  	if expectedInputLength != actualInputLength {
    57  		return nil, fmt.Errorf("%s takes %d inputs. Received %d", b.Name, expectedInputLength, actualInputLength)
    58  	}
    59  
    60  	/** Convert inputs to reflect values **/
    61  
    62  	// Create slice for the input arguments to the method call
    63  	callArgs := make([]reflect.Value, expectedInputLength)
    64  
    65  	// Iterate over given arguments
    66  	for index, arg := range args {
    67  		// Save the converted argument
    68  		callArgs[index] = reflect.ValueOf(arg)
    69  	}
    70  
    71  	// Do the call
    72  	callResults := b.Method.Call(callArgs)
    73  
    74  	//** Check results **//
    75  	var returnValue interface{}
    76  	var err error
    77  
    78  	switch b.OutputCount() {
    79  	case 1:
    80  		// Loop over results and determine if the result
    81  		// is an error or not
    82  		for _, result := range callResults {
    83  			interfac := result.Interface()
    84  			temp, ok := interfac.(error)
    85  			if ok {
    86  				err = temp
    87  			} else {
    88  				returnValue = interfac
    89  			}
    90  		}
    91  	case 2:
    92  		returnValue = callResults[0].Interface()
    93  		if temp, ok := callResults[1].Interface().(error); ok {
    94  			err = temp
    95  		}
    96  	}
    97  
    98  	return returnValue, err
    99  }