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 }