github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/reflect.go (about) 1 package reflect 2 3 import ( 4 "reflect" 5 "sync" 6 "unsafe" 7 8 "github.com/hirochachacha/plua/object" 9 ) 10 11 // interface{} (Go) -> Value (Lua) 12 func ValueOf(x interface{}) object.Value { 13 switch x := x.(type) { 14 case nil: 15 return nil 16 case bool: 17 return object.Boolean(x) 18 case int: 19 return object.Integer(x) 20 case int8: 21 return object.Integer(x) 22 case int32: 23 return object.Integer(x) 24 case int64: 25 return object.Integer(x) 26 case float32: 27 return object.Number(x) 28 case float64: 29 return object.Number(x) 30 case string: 31 return object.String(x) 32 case unsafe.Pointer: 33 return object.LightUserdata{Pointer: x} 34 case object.Integer: 35 return x 36 case object.Number: 37 return x 38 case object.String: 39 return x 40 case object.Boolean: 41 return x 42 case object.LightUserdata: 43 return x 44 case object.GoFunction: 45 return x 46 case *object.Userdata: 47 return x 48 case object.Table: 49 return x 50 case object.Closure: 51 return x 52 case object.Thread: 53 return x 54 } 55 56 return valueOfReflect(reflect.ValueOf(x), true) 57 } 58 59 var ( 60 tGoBool = reflect.TypeOf(false) 61 tGoInt = reflect.TypeOf(int(0)) 62 tGoInt8 = reflect.TypeOf(int8(0)) 63 tGoInt16 = reflect.TypeOf(int16(0)) 64 tGoInt32 = reflect.TypeOf(int32(0)) 65 tGoInt64 = reflect.TypeOf(int64(0)) 66 tGoFloat32 = reflect.TypeOf(float32(0)) 67 tGoFloat64 = reflect.TypeOf(float64(0)) 68 tGoString = reflect.TypeOf("") 69 tGoPointer = reflect.TypeOf(unsafe.Pointer(nil)) 70 71 tValue = reflect.TypeOf((*object.Value)(nil)).Elem() 72 73 tBoolean = reflect.TypeOf(object.False) 74 tInteger = reflect.TypeOf(object.Integer(0)) 75 tNumber = reflect.TypeOf(object.Number(0)) 76 tString = reflect.TypeOf(object.String("")) 77 tLightUserdata = reflect.TypeOf(object.LightUserdata{}) 78 tGoFunction = reflect.TypeOf(object.GoFunction(nil)) 79 tUserdataPtr = reflect.TypeOf((*object.Userdata)(nil)) 80 81 tTable = reflect.TypeOf((*object.Table)(nil)).Elem() 82 tClosure = reflect.TypeOf((*object.Closure)(nil)).Elem() 83 tThread = reflect.TypeOf((*object.Thread)(nil)).Elem() 84 ) 85 86 var ( 87 boolMT object.Table 88 intMT object.Table 89 floatMT object.Table 90 stringMT object.Table 91 uintMT object.Table 92 complexMT object.Table 93 arrayMT object.Table 94 chanMT object.Table 95 funcMT object.Table 96 ifaceMT object.Table 97 mapMT object.Table 98 ptrMT object.Table 99 sliceMT object.Table 100 structMT object.Table 101 ) 102 103 var ( 104 boolOnce sync.Once 105 intOnce sync.Once 106 floatOnce sync.Once 107 stringOnce sync.Once 108 uintOnce sync.Once 109 complexOnce sync.Once 110 arrayOnce sync.Once 111 chanOnce sync.Once 112 funcOnce sync.Once 113 ifaceOnce sync.Once 114 mapOnce sync.Once 115 ptrOnce sync.Once 116 sliceOnce sync.Once 117 structOnce sync.Once 118 ) 119 120 // reflect.Value (Go) -> Value (Lua) 121 func valueOfReflect(rval reflect.Value, skipPrimitive bool) object.Value { 122 if !skipPrimitive { 123 typ := rval.Type() 124 if typ == tValue { 125 if rval.IsNil() { 126 return nil 127 } 128 129 rval = rval.Elem() 130 typ = rval.Type() 131 } 132 133 switch typ { 134 case tGoBool: 135 return object.Boolean(rval.Bool()) 136 case tGoInt, tGoInt8, tGoInt16, tGoInt32, tGoInt32: 137 return object.Integer(rval.Int()) 138 case tGoFloat32, tGoFloat64: 139 return object.Number(rval.Float()) 140 case tGoString: 141 return object.String(rval.String()) 142 case tGoPointer: 143 return object.LightUserdata{Pointer: unsafe.Pointer(rval.Pointer())} 144 case tBoolean: 145 return rval.Interface().(object.Boolean) 146 case tInteger: 147 return rval.Interface().(object.Integer) 148 case tNumber: 149 return rval.Interface().(object.Number) 150 case tString: 151 return rval.Interface().(object.String) 152 case tLightUserdata: 153 return rval.Interface().(object.LightUserdata) 154 case tGoFunction: 155 return rval.Interface().(object.GoFunction) 156 case tUserdataPtr: 157 return rval.Interface().(*object.Userdata) 158 default: 159 switch { 160 case typ.Implements(tTable): 161 return rval.Interface().(object.Table) 162 case typ.Implements(tClosure): 163 return rval.Interface().(object.Closure) 164 case typ.Implements(tThread): 165 return rval.Interface().(object.Thread) 166 } 167 } 168 } 169 170 ud := &object.Userdata{Value: rval} 171 172 switch kind := rval.Kind(); kind { 173 case reflect.Bool: 174 boolOnce.Do(buildBoolMT) 175 176 ud.Metatable = boolMT 177 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 178 intOnce.Do(buildIntMT) 179 180 ud.Metatable = intMT 181 case reflect.Float32, reflect.Float64: 182 floatOnce.Do(buildFloatMT) 183 184 ud.Metatable = floatMT 185 case reflect.String: 186 stringOnce.Do(buildStringMT) 187 188 ud.Metatable = stringMT 189 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 190 uintOnce.Do(buildUintMT) 191 192 ud.Metatable = uintMT 193 case reflect.Complex64, reflect.Complex128: 194 complexOnce.Do(buildComplexMT) 195 196 ud.Metatable = complexMT 197 case reflect.Array: 198 arrayOnce.Do(buildArrayMT) 199 200 ud.Metatable = arrayMT 201 case reflect.Chan: 202 if rval.IsNil() { 203 return nil 204 } 205 206 chanOnce.Do(buildChanMT) 207 208 ud.Metatable = chanMT 209 case reflect.Func: 210 if rval.IsNil() { 211 return nil 212 } 213 214 funcOnce.Do(buildFuncMT) 215 216 ud.Metatable = funcMT 217 case reflect.Interface: 218 if rval.IsNil() { 219 return nil 220 } 221 222 ifaceOnce.Do(buildIfaceMT) 223 224 ud.Metatable = ifaceMT 225 case reflect.Map: 226 if rval.IsNil() { 227 return nil 228 } 229 230 mapOnce.Do(buildMapMT) 231 232 ud.Metatable = mapMT 233 case reflect.Ptr: 234 if rval.IsNil() { 235 return nil 236 } 237 238 ptrOnce.Do(buildPtrMT) 239 240 ud.Metatable = ptrMT 241 case reflect.Slice: 242 if rval.IsNil() { 243 return nil 244 } 245 246 sliceOnce.Do(buildSliceMT) 247 248 ud.Metatable = sliceMT 249 case reflect.Struct: 250 structOnce.Do(buildStructMT) 251 252 ud.Metatable = structMT 253 case reflect.UnsafePointer: 254 return object.LightUserdata{Pointer: unsafe.Pointer(rval.Pointer())} 255 case reflect.Invalid: 256 return nil 257 default: 258 panic("unreachable") 259 } 260 261 return ud 262 } 263 264 // Value (Lua) -> reflect.Value (Go) 265 func toReflectValue(typ reflect.Type, val object.Value) reflect.Value { 266 switch val := val.(type) { 267 case nil: 268 if typ == tValue { 269 return reflect.Zero(typ) 270 } 271 272 switch typ.Kind() { 273 case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice: 274 return reflect.Zero(typ) 275 } 276 case object.Boolean: 277 if typ == tValue { 278 return reflect.ValueOf(val) 279 } 280 281 if typ.Kind() == reflect.Bool { 282 return reflect.ValueOf(val).Convert(typ) 283 } 284 case object.Integer: 285 if typ == tValue { 286 return reflect.ValueOf(val) 287 } 288 289 switch typ.Kind() { 290 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 291 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 292 reflect.Float32, reflect.Float64: 293 return reflect.ValueOf(val).Convert(typ) 294 case reflect.String: 295 return reflect.ValueOf(integerToString(val)).Convert(typ) 296 } 297 case object.Number: 298 if typ == tValue { 299 return reflect.ValueOf(val) 300 } 301 302 switch typ.Kind() { 303 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 304 if ival, ok := numberToInteger(val); ok { 305 return reflect.ValueOf(ival).Convert(typ) 306 } 307 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 308 if u, ok := numberToGoUint(val); ok { 309 return reflect.ValueOf(u).Convert(typ) 310 } 311 case reflect.Float32, reflect.Float64: 312 return reflect.ValueOf(val).Convert(typ) 313 case reflect.String: 314 return reflect.ValueOf(numberToString(val)).Convert(typ) 315 } 316 case object.String: 317 if typ == tValue { 318 return reflect.ValueOf(val) 319 } 320 321 switch typ.Kind() { 322 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 323 if ival, ok := stringToInteger(val); ok { 324 return reflect.ValueOf(ival).Convert(typ) 325 } 326 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 327 if u, ok := stringToGoUint(val); ok { 328 return reflect.ValueOf(u).Convert(typ) 329 } 330 case reflect.Float32, reflect.Float64: 331 if nval, ok := stringToNumber(val); ok { 332 return reflect.ValueOf(nval).Convert(typ) 333 } 334 case reflect.String: 335 return reflect.ValueOf(val).Convert(typ) 336 } 337 case object.LightUserdata: 338 if typ == tValue { 339 return reflect.ValueOf(val) 340 } 341 342 if typ.Kind() == reflect.UnsafePointer { 343 return reflect.ValueOf(val.Pointer).Convert(typ) 344 } 345 case object.GoFunction: 346 if typ == tValue { 347 return reflect.ValueOf(val) 348 } 349 350 rval := reflect.ValueOf(val) 351 rtyp := rval.Type() 352 353 if rtyp == typ { 354 return rval 355 } 356 case *object.Userdata: 357 if typ == tValue { 358 return reflect.ValueOf(val) 359 } 360 361 if rval, ok := val.Value.(reflect.Value); ok { 362 rtyp := rval.Type() 363 364 if rtyp == typ { 365 return rval 366 } 367 } else { 368 rval := reflect.ValueOf(val.Value) 369 rtyp := rval.Type() 370 371 if rtyp == typ { 372 return rval 373 } 374 } 375 case object.Table: 376 if typ == tValue { 377 return reflect.ValueOf(val) 378 } 379 380 rval := reflect.ValueOf(val) 381 rtyp := rval.Type() 382 383 if rtyp == typ { 384 return rval 385 } 386 case object.Closure: 387 if typ == tValue { 388 return reflect.ValueOf(val) 389 } 390 391 rval := reflect.ValueOf(val) 392 rtyp := rval.Type() 393 394 if rtyp == typ { 395 return rval 396 } 397 case object.Thread: 398 if typ == tValue { 399 return reflect.ValueOf(val) 400 } 401 402 rval := reflect.ValueOf(val) 403 rtyp := rval.Type() 404 405 if rtyp == typ { 406 return rval 407 } 408 default: 409 panic("unreachable") 410 } 411 412 return reflect.ValueOf(nil) 413 }