github.com/goplusjs/reflectx@v0.5.4/methodof_js.go (about) 1 //go:build js && !wasm 2 // +build js,!wasm 3 4 package reflectx 5 6 import ( 7 "fmt" 8 "reflect" 9 "sort" 10 "strings" 11 "unsafe" 12 13 "github.com/goplusjs/gopherjs/js" 14 ) 15 16 func New(typ reflect.Type) reflect.Value { 17 return reflect.New(typ) 18 } 19 20 func Interface(v reflect.Value) interface{} { 21 return v.Interface() 22 } 23 24 func isMethod(typ reflect.Type) bool { 25 return typMethodMap[typ] 26 } 27 28 func MethodByIndex(typ reflect.Type, index int) reflect.Method { 29 m := MethodX(typ, index) 30 if isMethod(typ) { 31 m.Func = reflect.MakeFunc(m.Type, func(args []reflect.Value) []reflect.Value { 32 recv := args[0].MethodByName(m.Name) 33 if m.Type.IsVariadic() { 34 return recv.CallSlice(args[1:]) 35 } else { 36 return recv.Call(args[1:]) 37 } 38 }) 39 } 40 return m 41 } 42 43 func MethodByName(typ reflect.Type, name string) (m reflect.Method, ok bool) { 44 m, ok = MethodByNameX(typ, name) 45 if !ok { 46 return 47 } 48 if isMethod(typ) { 49 m.Func = reflect.MakeFunc(m.Type, func(args []reflect.Value) []reflect.Value { 50 recv := args[0].MethodByName(name) 51 if m.Type.IsVariadic() { 52 return recv.CallSlice(args[1:]) 53 } else { 54 return recv.Call(args[1:]) 55 } 56 }) 57 } 58 return 59 } 60 61 var ( 62 typMethodMap = make(map[reflect.Type]bool) 63 ) 64 65 func resetTypeList() { 66 typMethodMap = make(map[reflect.Type]bool) 67 } 68 69 func newMethodSet(styp reflect.Type, maxmfunc, maxpfunc int) reflect.Type { 70 rt, _ := newType(styp.PkgPath(), styp.Name(), styp, maxmfunc, 0) 71 setTypeName(rt, styp.PkgPath(), styp.Name()) 72 typ := toType(rt) 73 jstyp := jsType(rt) 74 jstyp.Set("methodSetCache", nil) 75 ptyp := reflect.PtrTo(typ) 76 prt := totype(ptyp) 77 resetUncommonType(prt, maxpfunc, 0) 78 pjstyp := jsType(prt) 79 pjstyp.Set("methodSetCache", nil) 80 if nt, ok := ntypeMap[styp]; ok { 81 ntypeMap[typ] = &Named{Name: nt.Name, PkgPath: nt.PkgPath, Type: typ, From: nt.From, Kind: nt.Kind} 82 } 83 return typ 84 } 85 86 func resizeMethod(typ reflect.Type, count int) error { 87 rt := totype(typ) 88 ut := toUncommonType(rt) 89 if ut == nil { 90 return fmt.Errorf("not found uncommonType of %v", typ) 91 } 92 if uint16(count) > ut.mcount { 93 return fmt.Errorf("too many methods of %v", typ) 94 } 95 ut.xcount = uint16(count) 96 return nil 97 } 98 99 func setMethodSet(typ reflect.Type, methods []Method) error { 100 sort.Slice(methods, func(i, j int) bool { 101 n := strings.Compare(methods[i].Name, methods[j].Name) 102 if n == 0 && methods[i].Type == methods[j].Type { 103 panic(fmt.Sprintf("method redeclared: %v", methods[j].Name)) 104 } 105 return n < 0 106 }) 107 isPointer := func(m Method) bool { 108 return m.Pointer 109 } 110 var mcount, pcount int 111 pcount = len(methods) 112 for _, m := range methods { 113 if !isPointer(m) { 114 mcount++ 115 } 116 } 117 118 ptyp := reflect.PtrTo(typ) 119 if err := resizeMethod(typ, mcount); err != nil { 120 return err 121 } 122 if err := resizeMethod(ptyp, pcount); err != nil { 123 return err 124 } 125 rt := totype(typ) 126 prt := totype(ptyp) 127 128 ums := toUncommonType(rt)._methods 129 130 jstyp := jsType(rt) 131 jstyp.Set("methodSetCache", nil) 132 jsms := jstyp.Get("methods") 133 jsproto := jstyp.Get("prototype") 134 jsmscache := js.Global.Get("Array").New() 135 136 pums := toUncommonType(prt)._methods 137 pjstyp := jsType(prt) 138 pjstyp.Set("methodSetCache", nil) 139 pjsms := pjstyp.Get("methods") 140 pjsproto := pjstyp.Get("prototype") 141 pjsmscache := js.Global.Get("Array").New() 142 143 index := -1 144 pindex := -1 145 for i, m := range methods { 146 in, out, ntyp, _, _ := parserMethodType(m.Type, nil) 147 var ftyp reflect.Type 148 if m.Pointer { 149 ftyp = reflect.FuncOf(append([]reflect.Type{ptyp}, in...), out, m.Type.IsVariadic()) 150 pindex++ 151 } else { 152 ftyp = reflect.FuncOf(append([]reflect.Type{typ}, in...), out, m.Type.IsVariadic()) 153 index++ 154 } 155 fn := js.Global.Get("Object").New() 156 fn.Set("pkg", "") 157 fn.Set("name", js.InternalObject(m.Name)) 158 fn.Set("prop", js.InternalObject(m.Name)) 159 fn.Set("typ", jsType(totype(ntyp))) 160 if m.Pointer { 161 pjsms.SetIndex(pindex, fn) 162 } else { 163 jsms.SetIndex(index, fn) 164 jsmscache.SetIndex(index, fn) 165 } 166 pjsmscache.SetIndex(i, fn) 167 168 mname := resolveReflectName(newName(m.Name, "", true)) 169 mtyp := resolveReflectType(totype(ntyp)) 170 pums[i].name = mname 171 pums[i].mtyp = mtyp 172 if !m.Pointer { 173 ums[index].name = mname 174 ums[index].mtyp = mtyp 175 } 176 dfn := reflect.MakeFunc(ftyp, m.Func) 177 tfn := tovalue(&dfn) 178 nargs := ftyp.NumIn() 179 if m.Pointer { 180 pjsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 181 iargs := make([]interface{}, nargs, nargs) 182 iargs[0] = this 183 for i, arg := range args { 184 iargs[i+1] = arg 185 } 186 return js.InternalObject(tfn.ptr).Invoke(iargs...) 187 })) 188 } else { 189 pjsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 190 iargs := make([]interface{}, nargs, nargs) 191 iargs[0] = *(**js.Object)(unsafe.Pointer(this)) 192 for i, arg := range args { 193 iargs[i+1] = arg 194 } 195 return js.InternalObject(tfn.ptr).Invoke(iargs...) 196 })) 197 } 198 jsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 199 iargs := make([]interface{}, nargs, nargs) 200 iargs[0] = this.Get("$val") 201 for i, arg := range args { 202 iargs[i+1] = arg 203 } 204 return js.InternalObject(tfn.ptr).Invoke(iargs...) 205 })) 206 } 207 jstyp.Set("methodSetCache", jsmscache) 208 pjstyp.Set("methodSetCache", pjsmscache) 209 210 typMethodMap[typ] = true 211 return nil 212 } 213 214 // func methodOf(styp reflect.Type, methods []Method) reflect.Type { 215 // sort.Slice(methods, func(i, j int) bool { 216 // n := strings.Compare(methods[i].Name, methods[j].Name) 217 // if n == 0 && methods[i].Type == methods[j].Type { 218 // panic(fmt.Sprintf("method redeclared: %v", methods[j].Name)) 219 // } 220 // return n < 0 221 // }) 222 // isPointer := func(m Method) bool { 223 // return m.Pointer 224 // } 225 // var mcount, pcount int 226 // pcount = len(methods) 227 // for _, m := range methods { 228 // if !isPointer(m) { 229 // mcount++ 230 // } 231 // } 232 // orgtyp := styp 233 // rt, ums := newType(styp.PkgPath(), styp.Name(), styp, mcount, mcount) 234 // setTypeName(rt, styp.PkgPath(), styp.Name()) 235 236 // typ := toType(rt) 237 // jstyp := jsType(rt) 238 // jstyp.Set("methodSetCache", nil) 239 // jsms := jstyp.Get("methods") 240 // jsproto := jstyp.Get("prototype") 241 // jsmscache := js.Global.Get("Array").New() 242 243 // ptyp := reflect.PtrTo(typ) 244 // prt := totype(ptyp) 245 // pums := resetUncommonType(prt, pcount, pcount)._methods 246 // pjstyp := jsType(prt) 247 // pjstyp.Set("methodSetCache", nil) 248 // pjsms := pjstyp.Get("methods") 249 // pjsproto := pjstyp.Get("prototype") 250 // pjsmscache := js.Global.Get("Array").New() 251 252 // index := -1 253 // pindex := -1 254 // for i, m := range methods { 255 // in, out, ntyp, _, _ := toRealType(typ, orgtyp, m.Type) 256 // var ftyp reflect.Type 257 // if m.Pointer { 258 // ftyp = reflect.FuncOf(append([]reflect.Type{ptyp}, in...), out, m.Type.IsVariadic()) 259 // pindex++ 260 // } else { 261 // ftyp = reflect.FuncOf(append([]reflect.Type{typ}, in...), out, m.Type.IsVariadic()) 262 // index++ 263 // } 264 // fn := js.Global.Get("Object").New() 265 // fn.Set("pkg", "") 266 // fn.Set("name", js.InternalObject(m.Name)) 267 // fn.Set("prop", js.InternalObject(m.Name)) 268 // fn.Set("typ", jsType(totype(ntyp))) 269 // if m.Pointer { 270 // pjsms.SetIndex(pindex, fn) 271 // } else { 272 // jsms.SetIndex(index, fn) 273 // jsmscache.SetIndex(index, fn) 274 // } 275 // pjsmscache.SetIndex(i, fn) 276 277 // mname := resolveReflectName(newName(m.Name, "", true)) 278 // mtyp := resolveReflectType(totype(ntyp)) 279 // pums[i].name = mname 280 // pums[i].mtyp = mtyp 281 // if !m.Pointer { 282 // ums[index].name = mname 283 // ums[index].mtyp = mtyp 284 // } 285 // dfn := reflect.MakeFunc(ftyp, m.Func) 286 // tfn := tovalue(&dfn) 287 // nargs := ftyp.NumIn() 288 // if m.Pointer { 289 // pjsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 290 // iargs := make([]interface{}, nargs, nargs) 291 // iargs[0] = this 292 // for i, arg := range args { 293 // iargs[i+1] = arg 294 // } 295 // return js.InternalObject(tfn.ptr).Invoke(iargs...) 296 // })) 297 // } else { 298 // pjsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 299 // iargs := make([]interface{}, nargs, nargs) 300 // iargs[0] = *(**js.Object)(unsafe.Pointer(this)) 301 // for i, arg := range args { 302 // iargs[i+1] = arg 303 // } 304 // return js.InternalObject(tfn.ptr).Invoke(iargs...) 305 // })) 306 // } 307 // jsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 308 // iargs := make([]interface{}, nargs, nargs) 309 // iargs[0] = this.Get("$val") 310 // for i, arg := range args { 311 // iargs[i+1] = arg 312 // } 313 // return js.InternalObject(tfn.ptr).Invoke(iargs...) 314 // })) 315 // } 316 // jstyp.Set("methodSetCache", jsmscache) 317 // pjstyp.Set("methodSetCache", pjsmscache) 318 319 // typMethodMap[typ] = true 320 // return typ 321 // }