1package goja
2
3import (
4	"reflect"
5
6	"github.com/dop251/goja/unistring"
7)
8
9type objectGoMapSimple struct {
10	baseObject
11	data map[string]interface{}
12}
13
14func (o *objectGoMapSimple) init() {
15	o.baseObject.init()
16	o.prototype = o.val.runtime.global.ObjectPrototype
17	o.class = classObject
18	o.extensible = true
19}
20
21func (o *objectGoMapSimple) _getStr(name string) Value {
22	v, exists := o.data[name]
23	if !exists {
24		return nil
25	}
26	return o.val.runtime.ToValue(v)
27}
28
29func (o *objectGoMapSimple) getStr(name unistring.String, receiver Value) Value {
30	if v := o._getStr(name.String()); v != nil {
31		return v
32	}
33	return o.baseObject.getStr(name, receiver)
34}
35
36func (o *objectGoMapSimple) getOwnPropStr(name unistring.String) Value {
37	if v := o._getStr(name.String()); v != nil {
38		return v
39	}
40	return nil
41}
42
43func (o *objectGoMapSimple) setOwnStr(name unistring.String, val Value, throw bool) bool {
44	n := name.String()
45	if _, exists := o.data[n]; exists {
46		o.data[n] = val.Export()
47		return true
48	}
49	if proto := o.prototype; proto != nil {
50		// we know it's foreign because prototype loops are not allowed
51		if res, ok := proto.self.setForeignStr(name, val, o.val, throw); ok {
52			return res
53		}
54	}
55	// new property
56	if !o.extensible {
57		o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", name)
58		return false
59	} else {
60		o.data[n] = val.Export()
61	}
62	return true
63}
64
65func trueValIfPresent(present bool) Value {
66	if present {
67		return valueTrue
68	}
69	return nil
70}
71
72func (o *objectGoMapSimple) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
73	return o._setForeignStr(name, trueValIfPresent(o._hasStr(name.String())), val, receiver, throw)
74}
75
76func (o *objectGoMapSimple) _hasStr(name string) bool {
77	_, exists := o.data[name]
78	return exists
79}
80
81func (o *objectGoMapSimple) hasOwnPropertyStr(name unistring.String) bool {
82	return o._hasStr(name.String())
83}
84
85func (o *objectGoMapSimple) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
86	if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
87		return false
88	}
89
90	n := name.String()
91	if o.extensible || o._hasStr(n) {
92		o.data[n] = descr.Value.Export()
93		return true
94	}
95
96	o.val.runtime.typeErrorResult(throw, "Cannot define property %s, object is not extensible", n)
97	return false
98}
99
100/*
101func (o *objectGoMapSimple) toPrimitiveNumber() Value {
102	return o.toPrimitiveString()
103}
104
105func (o *objectGoMapSimple) toPrimitiveString() Value {
106	return stringObjectObject
107}
108
109func (o *objectGoMapSimple) toPrimitive() Value {
110	return o.toPrimitiveString()
111}
112
113func (o *objectGoMapSimple) assertCallable() (call func(FunctionCall) Value, ok bool) {
114	return nil, false
115}
116*/
117
118func (o *objectGoMapSimple) deleteStr(name unistring.String, _ bool) bool {
119	delete(o.data, name.String())
120	return true
121}
122
123type gomapPropIter struct {
124	o         *objectGoMapSimple
125	propNames []string
126	idx       int
127}
128
129func (i *gomapPropIter) next() (propIterItem, iterNextFunc) {
130	for i.idx < len(i.propNames) {
131		name := i.propNames[i.idx]
132		i.idx++
133		if _, exists := i.o.data[name]; exists {
134			return propIterItem{name: unistring.NewFromString(name), enumerable: _ENUM_TRUE}, i.next
135		}
136	}
137
138	return propIterItem{}, nil
139}
140
141func (o *objectGoMapSimple) enumerateOwnKeys() iterNextFunc {
142	propNames := make([]string, len(o.data))
143	i := 0
144	for key := range o.data {
145		propNames[i] = key
146		i++
147	}
148
149	return (&gomapPropIter{
150		o:         o,
151		propNames: propNames,
152	}).next
153}
154
155func (o *objectGoMapSimple) ownKeys(_ bool, accum []Value) []Value {
156	// all own keys are enumerable
157	for key := range o.data {
158		accum = append(accum, newStringValue(key))
159	}
160	return accum
161}
162
163func (o *objectGoMapSimple) export(*objectExportCtx) interface{} {
164	return o.data
165}
166
167func (o *objectGoMapSimple) exportType() reflect.Type {
168	return reflectTypeMap
169}
170
171func (o *objectGoMapSimple) equal(other objectImpl) bool {
172	if other, ok := other.(*objectGoMapSimple); ok {
173		return o == other
174	}
175	return false
176}
177