github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/object_gomap_reflect.go (about)

     1  package goja
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/nuvolaris/goja/unistring"
     7  )
     8  
     9  type objectGoMapReflect struct {
    10  	objectGoReflect
    11  
    12  	keyType, valueType reflect.Type
    13  }
    14  
    15  func (o *objectGoMapReflect) init() {
    16  	o.objectGoReflect.init()
    17  	o.keyType = o.fieldsValue.Type().Key()
    18  	o.valueType = o.fieldsValue.Type().Elem()
    19  }
    20  
    21  func (o *objectGoMapReflect) toKey(n Value, throw bool) reflect.Value {
    22  	key := reflect.New(o.keyType).Elem()
    23  	err := o.val.runtime.toReflectValue(n, key, &objectExportCtx{})
    24  	if err != nil {
    25  		o.val.runtime.typeErrorResult(throw, "map key conversion error: %v", err)
    26  		return reflect.Value{}
    27  	}
    28  	return key
    29  }
    30  
    31  func (o *objectGoMapReflect) strToKey(name string, throw bool) reflect.Value {
    32  	if o.keyType.Kind() == reflect.String {
    33  		return reflect.ValueOf(name).Convert(o.keyType)
    34  	}
    35  	return o.toKey(newStringValue(name), throw)
    36  }
    37  
    38  func (o *objectGoMapReflect) _getKey(key reflect.Value) Value {
    39  	if !key.IsValid() {
    40  		return nil
    41  	}
    42  	if v := o.fieldsValue.MapIndex(key); v.IsValid() {
    43  		rv := v
    44  		if rv.Kind() == reflect.Interface {
    45  			rv = rv.Elem()
    46  		}
    47  		return o.val.runtime.toValue(v.Interface(), rv)
    48  	}
    49  
    50  	return nil
    51  }
    52  
    53  func (o *objectGoMapReflect) _get(n Value) Value {
    54  	return o._getKey(o.toKey(n, false))
    55  }
    56  
    57  func (o *objectGoMapReflect) _getStr(name string) Value {
    58  	return o._getKey(o.strToKey(name, false))
    59  }
    60  
    61  func (o *objectGoMapReflect) getStr(name unistring.String, receiver Value) Value {
    62  	if v := o._getStr(name.String()); v != nil {
    63  		return v
    64  	}
    65  	return o.objectGoReflect.getStr(name, receiver)
    66  }
    67  
    68  func (o *objectGoMapReflect) getIdx(idx valueInt, receiver Value) Value {
    69  	if v := o._get(idx); v != nil {
    70  		return v
    71  	}
    72  	return o.objectGoReflect.getIdx(idx, receiver)
    73  }
    74  
    75  func (o *objectGoMapReflect) getOwnPropStr(name unistring.String) Value {
    76  	if v := o._getStr(name.String()); v != nil {
    77  		return &valueProperty{
    78  			value:      v,
    79  			writable:   true,
    80  			enumerable: true,
    81  		}
    82  	}
    83  	return o.objectGoReflect.getOwnPropStr(name)
    84  }
    85  
    86  func (o *objectGoMapReflect) getOwnPropIdx(idx valueInt) Value {
    87  	if v := o._get(idx); v != nil {
    88  		return &valueProperty{
    89  			value:      v,
    90  			writable:   true,
    91  			enumerable: true,
    92  		}
    93  	}
    94  	return o.objectGoReflect.getOwnPropStr(idx.string())
    95  }
    96  
    97  func (o *objectGoMapReflect) toValue(val Value, throw bool) (reflect.Value, bool) {
    98  	v := reflect.New(o.valueType).Elem()
    99  	err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
   100  	if err != nil {
   101  		o.val.runtime.typeErrorResult(throw, "map value conversion error: %v", err)
   102  		return reflect.Value{}, false
   103  	}
   104  
   105  	return v, true
   106  }
   107  
   108  func (o *objectGoMapReflect) _put(key reflect.Value, val Value, throw bool) bool {
   109  	if key.IsValid() {
   110  		if o.extensible || o.fieldsValue.MapIndex(key).IsValid() {
   111  			v, ok := o.toValue(val, throw)
   112  			if !ok {
   113  				return false
   114  			}
   115  			o.fieldsValue.SetMapIndex(key, v)
   116  		} else {
   117  			o.val.runtime.typeErrorResult(throw, "Cannot set property %s, object is not extensible", key.String())
   118  			return false
   119  		}
   120  		return true
   121  	}
   122  	return false
   123  }
   124  
   125  func (o *objectGoMapReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
   126  	n := name.String()
   127  	key := o.strToKey(n, false)
   128  	if !key.IsValid() || !o.fieldsValue.MapIndex(key).IsValid() {
   129  		if proto := o.prototype; proto != nil {
   130  			// we know it's foreign because prototype loops are not allowed
   131  			if res, ok := proto.self.setForeignStr(name, val, o.val, throw); ok {
   132  				return res
   133  			}
   134  		}
   135  		// new property
   136  		if !o.extensible {
   137  			o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", n)
   138  			return false
   139  		} else {
   140  			if throw && !key.IsValid() {
   141  				o.strToKey(n, true)
   142  				return false
   143  			}
   144  		}
   145  	}
   146  	o._put(key, val, throw)
   147  	return true
   148  }
   149  
   150  func (o *objectGoMapReflect) setOwnIdx(idx valueInt, val Value, throw bool) bool {
   151  	key := o.toKey(idx, false)
   152  	if !key.IsValid() || !o.fieldsValue.MapIndex(key).IsValid() {
   153  		if proto := o.prototype; proto != nil {
   154  			// we know it's foreign because prototype loops are not allowed
   155  			if res, ok := proto.self.setForeignIdx(idx, val, o.val, throw); ok {
   156  				return res
   157  			}
   158  		}
   159  		// new property
   160  		if !o.extensible {
   161  			o.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
   162  			return false
   163  		} else {
   164  			if throw && !key.IsValid() {
   165  				o.toKey(idx, true)
   166  				return false
   167  			}
   168  		}
   169  	}
   170  	o._put(key, val, throw)
   171  	return true
   172  }
   173  
   174  func (o *objectGoMapReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
   175  	return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw)
   176  }
   177  
   178  func (o *objectGoMapReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
   179  	return o._setForeignIdx(idx, trueValIfPresent(o.hasOwnPropertyIdx(idx)), val, receiver, throw)
   180  }
   181  
   182  func (o *objectGoMapReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
   183  	if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
   184  		return false
   185  	}
   186  
   187  	return o._put(o.strToKey(name.String(), throw), descr.Value, throw)
   188  }
   189  
   190  func (o *objectGoMapReflect) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
   191  	if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) {
   192  		return false
   193  	}
   194  
   195  	return o._put(o.toKey(idx, throw), descr.Value, throw)
   196  }
   197  
   198  func (o *objectGoMapReflect) hasOwnPropertyStr(name unistring.String) bool {
   199  	key := o.strToKey(name.String(), false)
   200  	if key.IsValid() && o.fieldsValue.MapIndex(key).IsValid() {
   201  		return true
   202  	}
   203  	return false
   204  }
   205  
   206  func (o *objectGoMapReflect) hasOwnPropertyIdx(idx valueInt) bool {
   207  	key := o.toKey(idx, false)
   208  	if key.IsValid() && o.fieldsValue.MapIndex(key).IsValid() {
   209  		return true
   210  	}
   211  	return false
   212  }
   213  
   214  func (o *objectGoMapReflect) deleteStr(name unistring.String, throw bool) bool {
   215  	key := o.strToKey(name.String(), throw)
   216  	if !key.IsValid() {
   217  		return false
   218  	}
   219  	o.fieldsValue.SetMapIndex(key, reflect.Value{})
   220  	return true
   221  }
   222  
   223  func (o *objectGoMapReflect) deleteIdx(idx valueInt, throw bool) bool {
   224  	key := o.toKey(idx, throw)
   225  	if !key.IsValid() {
   226  		return false
   227  	}
   228  	o.fieldsValue.SetMapIndex(key, reflect.Value{})
   229  	return true
   230  }
   231  
   232  type gomapReflectPropIter struct {
   233  	o    *objectGoMapReflect
   234  	keys []reflect.Value
   235  	idx  int
   236  }
   237  
   238  func (i *gomapReflectPropIter) next() (propIterItem, iterNextFunc) {
   239  	for i.idx < len(i.keys) {
   240  		key := i.keys[i.idx]
   241  		v := i.o.fieldsValue.MapIndex(key)
   242  		i.idx++
   243  		if v.IsValid() {
   244  			return propIterItem{name: newStringValue(key.String()), enumerable: _ENUM_TRUE}, i.next
   245  		}
   246  	}
   247  
   248  	return propIterItem{}, nil
   249  }
   250  
   251  func (o *objectGoMapReflect) iterateStringKeys() iterNextFunc {
   252  	return (&gomapReflectPropIter{
   253  		o:    o,
   254  		keys: o.fieldsValue.MapKeys(),
   255  	}).next
   256  }
   257  
   258  func (o *objectGoMapReflect) stringKeys(_ bool, accum []Value) []Value {
   259  	// all own keys are enumerable
   260  	for _, key := range o.fieldsValue.MapKeys() {
   261  		accum = append(accum, newStringValue(key.String()))
   262  	}
   263  
   264  	return accum
   265  }