github.com/goplus/reflectx@v1.2.2/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/gopherjs/gopherjs/js" 14 ) 15 16 // icall stat 17 func IcallStat() (capacity int, allocate int, aviable int) { 18 return 0, 0, 0 19 } 20 21 func (ctx *Context) Reset() { 22 ctx.nAllocateError = 0 23 ctx.embedLookupCache = make(map[reflect.Type]reflect.Type) 24 ctx.structLookupCache = make(map[string][]reflect.Type) 25 ctx.interfceLookupCache = make(map[string]reflect.Type) 26 } 27 28 func resetAll() { 29 typMethodMap = make(map[reflect.Type]bool) 30 } 31 32 func (ctx *Context) IcallAlloc() int { 33 return 0 34 } 35 36 func isMethod(typ reflect.Type) bool { 37 return typMethodMap[typ] 38 } 39 40 type MethodProvider interface { 41 Remove(index []int) // remove method info 42 Clear() // clear all methods 43 } 44 45 func MethodByIndex(typ reflect.Type, index int) reflect.Method { 46 m := MethodX(typ, index) 47 if isMethod(typ) { 48 m.Func = reflect.MakeFunc(m.Type, func(args []reflect.Value) []reflect.Value { 49 recv := args[0].MethodByName(m.Name) 50 if m.Type.IsVariadic() { 51 return recv.CallSlice(args[1:]) 52 } else { 53 return recv.Call(args[1:]) 54 } 55 }) 56 } 57 return m 58 } 59 60 func MethodByName(typ reflect.Type, name string) (m reflect.Method, ok bool) { 61 m, ok = MethodByNameX(typ, name) 62 if !ok { 63 return 64 } 65 if isMethod(typ) { 66 m.Func = reflect.MakeFunc(m.Type, func(args []reflect.Value) []reflect.Value { 67 recv := args[0].MethodByName(name) 68 if m.Type.IsVariadic() { 69 return recv.CallSlice(args[1:]) 70 } else { 71 return recv.Call(args[1:]) 72 } 73 }) 74 } 75 return 76 } 77 78 var ( 79 typMethodMap = make(map[reflect.Type]bool) 80 ) 81 82 func newMethodSet(styp reflect.Type, maxmfunc, maxpfunc int) reflect.Type { 83 rt, _ := newType(styp.PkgPath(), styp.Name(), styp, maxmfunc, 0) 84 setTypeName(rt, styp.PkgPath(), styp.Name()) 85 typ := toType(rt) 86 jstyp := jsType(rt) 87 jstyp.Set("methodSetCache", nil) 88 ptyp := reflect.PtrTo(typ) 89 prt := totype(ptyp) 90 resetUncommonType(prt, maxpfunc, 0) 91 pjstyp := jsType(prt) 92 pjstyp.Set("methodSetCache", nil) 93 return typ 94 } 95 96 func resizeMethod(typ reflect.Type, mcount int, xcount int) error { 97 rt := totype(typ) 98 ut := toUncommonType(rt) 99 if ut == nil { 100 return fmt.Errorf("not found uncommonType of %v", typ) 101 } 102 if uint16(mcount) > ut.mcount { 103 return fmt.Errorf("too many methods of %v", typ) 104 } 105 ut.xcount = uint16(xcount) 106 return nil 107 } 108 109 func (ctx *Context) setMethodSet(typ reflect.Type, methods []Method) error { 110 sort.Slice(methods, func(i, j int) bool { 111 n := strings.Compare(methods[i].Name, methods[j].Name) 112 if n == 0 && methods[i].Type == methods[j].Type { 113 panic(fmt.Sprintf("method redeclared: %v", methods[j].Name)) 114 } 115 return n < 0 116 }) 117 118 var mcount, pcount int 119 var xcount, pxcount int 120 pcount = len(methods) 121 for _, m := range methods { 122 isexport := methodIsExported(m.Name) 123 if isexport { 124 pxcount++ 125 } 126 if !m.Pointer { 127 if isexport { 128 xcount++ 129 } 130 mcount++ 131 } 132 } 133 134 ptyp := reflect.PtrTo(typ) 135 if err := resizeMethod(typ, mcount, xcount); err != nil { 136 return err 137 } 138 if err := resizeMethod(ptyp, pcount, pxcount); err != nil { 139 return err 140 } 141 rt := totype(typ) 142 prt := totype(ptyp) 143 144 ums := toUncommonType(rt)._methods 145 146 jstyp := jsType(rt) 147 jstyp.Set("methodSetCache", nil) 148 jsms := jstyp.Get("methods") 149 jsproto := jstyp.Get("prototype") 150 jsmscache := js.Global.Get("Array").New() 151 152 pums := toUncommonType(prt)._methods 153 pjstyp := jsType(prt) 154 pjstyp.Set("methodSetCache", nil) 155 pjsms := pjstyp.Get("methods") 156 pjsproto := pjstyp.Get("prototype") 157 pjsmscache := js.Global.Get("Array").New() 158 159 index := -1 160 pindex := -1 161 for i, m := range methods { 162 in, out, ntyp, _, _ := parserMethodType(m.Type, nil) 163 var ftyp reflect.Type 164 if m.Pointer { 165 ftyp = reflect.FuncOf(append([]reflect.Type{ptyp}, in...), out, m.Type.IsVariadic()) 166 pindex++ 167 } else { 168 ftyp = reflect.FuncOf(append([]reflect.Type{typ}, in...), out, m.Type.IsVariadic()) 169 index++ 170 } 171 fn := js.Global.Get("Object").New() 172 fn.Set("pkg", "") 173 fn.Set("name", js.InternalObject(m.Name)) 174 fn.Set("prop", js.InternalObject(m.Name)) 175 fn.Set("typ", jsType(totype(ntyp))) 176 if m.Pointer { 177 pjsms.SetIndex(pindex, fn) 178 } else { 179 jsms.SetIndex(index, fn) 180 jsmscache.SetIndex(index, fn) 181 } 182 pjsmscache.SetIndex(i, fn) 183 184 isexport := methodIsExported(m.Name) 185 nm := newNameEx(m.Name, "", isexport, !isexport) 186 if !isexport { 187 fn.Set("pkg", m.PkgPath) 188 nm.setPkgPath(m.PkgPath) 189 } 190 mname := resolveReflectName(nm) 191 mtyp := resolveReflectType(totype(ntyp)) 192 pums[i].name = mname 193 pums[i].mtyp = mtyp 194 if !m.Pointer { 195 ums[index].name = mname 196 ums[index].mtyp = mtyp 197 } 198 dfn := reflect.MakeFunc(ftyp, m.Func) 199 tfn := tovalue(&dfn) 200 nargs := ftyp.NumIn() 201 if m.Pointer { 202 pjsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 203 iargs := make([]interface{}, nargs, nargs) 204 iargs[0] = this 205 for i, arg := range args { 206 iargs[i+1] = arg 207 } 208 return js.InternalObject(tfn.ptr).Invoke(iargs...) 209 })) 210 } else { 211 pjsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 212 iargs := make([]interface{}, nargs, nargs) 213 iargs[0] = *(**js.Object)(unsafe.Pointer(this)) 214 for i, arg := range args { 215 iargs[i+1] = arg 216 } 217 return js.InternalObject(tfn.ptr).Invoke(iargs...) 218 })) 219 } 220 jsproto.Set(m.Name, js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 221 iargs := make([]interface{}, nargs, nargs) 222 iargs[0] = this.Get("$val") 223 for i, arg := range args { 224 iargs[i+1] = arg 225 } 226 return js.InternalObject(tfn.ptr).Invoke(iargs...) 227 })) 228 } 229 jstyp.Set("methodSetCache", jsmscache) 230 pjstyp.Set("methodSetCache", pjsmscache) 231 232 typMethodMap[typ] = true 233 return nil 234 }