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

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