1use crate::runner::ds::object::JsObjectType;
2use crate::runner::ds::operations::test_and_comparison::{same_object, same_value};
3use crate::runner::ds::symbol::SymbolData;
4use crate::runner::ds::value::JsValue;
5use std::fmt;
6use std::fmt::{Display, Formatter};
7use std::hash::{Hash, Hasher};
8
9pub enum PropertyKey {
10 Str(String),
11 Sym(SymbolData),
12}
13impl Display for PropertyKey {
14 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
15 match self {
16 PropertyKey::Str(s) => write!(f, "\"{}\"", s),
17 PropertyKey::Sym(s) => write!(f, "{}", s),
18 }
19 }
20}
21impl PartialEq for PropertyKey {
22 fn eq(&self, other: &Self) -> bool {
23 match self {
24 PropertyKey::Str(s) => {
25 if let PropertyKey::Str(s2) = other {
26 s == s2
27 } else {
28 false
29 }
30 }
31 PropertyKey::Sym(s) => {
32 if let PropertyKey::Sym(s2) = other {
33 s == s2
34 } else {
35 false
36 }
37 }
38 }
39 }
40}
41impl Hash for PropertyKey {
42 fn hash<H: Hasher>(&self, state: &mut H) {
43 match self {
44 PropertyKey::Str(s) => s.hash(state),
45 PropertyKey::Sym(s) => s.hash(state),
46 }
47 }
48}
49impl Eq for PropertyKey {}
50impl Clone for PropertyKey {
51 fn clone(&self) -> Self {
52 match self {
53 PropertyKey::Str(s) => PropertyKey::Str(s.clone()),
54 PropertyKey::Sym(s) => PropertyKey::Sym(s.clone()),
55 }
56 }
57}
58
59pub struct PropertyDescriptorSetter {
60 pub honour_value: bool,
61 pub honour_writable: bool,
62 pub honour_set: bool,
63 pub honour_get: bool,
64 pub honour_enumerable: bool,
65 pub honour_configurable: bool,
66 pub descriptor: PropertyDescriptor,
67}
68impl PropertyDescriptorSetter {
69 pub fn new_from_property_descriptor(desc: PropertyDescriptor) -> Self {
70 match desc {
71 PropertyDescriptor::Data { .. } => PropertyDescriptorSetter {
72 honour_value: true,
73 honour_writable: true,
74 honour_configurable: true,
75 honour_enumerable: true,
76 descriptor: desc,
77 honour_set: false,
78 honour_get: false,
79 },
80 PropertyDescriptor::Accessor { .. } => PropertyDescriptorSetter {
81 honour_set: true,
82 honour_get: true,
83 honour_configurable: true,
84 honour_enumerable: true,
85 descriptor: desc,
86 honour_value: false,
87 honour_writable: false,
88 },
89 }
90 }
91
92 pub fn is_empty(&self) -> bool {
93 !self.honour_configurable
94 && !self.honour_enumerable
95 && !self.honour_get
96 && !self.honour_set
97 && !self.honour_value
98 && !self.honour_writable
99 }
100
101 pub fn are_all_fields_set(&self) -> bool {
102 if self.descriptor.is_data_descriptor() {
103 self.honour_configurable
104 && self.honour_enumerable
105 && self.honour_value
106 && self.honour_writable
107 } else {
108 self.honour_configurable && self.honour_enumerable && self.honour_get && self.honour_set
109 }
110 }
111
112 pub fn is_generic_descriptor(&self) -> bool {
113 !self.honour_get && !self.honour_set && !self.honour_value && !self.honour_writable
114 }
115}
116impl Clone for PropertyDescriptorSetter {
117 fn clone(&self) -> Self {
118 PropertyDescriptorSetter {
119 honour_set: self.honour_set,
120 honour_get: self.honour_get,
121 honour_configurable: self.honour_configurable,
122 honour_enumerable: self.honour_enumerable,
123 honour_value: self.honour_value,
124 honour_writable: self.honour_writable,
125 descriptor: self.descriptor.clone(),
126 }
127 }
128}
129
130pub struct PropertyDescriptorData {
131 pub value: JsValue,
132 pub writable: bool,
133 pub enumerable: bool,
134 pub configurable: bool,
135}
136
137pub struct PropertyDescriptorAccessor {
138 pub set: Option<JsObjectType>,
139 pub get: Option<JsObjectType>,
140 pub enumerable: bool,
141 pub configurable: bool,
142}
143
144pub enum PropertyDescriptor {
145 Data(PropertyDescriptorData),
146 Accessor(PropertyDescriptorAccessor),
147}
148impl PropertyDescriptor {
149 pub fn new_from_property_descriptor_setter(desc_setter: PropertyDescriptorSetter) -> Self {
150 if desc_setter.is_generic_descriptor() {
151 if desc_setter.descriptor.is_data_descriptor() {
152 PropertyDescriptor::Data(PropertyDescriptorData {
153 value: JsValue::Undefined,
154 writable: false,
155 enumerable: if desc_setter.honour_enumerable {
156 desc_setter.descriptor.is_enumerable()
157 } else {
158 false
159 },
160 configurable: if desc_setter.honour_configurable {
161 desc_setter.descriptor.is_configurable()
162 } else {
163 false
164 },
165 })
166 } else {
167 PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
168 set: None,
169 get: None,
170 enumerable: if desc_setter.honour_enumerable {
171 desc_setter.descriptor.is_enumerable()
172 } else {
173 false
174 },
175 configurable: if desc_setter.honour_configurable {
176 desc_setter.descriptor.is_configurable()
177 } else {
178 false
179 },
180 })
181 }
182 } else if desc_setter.descriptor.is_data_descriptor() {
183 if let PropertyDescriptor::Data(PropertyDescriptorData {
184 writable, value, ..
185 }) = &desc_setter.descriptor
186 {
187 PropertyDescriptor::Data(PropertyDescriptorData {
188 value: if desc_setter.honour_value {
189 value.clone()
190 } else {
191 JsValue::Undefined
192 },
193 writable: if desc_setter.honour_writable {
194 *writable
195 } else {
196 false
197 },
198 enumerable: if desc_setter.honour_enumerable {
199 desc_setter.descriptor.is_enumerable()
200 } else {
201 false
202 },
203 configurable: if desc_setter.honour_configurable {
204 desc_setter.descriptor.is_configurable()
205 } else {
206 false
207 },
208 })
209 } else {
210 unreachable!()
211 }
212 } else if desc_setter.descriptor.is_accessor_descriptor() {
213 let is_enumerable = desc_setter.descriptor.is_enumerable();
214 let is_configurable = desc_setter.descriptor.is_configurable();
215 if let PropertyDescriptor::Accessor(PropertyDescriptorAccessor { set, get, .. }) =
216 desc_setter.descriptor
217 {
218 PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
219 set: if desc_setter.honour_set { set } else { None },
220 get: if desc_setter.honour_get { get } else { None },
221 enumerable: if desc_setter.honour_enumerable {
222 is_enumerable
223 } else {
224 false
225 },
226 configurable: if desc_setter.honour_configurable {
227 is_configurable
228 } else {
229 false
230 },
231 })
232 } else {
233 unreachable!()
234 }
235 } else {
236 panic!("Unexpected code path reached in PropertyDescriptor::new_from_property_descriptor_setter")
237 }
238 }
239
240 pub fn is_enumerable(&self) -> bool {
241 match self {
242 PropertyDescriptor::Data(PropertyDescriptorData { enumerable, .. }) => *enumerable,
243 PropertyDescriptor::Accessor(PropertyDescriptorAccessor { enumerable, .. }) => {
244 *enumerable
245 }
246 }
247 }
248
249 pub fn is_configurable(&self) -> bool {
250 match self {
251 PropertyDescriptor::Data(PropertyDescriptorData { configurable, .. }) => *configurable,
252 PropertyDescriptor::Accessor(PropertyDescriptorAccessor { configurable, .. }) => {
253 *configurable
254 }
255 }
256 }
257
258 pub fn is_data_descriptor(&self) -> bool {
259 match self {
260 PropertyDescriptor::Data { .. } => true,
261 PropertyDescriptor::Accessor { .. } => false,
262 }
263 }
264
265 pub fn is_accessor_descriptor(&self) -> bool {
266 match self {
267 PropertyDescriptor::Data { .. } => false,
268 PropertyDescriptor::Accessor { .. } => true,
269 }
270 }
271}
272impl PartialEq for PropertyDescriptor {
273 fn eq(&self, other: &Self) -> bool {
274 match self {
275 PropertyDescriptor::Data(PropertyDescriptorData {
276 value,
277 writable,
278 enumerable,
279 configurable,
280 }) => {
281 if let PropertyDescriptor::Data(PropertyDescriptorData {
282 value: other_value,
283 writable: other_writable,
284 enumerable: other_enumerable,
285 configurable: other_configurable,
286 }) = other
287 {
288 same_value(value, other_value)
289 && writable == other_writable
290 && enumerable == other_enumerable
291 && configurable == other_configurable
292 } else {
293 false
294 }
295 }
296 PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
297 set: setter,
298 get: _getter,
299 enumerable,
300 configurable,
301 }) => {
302 if let PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
303 set: other_setter,
304 get: _other_getter,
305 enumerable: other_enumerable,
306 configurable: other_configurable,
307 }) = other
308 {
309 if enumerable != other_enumerable {
310 false
311 } else if configurable != other_configurable {
312 false
313 } else if setter.is_none() && !other_setter.is_none() {
314 false
315 } else if !setter.is_none() && other_setter.is_none() {
316 false
317 } else if setter.is_none() && other_setter.is_none() {
318 true
319 } else {
320 if let Some(s) = setter {
321 if let Some(os) = other_setter {
322 return same_object(&(**s).borrow(), &(**os).borrow());
323 }
324 }
325 false
326 }
327 } else {
328 false
329 }
330 }
331 }
332 }
333}
334impl Clone for PropertyDescriptor {
335 fn clone(&self) -> Self {
336 match self {
337 PropertyDescriptor::Data(d) => PropertyDescriptor::Data(PropertyDescriptorData {
338 value: d.value.clone(),
339 writable: d.writable,
340 enumerable: d.enumerable,
341 configurable: d.configurable,
342 }),
343 PropertyDescriptor::Accessor(d) => {
344 PropertyDescriptor::Accessor(PropertyDescriptorAccessor {
345 set: match &d.set {
346 None => None,
347 Some(s) => Some(s.clone()),
348 },
349 get: match &d.get {
350 None => None,
351 Some(g) => Some(g.clone()),
352 },
353 enumerable: d.enumerable,
354 configurable: d.configurable,
355 })
356 }
357 }
358 }
359}