github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/lib/golib/govalue.go (about)

     1  package golib
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  
     8  	rt "github.com/arnodel/golua/runtime"
     9  )
    10  
    11  // Index tries to find the value of the go value at "index" v. This could mean
    12  // finding a method or a struct field or a map key or a slice index.
    13  func goIndex(t *rt.Thread, u *rt.UserData, key rt.Value) (rt.Value, error) {
    14  	gv := reflect.ValueOf(u.Value())
    15  	meta := u.Metatable()
    16  	field, ok := key.ToString()
    17  	if ok {
    18  		// First try a method
    19  		m := gv.MethodByName(string(field))
    20  		if m != (reflect.Value{}) {
    21  			return reflectToValue(m, meta), nil
    22  		}
    23  		if gv.CanAddr() {
    24  			// Is that even possible?
    25  			m = gv.Addr().MethodByName(string(field))
    26  			if m != (reflect.Value{}) {
    27  				return reflectToValue(m, meta), nil
    28  			}
    29  		}
    30  	}
    31  	switch gv.Kind() {
    32  	case reflect.Ptr:
    33  		gv = gv.Elem()
    34  		if gv.Kind() != reflect.Struct {
    35  			return rt.NilValue, errors.New("can only index a pointer when to a struct")
    36  		}
    37  		fallthrough
    38  	case reflect.Struct:
    39  		if !ok {
    40  			return rt.NilValue, errors.New("can only index a struct with a string")
    41  		}
    42  		f := gv.FieldByName(string(field))
    43  		if f != (reflect.Value{}) {
    44  			return reflectToValue(f, meta), nil
    45  		}
    46  		return rt.NilValue, fmt.Errorf("no field or method with name %q", field)
    47  	case reflect.Map:
    48  		goV, err := valueToType(t, key, gv.Type().Key())
    49  		if err != nil {
    50  			return rt.NilValue, fmt.Errorf("map index or incorrect type: %s", err)
    51  		}
    52  		return reflectToValue(gv.MapIndex(goV), meta), nil
    53  	case reflect.Slice:
    54  		i, ok := rt.ToInt(key)
    55  		if !ok {
    56  			return rt.NilValue, errors.New("slice index must be an integer")
    57  		}
    58  		if i < 0 || int(i) >= gv.Len() {
    59  			return rt.NilValue, errors.New("index out of slice bounds")
    60  		}
    61  		return reflectToValue(gv.Index(int(i)), meta), nil
    62  	}
    63  	return rt.NilValue, errors.New("unable to index")
    64  }
    65  
    66  // SetIndex tries to set the value of the index given by key to val.  This could
    67  // mean setting a struct field value or a map value or a slice item.
    68  func goSetIndex(t *rt.Thread, u *rt.UserData, key rt.Value, val rt.Value) error {
    69  	gv := reflect.ValueOf(u.Value())
    70  	switch gv.Kind() {
    71  	case reflect.Ptr:
    72  		gv = gv.Elem()
    73  		if gv.Kind() != reflect.Struct {
    74  			return errors.New("can only set pointer index when pointing to a struct")
    75  		}
    76  		fallthrough
    77  	case reflect.Struct:
    78  		field, ok := key.ToString()
    79  		if !ok {
    80  			return errors.New("can only set struct index for a string")
    81  		}
    82  		f := gv.FieldByName(string(field))
    83  		if f == (reflect.Value{}) {
    84  			return errors.New("struct does not have field: " + string(field))
    85  		}
    86  		if !f.CanSet() {
    87  			return errors.New("struct field cannot be set")
    88  		}
    89  		goVal, err := valueToType(t, val, f.Type())
    90  		if err != nil {
    91  			return fmt.Errorf("struct field of incompatible type: %s", err)
    92  		}
    93  		f.Set(goVal)
    94  		return nil
    95  	case reflect.Map:
    96  		goKey, err := valueToType(t, key, gv.Type().Key())
    97  		if err != nil {
    98  			return fmt.Errorf("map key of incompatible type: %s", err)
    99  		}
   100  		goVal, err := valueToType(t, val, gv.Type().Elem())
   101  		if err != nil {
   102  			return fmt.Errorf("map value set to incompatible type: %s", err)
   103  		}
   104  		gv.SetMapIndex(goKey, goVal)
   105  		return nil
   106  	case reflect.Slice:
   107  		i, ok := rt.ToInt(key)
   108  		if !ok {
   109  			return errors.New("slice index must be an integer")
   110  		}
   111  		if i < 0 || int(i) >= gv.Len() {
   112  			return errors.New("slice index out of bounds")
   113  		}
   114  		goVal, err := valueToType(t, val, gv.Type().Elem())
   115  		if err != nil {
   116  			return fmt.Errorf("slice item set to incompatible type: %s", err)
   117  		}
   118  		gv.Index(int(i)).Set(goVal)
   119  		return nil
   120  	}
   121  	return errors.New("unable to set index")
   122  }
   123  
   124  // Call tries to call the goValue if it is a function with the given arguments.
   125  func goCall(t *rt.Thread, u *rt.UserData, args []rt.Value) (res []rt.Value, err error) {
   126  	gv := reflect.ValueOf(u.Value())
   127  	meta := u.Metatable()
   128  	if gv.Kind() != reflect.Func {
   129  		return nil, fmt.Errorf("%s is not a function", gv.Kind())
   130  	}
   131  	f := gv.Type()
   132  	numParams := f.NumIn()
   133  	goArgs := make([]reflect.Value, numParams)
   134  	isVariadic := f.IsVariadic()
   135  	if isVariadic {
   136  		numParams--
   137  	}
   138  	var goArg reflect.Value
   139  	for i := 0; i < numParams; i++ {
   140  		if i < len(args) {
   141  			goArg, err = valueToType(t, args[i], f.In(i))
   142  			if err != nil {
   143  				return
   144  			}
   145  		} else {
   146  			goArg = reflect.Zero(f.In(i))
   147  		}
   148  		goArgs[i] = goArg
   149  	}
   150  	var goRes []reflect.Value
   151  	defer func() {
   152  		if r := recover(); r != nil {
   153  			err = fmt.Errorf("panic in go call: %v", r)
   154  		}
   155  	}()
   156  	if isVariadic {
   157  		etcSliceType := f.In(numParams)
   158  		etcType := etcSliceType.Elem()
   159  		etcLen := len(args) - numParams
   160  		etc := reflect.MakeSlice(etcSliceType, etcLen, etcLen)
   161  		for i := 0; i < etcLen; i++ {
   162  			goArg, err = valueToType(t, args[i+numParams], etcType)
   163  			if err != nil {
   164  				return nil, err
   165  			}
   166  			etc.Index(i).Set(goArg)
   167  		}
   168  		goArgs[numParams] = etc
   169  		goRes = gv.CallSlice(goArgs)
   170  	} else {
   171  		goRes = gv.Call(goArgs)
   172  	}
   173  	res = make([]rt.Value, len(goRes))
   174  	for i, x := range goRes {
   175  		res[i] = reflectToValue(x, meta)
   176  	}
   177  	return
   178  }
   179  
   180  func fillStruct(t *rt.Thread, s reflect.Value, v rt.Value) error {
   181  	var ok bool
   182  	tbl, ok := v.TryTable()
   183  	if !ok {
   184  		return errors.New("fillStruct: can only fill from a table")
   185  	}
   186  	var fk, fv rt.Value
   187  	for {
   188  		fk, fv, ok = tbl.Next(fk)
   189  		if !ok || fk.IsNil() {
   190  			break
   191  		}
   192  		name, ok := fk.TryString()
   193  		if !ok {
   194  			return errors.New("fillStruct: table fields must be strings")
   195  		}
   196  		field := s.FieldByName(string(name))
   197  		if field == (reflect.Value{}) {
   198  			return fmt.Errorf("fillStruct: field %q does not exist in struct", name)
   199  		}
   200  		goFv, err := valueToType(t, fv, field.Type())
   201  		if err != nil {
   202  			return err
   203  		}
   204  		field.Set(goFv)
   205  	}
   206  	return nil
   207  }
   208  
   209  func valueToFunc(t *rt.Thread, v rt.Value, tp reflect.Type) (reflect.Value, error) {
   210  	meta := getMeta(t.Runtime)
   211  	fn := func(in []reflect.Value) []reflect.Value {
   212  		args := make([]rt.Value, len(in))
   213  		for i, x := range in {
   214  			args[i] = reflectToValue(x, meta)
   215  		}
   216  		res := make([]rt.Value, tp.NumOut())
   217  		out := make([]reflect.Value, len(res))
   218  		term := rt.NewTermination(t.CurrentCont(), res, nil)
   219  		if err := rt.Call(t, v, args, term); err != nil {
   220  			panic(err)
   221  		}
   222  		var err error
   223  		for i, y := range res {
   224  			out[i], err = valueToType(t, y, tp.Out(i))
   225  			if err != nil {
   226  				panic(err)
   227  			}
   228  		}
   229  		return out
   230  	}
   231  	return reflect.MakeFunc(tp, fn), nil
   232  }
   233  
   234  var runtimeValueType = reflect.TypeOf(rt.Value{})
   235  
   236  func valueToType(t *rt.Thread, v rt.Value, tp reflect.Type) (reflect.Value, error) {
   237  	if tp == runtimeValueType {
   238  		return reflect.ValueOf(v), nil
   239  	}
   240  	// Fist we deal with UserData
   241  	if u, ok := v.TryUserData(); ok {
   242  		gv := reflect.ValueOf(u.Value())
   243  		if gv.Type().AssignableTo(tp) {
   244  			return gv, nil
   245  		}
   246  		if gv.Type().ConvertibleTo(tp) {
   247  			return gv.Convert(tp), nil
   248  		}
   249  		return reflect.Value{}, fmt.Errorf("%+v is not assignable or convertible to %s", u.Value(), tp.Name())
   250  	}
   251  	switch tp.Kind() {
   252  	case reflect.Ptr:
   253  		if tp.Elem().Kind() != reflect.Struct {
   254  			return reflect.Value{}, fmt.Errorf("lua value cannot be converted to %s", tp.Name())
   255  		}
   256  		p := reflect.New(tp.Elem())
   257  		if err := fillStruct(t, p.Elem(), v); err != nil {
   258  			return reflect.Value{}, err
   259  		}
   260  		return p, nil
   261  	case reflect.Struct:
   262  		s := reflect.Zero(tp)
   263  		if err := fillStruct(t, s, v); err != nil {
   264  			return reflect.Value{}, err
   265  		}
   266  		return s, nil
   267  	case reflect.Func:
   268  		return valueToFunc(t, v, tp)
   269  	case reflect.Int:
   270  		x, ok := rt.ToInt(v)
   271  		if ok {
   272  			return reflect.ValueOf(int(x)), nil
   273  		}
   274  	case reflect.Float64:
   275  		x, ok := rt.ToFloat(v)
   276  		if ok {
   277  			return reflect.ValueOf(float64(x)), nil
   278  		}
   279  	case reflect.String:
   280  		x, ok := v.ToString()
   281  		if ok {
   282  			return reflect.ValueOf(string(x)), nil
   283  		}
   284  	case reflect.Bool:
   285  		return reflect.ValueOf(rt.Truth(v)), nil
   286  	case reflect.Slice:
   287  		if tp.Elem().Kind() == reflect.Uint8 {
   288  			s, ok := v.TryString()
   289  			if ok {
   290  				return reflect.ValueOf([]byte(s)), nil
   291  			}
   292  		}
   293  	case reflect.Interface:
   294  		iface := v.Interface()
   295  		if reflect.TypeOf(iface).Implements(tp) {
   296  			return reflect.ValueOf(iface), nil
   297  		}
   298  	}
   299  	return reflect.Value{}, fmt.Errorf("%+v cannot be converted to %s", v, tp.Name())
   300  }
   301  
   302  func reflectToValue(v reflect.Value, meta *rt.Table) rt.Value {
   303  	if v == (reflect.Value{}) {
   304  		return rt.NilValue
   305  	}
   306  	switch v.Kind() {
   307  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   308  		return rt.IntValue(v.Int())
   309  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   310  		return rt.IntValue(int64(v.Uint()))
   311  	case reflect.Float32, reflect.Float64:
   312  		return rt.FloatValue(v.Float())
   313  	case reflect.String:
   314  		return rt.StringValue(v.String())
   315  	case reflect.Bool:
   316  		return rt.BoolValue(v.Bool())
   317  	case reflect.Slice:
   318  		if v.IsNil() {
   319  			return rt.NilValue
   320  		}
   321  		if v.Type().Elem().Kind() == reflect.Uint8 {
   322  			return rt.StringValue(string(v.Interface().([]byte)))
   323  		}
   324  	case reflect.Ptr:
   325  		if v.IsNil() {
   326  			return rt.NilValue
   327  		}
   328  		switch x := v.Interface().(type) {
   329  		case *rt.Table:
   330  			return rt.TableValue(x)
   331  		case *rt.UserData:
   332  			return rt.UserDataValue(x)
   333  		}
   334  	case reflect.Interface:
   335  		if v.IsNil() {
   336  			return rt.NilValue
   337  		}
   338  	}
   339  	return rt.UserDataValue(rt.NewUserData(v.Interface(), meta))
   340  }