go.ketch.com/lib/goja@v0.0.1/object_goreflect.go (about)

     1  package goja
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"reflect"
     7  	"strings"
     8  
     9  	"go.ketch.com/lib/goja/parser"
    10  	"go.ketch.com/lib/goja/unistring"
    11  )
    12  
    13  // JsonEncodable allows custom JSON encoding by JSON.stringify()
    14  // Note that if the returned value itself also implements JsonEncodable, it won't have any effect.
    15  type JsonEncodable interface {
    16  	JsonEncodable() interface{}
    17  }
    18  
    19  // FieldNameMapper provides custom mapping between Go and JavaScript property names.
    20  type FieldNameMapper interface {
    21  	// FieldName returns a JavaScript name for the given struct field in the given type.
    22  	// If this method returns "" the field becomes hidden.
    23  	FieldName(t reflect.Type, f reflect.StructField) string
    24  
    25  	// MethodName returns a JavaScript name for the given method in the given type.
    26  	// If this method returns "" the method becomes hidden.
    27  	MethodName(t reflect.Type, m reflect.Method) string
    28  }
    29  
    30  type tagFieldNameMapper struct {
    31  	tagName      string
    32  	uncapMethods bool
    33  }
    34  
    35  func (tfm tagFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
    36  	tag := f.Tag.Get(tfm.tagName)
    37  	if idx := strings.IndexByte(tag, ','); idx != -1 {
    38  		tag = tag[:idx]
    39  	}
    40  	if parser.IsIdentifier(tag) {
    41  		return tag
    42  	}
    43  	return ""
    44  }
    45  
    46  func uncapitalize(s string) string {
    47  	return strings.ToLower(s[0:1]) + s[1:]
    48  }
    49  
    50  func (tfm tagFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
    51  	if tfm.uncapMethods {
    52  		return uncapitalize(m.Name)
    53  	}
    54  	return m.Name
    55  }
    56  
    57  type uncapFieldNameMapper struct {
    58  }
    59  
    60  func (u uncapFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
    61  	return uncapitalize(f.Name)
    62  }
    63  
    64  func (u uncapFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
    65  	return uncapitalize(m.Name)
    66  }
    67  
    68  type reflectFieldInfo struct {
    69  	Index     []int
    70  	Anonymous bool
    71  }
    72  
    73  type reflectFieldsInfo struct {
    74  	Fields map[string]reflectFieldInfo
    75  	Names  []string
    76  }
    77  
    78  type reflectMethodsInfo struct {
    79  	Methods map[string]int
    80  	Names   []string
    81  }
    82  
    83  type reflectValueWrapper interface {
    84  	esValue() Value
    85  	reflectValue() reflect.Value
    86  	setReflectValue(reflect.Value)
    87  }
    88  
    89  func isContainer(k reflect.Kind) bool {
    90  	switch k {
    91  	case reflect.Struct, reflect.Slice, reflect.Array:
    92  		return true
    93  	}
    94  	return false
    95  }
    96  
    97  func copyReflectValueWrapper(w reflectValueWrapper) {
    98  	v := w.reflectValue()
    99  	c := reflect.New(v.Type()).Elem()
   100  	c.Set(v)
   101  	w.setReflectValue(c)
   102  }
   103  
   104  type objectGoReflect struct {
   105  	baseObject
   106  	origValue, fieldsValue reflect.Value
   107  
   108  	fieldsInfo  *reflectFieldsInfo
   109  	methodsInfo *reflectMethodsInfo
   110  
   111  	methodsValue reflect.Value
   112  
   113  	valueCache map[string]reflectValueWrapper
   114  
   115  	toString, valueOf func() Value
   116  
   117  	toJson func() interface{}
   118  }
   119  
   120  func (o *objectGoReflect) init() {
   121  	o.baseObject.init()
   122  	switch o.fieldsValue.Kind() {
   123  	case reflect.Bool:
   124  		o.class = classBoolean
   125  		o.prototype = o.val.runtime.global.BooleanPrototype
   126  		o.toString = o._toStringBool
   127  		o.valueOf = o._valueOfBool
   128  	case reflect.String:
   129  		o.class = classString
   130  		o.prototype = o.val.runtime.global.StringPrototype
   131  		o.toString = o._toStringString
   132  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   133  		o.class = classNumber
   134  		o.prototype = o.val.runtime.global.NumberPrototype
   135  		o.valueOf = o._valueOfInt
   136  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   137  		o.class = classNumber
   138  		o.prototype = o.val.runtime.global.NumberPrototype
   139  		o.valueOf = o._valueOfUint
   140  	case reflect.Float32, reflect.Float64:
   141  		o.class = classNumber
   142  		o.prototype = o.val.runtime.global.NumberPrototype
   143  		o.valueOf = o._valueOfFloat
   144  	default:
   145  		o.class = classObject
   146  		o.prototype = o.val.runtime.global.ObjectPrototype
   147  	}
   148  
   149  	if o.fieldsValue.Kind() == reflect.Struct {
   150  		o.fieldsInfo = o.val.runtime.fieldsInfo(o.fieldsValue.Type())
   151  	}
   152  
   153  	var methodsType reflect.Type
   154  	// Always use pointer type for non-interface values to be able to access both methods defined on
   155  	// the literal type and on the pointer.
   156  	if o.fieldsValue.Kind() != reflect.Interface {
   157  		methodsType = reflect.PtrTo(o.fieldsValue.Type())
   158  	} else {
   159  		methodsType = o.fieldsValue.Type()
   160  	}
   161  
   162  	o.methodsInfo = o.val.runtime.methodsInfo(methodsType)
   163  
   164  	// Container values and values that have at least one method defined on the pointer type
   165  	// need to be addressable.
   166  	if !o.origValue.CanAddr() && (isContainer(o.origValue.Kind()) || len(o.methodsInfo.Names) > 0) {
   167  		value := reflect.New(o.origValue.Type()).Elem()
   168  		value.Set(o.origValue)
   169  		o.origValue = value
   170  		if value.Kind() != reflect.Ptr {
   171  			o.fieldsValue = value
   172  		}
   173  	}
   174  
   175  	o.extensible = true
   176  
   177  	switch o.origValue.Interface().(type) {
   178  	case fmt.Stringer:
   179  		o.toString = o._toStringStringer
   180  	case error:
   181  		o.toString = o._toStringError
   182  	}
   183  
   184  	if o.toString != nil || o.valueOf != nil {
   185  		o.baseObject._putProp("toString", o.val.runtime.newNativeFunc(o.toStringFunc, nil, "toString", nil, 0), true, false, true)
   186  		o.baseObject._putProp("valueOf", o.val.runtime.newNativeFunc(o.valueOfFunc, nil, "valueOf", nil, 0), true, false, true)
   187  	}
   188  
   189  	if len(o.methodsInfo.Names) > 0 && o.fieldsValue.Kind() != reflect.Interface {
   190  		o.methodsValue = o.fieldsValue.Addr()
   191  	} else {
   192  		o.methodsValue = o.fieldsValue
   193  	}
   194  
   195  	if j, ok := o.origValue.Interface().(JsonEncodable); ok {
   196  		o.toJson = j.JsonEncodable
   197  	}
   198  }
   199  
   200  func (o *objectGoReflect) toStringFunc(FunctionCall) Value {
   201  	return o.toPrimitiveString()
   202  }
   203  
   204  func (o *objectGoReflect) valueOfFunc(FunctionCall) Value {
   205  	return o.toPrimitiveNumber()
   206  }
   207  
   208  func (o *objectGoReflect) getStr(name unistring.String, receiver Value) Value {
   209  	if v := o._get(name.String()); v != nil {
   210  		return v
   211  	}
   212  	return o.baseObject.getStr(name, receiver)
   213  }
   214  
   215  func (o *objectGoReflect) _getField(jsName string) reflect.Value {
   216  	if o.fieldsInfo != nil {
   217  		if info, exists := o.fieldsInfo.Fields[jsName]; exists {
   218  			return o.fieldsValue.FieldByIndex(info.Index)
   219  		}
   220  	}
   221  
   222  	return reflect.Value{}
   223  }
   224  
   225  func (o *objectGoReflect) _getMethod(jsName string) reflect.Value {
   226  	if o.methodsInfo != nil {
   227  		if idx, exists := o.methodsInfo.Methods[jsName]; exists {
   228  			return o.methodsValue.Method(idx)
   229  		}
   230  	}
   231  
   232  	return reflect.Value{}
   233  }
   234  
   235  func (o *objectGoReflect) elemToValue(ev reflect.Value) (Value, reflectValueWrapper) {
   236  	if isContainer(ev.Kind()) {
   237  		if ev.Type() == reflectTypeArray {
   238  			a := o.val.runtime.newObjectGoSlice(ev.Addr().Interface().(*[]interface{}))
   239  			return a.val, a
   240  		}
   241  		ret := o.val.runtime.reflectValueToValue(ev)
   242  		if obj, ok := ret.(*Object); ok {
   243  			if w, ok := obj.self.(reflectValueWrapper); ok {
   244  				return ret, w
   245  			}
   246  		}
   247  		panic("reflectValueToValue() returned a value which is not a reflectValueWrapper")
   248  	}
   249  
   250  	for ev.Kind() == reflect.Interface {
   251  		ev = ev.Elem()
   252  	}
   253  
   254  	if ev.Kind() == reflect.Invalid {
   255  		return _null, nil
   256  	}
   257  
   258  	return o.val.runtime.ToValue(ev.Interface()), nil
   259  }
   260  
   261  func (o *objectGoReflect) _getFieldValue(name string) Value {
   262  	if v := o.valueCache[name]; v != nil {
   263  		return v.esValue()
   264  	}
   265  	if v := o._getField(name); v.IsValid() {
   266  		res, w := o.elemToValue(v)
   267  		if w != nil {
   268  			if o.valueCache == nil {
   269  				o.valueCache = make(map[string]reflectValueWrapper)
   270  			}
   271  			o.valueCache[name] = w
   272  		}
   273  		return res
   274  	}
   275  	return nil
   276  }
   277  
   278  func (o *objectGoReflect) _get(name string) Value {
   279  	if o.fieldsValue.Kind() == reflect.Struct {
   280  		if ret := o._getFieldValue(name); ret != nil {
   281  			return ret
   282  		}
   283  	}
   284  
   285  	if v := o._getMethod(name); v.IsValid() {
   286  		return o.val.runtime.reflectValueToValue(v)
   287  	}
   288  
   289  	return nil
   290  }
   291  
   292  func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
   293  	n := name.String()
   294  	if o.fieldsValue.Kind() == reflect.Struct {
   295  		if v := o._getFieldValue(n); v != nil {
   296  			return &valueProperty{
   297  				value:      v,
   298  				writable:   true,
   299  				enumerable: true,
   300  			}
   301  		}
   302  	}
   303  
   304  	if v := o._getMethod(n); v.IsValid() {
   305  		return &valueProperty{
   306  			value:      o.val.runtime.reflectValueToValue(v),
   307  			enumerable: true,
   308  		}
   309  	}
   310  
   311  	return nil
   312  }
   313  
   314  func (o *objectGoReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
   315  	has, ok := o._put(name.String(), val, throw)
   316  	if !has {
   317  		if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
   318  			o.val.runtime.typeErrorResult(throw, "Cannot assign to property %s of a host object", name)
   319  			return false
   320  		} else {
   321  			return res
   322  		}
   323  	}
   324  	return ok
   325  }
   326  
   327  func (o *objectGoReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
   328  	return o._setForeignStr(name, trueValIfPresent(o._has(name.String())), val, receiver, throw)
   329  }
   330  
   331  func (o *objectGoReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
   332  	return o._setForeignIdx(idx, nil, val, receiver, throw)
   333  }
   334  
   335  func (o *objectGoReflect) _put(name string, val Value, throw bool) (has, ok bool) {
   336  	if o.fieldsValue.Kind() == reflect.Struct {
   337  		if v := o._getField(name); v.IsValid() {
   338  			cached := o.valueCache[name]
   339  			if cached != nil {
   340  				copyReflectValueWrapper(cached)
   341  			}
   342  
   343  			err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
   344  			if err != nil {
   345  				if cached != nil {
   346  					cached.setReflectValue(v)
   347  				}
   348  				o.val.runtime.typeErrorResult(throw, "Go struct conversion error: %v", err)
   349  				return true, false
   350  			}
   351  			if cached != nil {
   352  				delete(o.valueCache, name)
   353  			}
   354  			return true, true
   355  		}
   356  	}
   357  	return false, false
   358  }
   359  
   360  func (o *objectGoReflect) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
   361  	if _, ok := o._put(name.String(), value, false); ok {
   362  		return value
   363  	}
   364  	return o.baseObject._putProp(name, value, writable, enumerable, configurable)
   365  }
   366  
   367  func (r *Runtime) checkHostObjectPropertyDescr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
   368  	if descr.Getter != nil || descr.Setter != nil {
   369  		r.typeErrorResult(throw, "Host objects do not support accessor properties")
   370  		return false
   371  	}
   372  	if descr.Writable == FLAG_FALSE {
   373  		r.typeErrorResult(throw, "Host object field %s cannot be made read-only", name)
   374  		return false
   375  	}
   376  	if descr.Configurable == FLAG_TRUE {
   377  		r.typeErrorResult(throw, "Host object field %s cannot be made configurable", name)
   378  		return false
   379  	}
   380  	return true
   381  }
   382  
   383  func (o *objectGoReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
   384  	if o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
   385  		n := name.String()
   386  		if has, ok := o._put(n, descr.Value, throw); !has {
   387  			o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a host object", n)
   388  			return false
   389  		} else {
   390  			return ok
   391  		}
   392  	}
   393  	return false
   394  }
   395  
   396  func (o *objectGoReflect) _has(name string) bool {
   397  	if o.fieldsValue.Kind() == reflect.Struct {
   398  		if v := o._getField(name); v.IsValid() {
   399  			return true
   400  		}
   401  	}
   402  	if v := o._getMethod(name); v.IsValid() {
   403  		return true
   404  	}
   405  	return false
   406  }
   407  
   408  func (o *objectGoReflect) hasOwnPropertyStr(name unistring.String) bool {
   409  	return o._has(name.String())
   410  }
   411  
   412  func (o *objectGoReflect) _valueOfInt() Value {
   413  	return intToValue(o.fieldsValue.Int())
   414  }
   415  
   416  func (o *objectGoReflect) _valueOfUint() Value {
   417  	return intToValue(int64(o.fieldsValue.Uint()))
   418  }
   419  
   420  func (o *objectGoReflect) _valueOfBool() Value {
   421  	if o.fieldsValue.Bool() {
   422  		return valueTrue
   423  	} else {
   424  		return valueFalse
   425  	}
   426  }
   427  
   428  func (o *objectGoReflect) _valueOfFloat() Value {
   429  	return floatToValue(o.fieldsValue.Float())
   430  }
   431  
   432  func (o *objectGoReflect) _toStringStringer() Value {
   433  	return newStringValue(o.origValue.Interface().(fmt.Stringer).String())
   434  }
   435  
   436  func (o *objectGoReflect) _toStringString() Value {
   437  	return newStringValue(o.fieldsValue.String())
   438  }
   439  
   440  func (o *objectGoReflect) _toStringBool() Value {
   441  	if o.fieldsValue.Bool() {
   442  		return stringTrue
   443  	} else {
   444  		return stringFalse
   445  	}
   446  }
   447  
   448  func (o *objectGoReflect) _toStringError() Value {
   449  	return newStringValue(o.origValue.Interface().(error).Error())
   450  }
   451  
   452  func (o *objectGoReflect) toPrimitiveNumber() Value {
   453  	if o.valueOf != nil {
   454  		return o.valueOf()
   455  	}
   456  	if o.toString != nil {
   457  		return o.toString()
   458  	}
   459  	return o.baseObject.toPrimitiveNumber()
   460  }
   461  
   462  func (o *objectGoReflect) toPrimitiveString() Value {
   463  	if o.toString != nil {
   464  		return o.toString()
   465  	}
   466  	if o.valueOf != nil {
   467  		return o.valueOf().toString()
   468  	}
   469  	return o.baseObject.toPrimitiveString()
   470  }
   471  
   472  func (o *objectGoReflect) toPrimitive() Value {
   473  	if o.valueOf != nil {
   474  		return o.valueOf()
   475  	}
   476  	if o.toString != nil {
   477  		return o.toString()
   478  	}
   479  
   480  	return o.baseObject.toPrimitive()
   481  }
   482  
   483  func (o *objectGoReflect) deleteStr(name unistring.String, throw bool) bool {
   484  	n := name.String()
   485  	if o._has(n) {
   486  		o.val.runtime.typeErrorResult(throw, "Cannot delete property %s from a Go type", n)
   487  		return false
   488  	}
   489  	return o.baseObject.deleteStr(name, throw)
   490  }
   491  
   492  type goreflectPropIter struct {
   493  	o   *objectGoReflect
   494  	idx int
   495  }
   496  
   497  func (i *goreflectPropIter) nextField() (propIterItem, iterNextFunc) {
   498  	names := i.o.fieldsInfo.Names
   499  	if i.idx < len(names) {
   500  		name := names[i.idx]
   501  		i.idx++
   502  		return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextField
   503  	}
   504  
   505  	i.idx = 0
   506  	return i.nextMethod()
   507  }
   508  
   509  func (i *goreflectPropIter) nextMethod() (propIterItem, iterNextFunc) {
   510  	names := i.o.methodsInfo.Names
   511  	if i.idx < len(names) {
   512  		name := names[i.idx]
   513  		i.idx++
   514  		return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextMethod
   515  	}
   516  
   517  	return propIterItem{}, nil
   518  }
   519  
   520  func (o *objectGoReflect) iterateStringKeys() iterNextFunc {
   521  	r := &goreflectPropIter{
   522  		o: o,
   523  	}
   524  	if o.fieldsInfo != nil {
   525  		return r.nextField
   526  	}
   527  
   528  	return r.nextMethod
   529  }
   530  
   531  func (o *objectGoReflect) stringKeys(_ bool, accum []Value) []Value {
   532  	// all own keys are enumerable
   533  	if o.fieldsInfo != nil {
   534  		for _, name := range o.fieldsInfo.Names {
   535  			accum = append(accum, newStringValue(name))
   536  		}
   537  	}
   538  
   539  	for _, name := range o.methodsInfo.Names {
   540  		accum = append(accum, newStringValue(name))
   541  	}
   542  
   543  	return accum
   544  }
   545  
   546  func (o *objectGoReflect) export(*objectExportCtx) interface{} {
   547  	return o.origValue.Interface()
   548  }
   549  
   550  func (o *objectGoReflect) exportType() reflect.Type {
   551  	return o.origValue.Type()
   552  }
   553  
   554  func (o *objectGoReflect) equal(other objectImpl) bool {
   555  	if other, ok := other.(*objectGoReflect); ok {
   556  		k1, k2 := o.fieldsValue.Kind(), other.fieldsValue.Kind()
   557  		if k1 == k2 {
   558  			if isContainer(k1) {
   559  				return o.fieldsValue == other.fieldsValue
   560  			}
   561  			return o.fieldsValue.Interface() == other.fieldsValue.Interface()
   562  		}
   563  	}
   564  	return false
   565  }
   566  
   567  func (o *objectGoReflect) reflectValue() reflect.Value {
   568  	return o.fieldsValue
   569  }
   570  
   571  func (o *objectGoReflect) setReflectValue(v reflect.Value) {
   572  	o.fieldsValue = v
   573  	o.origValue = v
   574  	o.methodsValue = v.Addr()
   575  }
   576  
   577  func (o *objectGoReflect) esValue() Value {
   578  	return o.val
   579  }
   580  
   581  func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectFieldsInfo) {
   582  	n := t.NumField()
   583  	for i := 0; i < n; i++ {
   584  		field := t.Field(i)
   585  		name := field.Name
   586  		if !ast.IsExported(name) {
   587  			continue
   588  		}
   589  		if r.fieldNameMapper != nil {
   590  			name = r.fieldNameMapper.FieldName(t, field)
   591  		}
   592  
   593  		if name != "" {
   594  			if inf, exists := info.Fields[name]; !exists {
   595  				info.Names = append(info.Names, name)
   596  			} else {
   597  				if len(inf.Index) <= len(index) {
   598  					continue
   599  				}
   600  			}
   601  		}
   602  
   603  		if name != "" || field.Anonymous {
   604  			idx := make([]int, len(index)+1)
   605  			copy(idx, index)
   606  			idx[len(idx)-1] = i
   607  
   608  			if name != "" {
   609  				info.Fields[name] = reflectFieldInfo{
   610  					Index:     idx,
   611  					Anonymous: field.Anonymous,
   612  				}
   613  			}
   614  			if field.Anonymous {
   615  				typ := field.Type
   616  				for typ.Kind() == reflect.Ptr {
   617  					typ = typ.Elem()
   618  				}
   619  				if typ.Kind() == reflect.Struct {
   620  					r.buildFieldInfo(typ, idx, info)
   621  				}
   622  			}
   623  		}
   624  	}
   625  }
   626  
   627  var emptyMethodsInfo = reflectMethodsInfo{}
   628  
   629  func (r *Runtime) buildMethodsInfo(t reflect.Type) (info *reflectMethodsInfo) {
   630  	n := t.NumMethod()
   631  	if n == 0 {
   632  		return &emptyMethodsInfo
   633  	}
   634  	info = new(reflectMethodsInfo)
   635  	info.Methods = make(map[string]int, n)
   636  	info.Names = make([]string, 0, n)
   637  	for i := 0; i < n; i++ {
   638  		method := t.Method(i)
   639  		name := method.Name
   640  		if !ast.IsExported(name) {
   641  			continue
   642  		}
   643  		if r.fieldNameMapper != nil {
   644  			name = r.fieldNameMapper.MethodName(t, method)
   645  			if name == "" {
   646  				continue
   647  			}
   648  		}
   649  
   650  		if _, exists := info.Methods[name]; !exists {
   651  			info.Names = append(info.Names, name)
   652  		}
   653  
   654  		info.Methods[name] = i
   655  	}
   656  	return
   657  }
   658  
   659  func (r *Runtime) buildFieldsInfo(t reflect.Type) (info *reflectFieldsInfo) {
   660  	info = new(reflectFieldsInfo)
   661  	n := t.NumField()
   662  	info.Fields = make(map[string]reflectFieldInfo, n)
   663  	info.Names = make([]string, 0, n)
   664  	r.buildFieldInfo(t, nil, info)
   665  	return
   666  }
   667  
   668  func (r *Runtime) fieldsInfo(t reflect.Type) (info *reflectFieldsInfo) {
   669  	var exists bool
   670  	if info, exists = r.fieldsInfoCache[t]; !exists {
   671  		info = r.buildFieldsInfo(t)
   672  		if r.fieldsInfoCache == nil {
   673  			r.fieldsInfoCache = make(map[reflect.Type]*reflectFieldsInfo)
   674  		}
   675  		r.fieldsInfoCache[t] = info
   676  	}
   677  
   678  	return
   679  }
   680  
   681  func (r *Runtime) methodsInfo(t reflect.Type) (info *reflectMethodsInfo) {
   682  	var exists bool
   683  	if info, exists = r.methodsInfoCache[t]; !exists {
   684  		info = r.buildMethodsInfo(t)
   685  		if r.methodsInfoCache == nil {
   686  			r.methodsInfoCache = make(map[reflect.Type]*reflectMethodsInfo)
   687  		}
   688  		r.methodsInfoCache[t] = info
   689  	}
   690  
   691  	return
   692  }
   693  
   694  // SetFieldNameMapper sets a custom field name mapper for Go types. It can be called at any time, however
   695  // the mapping for any given value is fixed at the point of creation.
   696  // Setting this to nil restores the default behaviour which is all exported fields and methods are mapped to their
   697  // original unchanged names.
   698  func (r *Runtime) SetFieldNameMapper(mapper FieldNameMapper) {
   699  	r.fieldNameMapper = mapper
   700  	r.fieldsInfoCache = nil
   701  	r.methodsInfoCache = nil
   702  }
   703  
   704  // TagFieldNameMapper returns a FieldNameMapper that uses the given tagName for struct fields and optionally
   705  // uncapitalises (making the first letter lower case) method names.
   706  // The common tag value syntax is supported (name[,options]), however options are ignored.
   707  // Setting name to anything other than a valid ECMAScript identifier makes the field hidden.
   708  func TagFieldNameMapper(tagName string, uncapMethods bool) FieldNameMapper {
   709  	return tagFieldNameMapper{
   710  		tagName:      tagName,
   711  		uncapMethods: uncapMethods,
   712  	}
   713  }
   714  
   715  // UncapFieldNameMapper returns a FieldNameMapper that uncapitalises struct field and method names
   716  // making the first letter lower case.
   717  func UncapFieldNameMapper() FieldNameMapper {
   718  	return uncapFieldNameMapper{}
   719  }