Skip to main content

just_engine/runner/ds/
object_property.rs

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}