boa/object/
mod.rs

1//! This module implements the Rust representation of a JavaScript object.
2
3use crate::{
4    builtins::{
5        array::array_iterator::ArrayIterator,
6        function::{Captures, Function, NativeFunction},
7        map::map_iterator::MapIterator,
8        map::ordered_map::OrderedMap,
9        regexp::regexp_string_iterator::RegExpStringIterator,
10        set::ordered_set::OrderedSet,
11        set::set_iterator::SetIterator,
12        string::string_iterator::StringIterator,
13        Date, RegExp,
14    },
15    context::StandardConstructor,
16    gc::{Finalize, Trace},
17    property::{Attribute, PropertyDescriptor, PropertyKey},
18    BoaProfiler, Context, JsBigInt, JsResult, JsString, JsSymbol, JsValue,
19};
20use std::{
21    any::Any,
22    fmt::{self, Debug, Display},
23    ops::{Deref, DerefMut},
24};
25
26#[cfg(test)]
27mod tests;
28
29mod gcobject;
30pub(crate) mod internal_methods;
31mod operations;
32mod property_map;
33
34use crate::builtins::object::for_in_iterator::ForInIterator;
35pub use gcobject::{JsObject, RecursionLimiter, Ref, RefMut};
36use internal_methods::InternalObjectMethods;
37pub use operations::IntegrityLevel;
38pub use property_map::*;
39
40use self::internal_methods::{
41    array::ARRAY_EXOTIC_INTERNAL_METHODS, string::STRING_EXOTIC_INTERNAL_METHODS,
42    ORDINARY_INTERNAL_METHODS,
43};
44
45/// Static `prototype`, usually set on constructors as a key to point to their respective prototype object.
46pub static PROTOTYPE: &str = "prototype";
47
48/// This trait allows Rust types to be passed around as objects.
49///
50/// This is automatically implemented, when a type implements `Debug`, `Any` and `Trace`.
51pub trait NativeObject: Debug + Any + Trace {
52    /// Convert the Rust type which implements `NativeObject` to a `&dyn Any`.
53    fn as_any(&self) -> &dyn Any;
54
55    /// Convert the Rust type which implements `NativeObject` to a `&mut dyn Any`.
56    fn as_mut_any(&mut self) -> &mut dyn Any;
57}
58
59impl<T: Any + Debug + Trace> NativeObject for T {
60    #[inline]
61    fn as_any(&self) -> &dyn Any {
62        self as &dyn Any
63    }
64
65    #[inline]
66    fn as_mut_any(&mut self) -> &mut dyn Any {
67        self as &mut dyn Any
68    }
69}
70
71/// The internal representation of an JavaScript object.
72#[derive(Debug, Trace, Finalize)]
73pub struct Object {
74    /// The type of the object.
75    pub data: ObjectData,
76    properties: PropertyMap,
77    /// Instance prototype `__proto__`.
78    prototype: JsValue,
79    /// Whether it can have new properties added to it.
80    extensible: bool,
81}
82
83/// Defines the kind of an object and its internal methods
84#[derive(Trace, Finalize)]
85pub struct ObjectData {
86    kind: ObjectKind,
87    internal_methods: &'static InternalObjectMethods,
88}
89
90/// Defines the different types of objects.
91#[derive(Debug, Trace, Finalize)]
92pub enum ObjectKind {
93    Array,
94    ArrayIterator(ArrayIterator),
95    Map(OrderedMap<JsValue>),
96    MapIterator(MapIterator),
97    RegExp(Box<RegExp>),
98    RegExpStringIterator(RegExpStringIterator),
99    BigInt(JsBigInt),
100    Boolean(bool),
101    ForInIterator(ForInIterator),
102    Function(Function),
103    Set(OrderedSet<JsValue>),
104    SetIterator(SetIterator),
105    String(JsString),
106    StringIterator(StringIterator),
107    Number(f64),
108    Symbol(JsSymbol),
109    Error,
110    Ordinary,
111    Date(Date),
112    Global,
113    NativeObject(Box<dyn NativeObject>),
114}
115
116impl ObjectData {
117    /// Create the `Array` object data and reference its exclusive internal methods
118    pub fn array() -> Self {
119        Self {
120            kind: ObjectKind::Array,
121            internal_methods: &ARRAY_EXOTIC_INTERNAL_METHODS,
122        }
123    }
124
125    /// Create the `ArrayIterator` object data
126    pub fn array_iterator(array_iterator: ArrayIterator) -> Self {
127        Self {
128            kind: ObjectKind::ArrayIterator(array_iterator),
129            internal_methods: &ORDINARY_INTERNAL_METHODS,
130        }
131    }
132
133    /// Create the `Map` object data
134    pub fn map(map: OrderedMap<JsValue>) -> Self {
135        Self {
136            kind: ObjectKind::Map(map),
137            internal_methods: &ORDINARY_INTERNAL_METHODS,
138        }
139    }
140
141    /// Create the `MapIterator` object data
142    pub fn map_iterator(map_iterator: MapIterator) -> Self {
143        Self {
144            kind: ObjectKind::MapIterator(map_iterator),
145            internal_methods: &ORDINARY_INTERNAL_METHODS,
146        }
147    }
148
149    /// Create the `RegExp` object data
150    pub fn reg_exp(reg_exp: Box<RegExp>) -> Self {
151        Self {
152            kind: ObjectKind::RegExp(reg_exp),
153            internal_methods: &ORDINARY_INTERNAL_METHODS,
154        }
155    }
156
157    /// Create the `RegExpStringIterator` object data
158    pub fn reg_exp_string_iterator(reg_exp_string_iterator: RegExpStringIterator) -> Self {
159        Self {
160            kind: ObjectKind::RegExpStringIterator(reg_exp_string_iterator),
161            internal_methods: &ORDINARY_INTERNAL_METHODS,
162        }
163    }
164
165    /// Create the `BigInt` object data
166    pub fn big_int(big_int: JsBigInt) -> Self {
167        Self {
168            kind: ObjectKind::BigInt(big_int),
169            internal_methods: &ORDINARY_INTERNAL_METHODS,
170        }
171    }
172
173    /// Create the `Boolean` object data
174    pub fn boolean(boolean: bool) -> Self {
175        Self {
176            kind: ObjectKind::Boolean(boolean),
177            internal_methods: &ORDINARY_INTERNAL_METHODS,
178        }
179    }
180
181    /// Create the `ForInIterator` object data
182    pub fn for_in_iterator(for_in_iterator: ForInIterator) -> Self {
183        Self {
184            kind: ObjectKind::ForInIterator(for_in_iterator),
185            internal_methods: &ORDINARY_INTERNAL_METHODS,
186        }
187    }
188
189    /// Create the `Function` object data
190    pub fn function(function: Function) -> Self {
191        Self {
192            kind: ObjectKind::Function(function),
193            internal_methods: &ORDINARY_INTERNAL_METHODS,
194        }
195    }
196
197    /// Create the `Set` object data
198    pub fn set(set: OrderedSet<JsValue>) -> Self {
199        Self {
200            kind: ObjectKind::Set(set),
201            internal_methods: &ORDINARY_INTERNAL_METHODS,
202        }
203    }
204
205    /// Create the `SetIterator` object data
206    pub fn set_iterator(set_iterator: SetIterator) -> Self {
207        Self {
208            kind: ObjectKind::SetIterator(set_iterator),
209            internal_methods: &ORDINARY_INTERNAL_METHODS,
210        }
211    }
212
213    /// Create the `String` object data and reference its exclusive internal methods
214    pub fn string(string: JsString) -> Self {
215        Self {
216            kind: ObjectKind::String(string),
217            internal_methods: &STRING_EXOTIC_INTERNAL_METHODS,
218        }
219    }
220
221    /// Create the `StringIterator` object data
222    pub fn string_iterator(string_iterator: StringIterator) -> Self {
223        Self {
224            kind: ObjectKind::StringIterator(string_iterator),
225            internal_methods: &ORDINARY_INTERNAL_METHODS,
226        }
227    }
228
229    /// Create the `Number` object data
230    pub fn number(number: f64) -> Self {
231        Self {
232            kind: ObjectKind::Number(number),
233            internal_methods: &ORDINARY_INTERNAL_METHODS,
234        }
235    }
236
237    /// Create the `Symbol` object data
238    pub fn symbol(symbol: JsSymbol) -> Self {
239        Self {
240            kind: ObjectKind::Symbol(symbol),
241            internal_methods: &ORDINARY_INTERNAL_METHODS,
242        }
243    }
244
245    /// Create the `Error` object data
246    pub fn error() -> Self {
247        Self {
248            kind: ObjectKind::Error,
249            internal_methods: &ORDINARY_INTERNAL_METHODS,
250        }
251    }
252
253    /// Create the `Ordinary` object data
254    pub fn ordinary() -> Self {
255        Self {
256            kind: ObjectKind::Ordinary,
257            internal_methods: &ORDINARY_INTERNAL_METHODS,
258        }
259    }
260
261    /// Create the `Date` object data
262    pub fn date(date: Date) -> Self {
263        Self {
264            kind: ObjectKind::Date(date),
265            internal_methods: &ORDINARY_INTERNAL_METHODS,
266        }
267    }
268
269    /// Create the `Global` object data
270    pub fn global() -> Self {
271        Self {
272            kind: ObjectKind::Global,
273            internal_methods: &ORDINARY_INTERNAL_METHODS,
274        }
275    }
276
277    /// Create the `NativeObject` object data
278    pub fn native_object(native_object: Box<dyn NativeObject>) -> Self {
279        Self {
280            kind: ObjectKind::NativeObject(native_object),
281            internal_methods: &ORDINARY_INTERNAL_METHODS,
282        }
283    }
284}
285
286impl Display for ObjectKind {
287    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288        write!(
289            f,
290            "{}",
291            match self {
292                Self::Array => "Array",
293                Self::ArrayIterator(_) => "ArrayIterator",
294                Self::ForInIterator(_) => "ForInIterator",
295                Self::Function(_) => "Function",
296                Self::RegExp(_) => "RegExp",
297                Self::RegExpStringIterator(_) => "RegExpStringIterator",
298                Self::Map(_) => "Map",
299                Self::MapIterator(_) => "MapIterator",
300                Self::Set(_) => "Set",
301                Self::SetIterator(_) => "SetIterator",
302                Self::String(_) => "String",
303                Self::StringIterator(_) => "StringIterator",
304                Self::Symbol(_) => "Symbol",
305                Self::Error => "Error",
306                Self::Ordinary => "Ordinary",
307                Self::Boolean(_) => "Boolean",
308                Self::Number(_) => "Number",
309                Self::BigInt(_) => "BigInt",
310                Self::Date(_) => "Date",
311                Self::Global => "Global",
312                Self::NativeObject(_) => "NativeObject",
313            }
314        )
315    }
316}
317
318impl Debug for ObjectData {
319    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320        f.debug_struct("ObjectData")
321            .field("kind", &self.kind)
322            .field("internal_methods", &"internal_methods")
323            .finish()
324    }
325}
326
327impl Default for Object {
328    /// Return a new ObjectData struct, with `kind` set to Ordinary
329    #[inline]
330    fn default() -> Self {
331        Self {
332            data: ObjectData::ordinary(),
333            properties: PropertyMap::default(),
334            prototype: JsValue::null(),
335            extensible: true,
336        }
337    }
338}
339
340impl Object {
341    #[inline]
342    pub fn new() -> Self {
343        Default::default()
344    }
345
346    /// Return a new ObjectData struct, with `kind` set to Ordinary
347    #[inline]
348    pub fn function(function: Function, prototype: JsValue) -> Self {
349        let _timer = BoaProfiler::global().start_event("Object::Function", "object");
350
351        Self {
352            data: ObjectData::function(function),
353            properties: PropertyMap::default(),
354            prototype,
355            extensible: true,
356        }
357    }
358
359    /// ObjectCreate is used to specify the runtime creation of new ordinary objects.
360    ///
361    /// More information:
362    ///  - [ECMAScript reference][spec]
363    ///
364    /// [spec]: https://tc39.es/ecma262/#sec-objectcreate
365    // TODO: proto should be a &Value here
366    #[inline]
367    pub fn create(proto: JsValue) -> Self {
368        let mut obj = Self::new();
369        obj.prototype = proto;
370        obj
371    }
372
373    /// Return a new Boolean object whose `[[BooleanData]]` internal slot is set to argument.
374    #[inline]
375    pub fn boolean(value: bool) -> Self {
376        Self {
377            data: ObjectData::boolean(value),
378            properties: PropertyMap::default(),
379            prototype: JsValue::null(),
380            extensible: true,
381        }
382    }
383
384    /// Return a new `Number` object whose `[[NumberData]]` internal slot is set to argument.
385    #[inline]
386    pub fn number(value: f64) -> Self {
387        Self {
388            data: ObjectData::number(value),
389            properties: PropertyMap::default(),
390            prototype: JsValue::null(),
391            extensible: true,
392        }
393    }
394
395    /// Return a new `String` object whose `[[StringData]]` internal slot is set to argument.
396    #[inline]
397    pub fn string<S>(value: S) -> Self
398    where
399        S: Into<JsString>,
400    {
401        Self {
402            data: ObjectData::string(value.into()),
403            properties: PropertyMap::default(),
404            prototype: JsValue::null(),
405            extensible: true,
406        }
407    }
408
409    /// Return a new `BigInt` object whose `[[BigIntData]]` internal slot is set to argument.
410    #[inline]
411    pub fn bigint(value: JsBigInt) -> Self {
412        Self {
413            data: ObjectData::big_int(value),
414            properties: PropertyMap::default(),
415            prototype: JsValue::null(),
416            extensible: true,
417        }
418    }
419
420    /// Create a new native object of type `T`.
421    #[inline]
422    pub fn native_object<T>(value: T) -> Self
423    where
424        T: NativeObject,
425    {
426        Self {
427            data: ObjectData::native_object(Box::new(value)),
428            properties: PropertyMap::default(),
429            prototype: JsValue::null(),
430            extensible: true,
431        }
432    }
433
434    #[inline]
435    pub fn kind(&self) -> &ObjectKind {
436        &self.data.kind
437    }
438
439    /// It determines if Object is a callable function with a `[[Call]]` internal method.
440    ///
441    /// More information:
442    /// - [EcmaScript reference][spec]
443    ///
444    /// [spec]: https://tc39.es/ecma262/#sec-iscallable
445    #[inline]
446    // todo: functions are not the only objects that are callable.
447    // todo: e.g. https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
448    pub fn is_callable(&self) -> bool {
449        matches!(
450            self.data,
451            ObjectData {
452                kind: ObjectKind::Function(_),
453                ..
454            }
455        )
456    }
457
458    /// It determines if Object is a function object with a `[[Construct]]` internal method.
459    ///
460    /// More information:
461    /// - [EcmaScript reference][spec]
462    ///
463    /// [spec]: https://tc39.es/ecma262/#sec-isconstructor
464    #[inline]
465    // todo: functions are not the only objects that are constructable.
466    // todo: e.g. https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-construct-argumentslist-newtarget
467    pub fn is_constructable(&self) -> bool {
468        matches!(self.data, ObjectData{kind: ObjectKind::Function(ref f), ..} if f.is_constructable())
469    }
470
471    /// Checks if it an `Array` object.
472    #[inline]
473    pub fn is_array(&self) -> bool {
474        matches!(
475            self.data,
476            ObjectData {
477                kind: ObjectKind::Array,
478                ..
479            }
480        )
481    }
482
483    #[inline]
484    pub fn as_array(&self) -> Option<()> {
485        match self.data {
486            ObjectData {
487                kind: ObjectKind::Array,
488                ..
489            } => Some(()),
490            _ => None,
491        }
492    }
493
494    /// Checks if it is an `ArrayIterator` object.
495    #[inline]
496    pub fn is_array_iterator(&self) -> bool {
497        matches!(
498            self.data,
499            ObjectData {
500                kind: ObjectKind::ArrayIterator(_),
501                ..
502            }
503        )
504    }
505
506    #[inline]
507    pub fn as_array_iterator(&self) -> Option<&ArrayIterator> {
508        match self.data {
509            ObjectData {
510                kind: ObjectKind::ArrayIterator(ref iter),
511                ..
512            } => Some(iter),
513            _ => None,
514        }
515    }
516
517    #[inline]
518    pub fn as_array_iterator_mut(&mut self) -> Option<&mut ArrayIterator> {
519        match &mut self.data {
520            ObjectData {
521                kind: ObjectKind::ArrayIterator(iter),
522                ..
523            } => Some(iter),
524            _ => None,
525        }
526    }
527
528    #[inline]
529    pub fn as_string_iterator_mut(&mut self) -> Option<&mut StringIterator> {
530        match &mut self.data {
531            ObjectData {
532                kind: ObjectKind::StringIterator(iter),
533                ..
534            } => Some(iter),
535            _ => None,
536        }
537    }
538
539    #[inline]
540    pub fn as_regexp_string_iterator_mut(&mut self) -> Option<&mut RegExpStringIterator> {
541        match &mut self.data {
542            ObjectData {
543                kind: ObjectKind::RegExpStringIterator(iter),
544                ..
545            } => Some(iter),
546            _ => None,
547        }
548    }
549
550    #[inline]
551    pub fn as_for_in_iterator(&self) -> Option<&ForInIterator> {
552        match &self.data {
553            ObjectData {
554                kind: ObjectKind::ForInIterator(iter),
555                ..
556            } => Some(iter),
557            _ => None,
558        }
559    }
560
561    #[inline]
562    pub fn as_for_in_iterator_mut(&mut self) -> Option<&mut ForInIterator> {
563        match &mut self.data {
564            ObjectData {
565                kind: ObjectKind::ForInIterator(iter),
566                ..
567            } => Some(iter),
568            _ => None,
569        }
570    }
571
572    /// Checks if it is a `Map` object.pub
573    #[inline]
574    pub fn is_map(&self) -> bool {
575        matches!(
576            self.data,
577            ObjectData {
578                kind: ObjectKind::Map(_),
579                ..
580            }
581        )
582    }
583
584    #[inline]
585    pub fn as_map_ref(&self) -> Option<&OrderedMap<JsValue>> {
586        match self.data {
587            ObjectData {
588                kind: ObjectKind::Map(ref map),
589                ..
590            } => Some(map),
591            _ => None,
592        }
593    }
594
595    #[inline]
596    pub fn as_map_mut(&mut self) -> Option<&mut OrderedMap<JsValue>> {
597        match &mut self.data {
598            ObjectData {
599                kind: ObjectKind::Map(map),
600                ..
601            } => Some(map),
602            _ => None,
603        }
604    }
605
606    #[inline]
607    pub fn is_map_iterator(&self) -> bool {
608        matches!(
609            self.data,
610            ObjectData {
611                kind: ObjectKind::MapIterator(_),
612                ..
613            }
614        )
615    }
616
617    #[inline]
618    pub fn as_map_iterator_ref(&self) -> Option<&MapIterator> {
619        match &self.data {
620            ObjectData {
621                kind: ObjectKind::MapIterator(iter),
622                ..
623            } => Some(iter),
624            _ => None,
625        }
626    }
627
628    #[inline]
629    pub fn as_map_iterator_mut(&mut self) -> Option<&mut MapIterator> {
630        match &mut self.data {
631            ObjectData {
632                kind: ObjectKind::MapIterator(iter),
633                ..
634            } => Some(iter),
635            _ => None,
636        }
637    }
638
639    #[inline]
640    pub fn is_set(&self) -> bool {
641        matches!(
642            self.data,
643            ObjectData {
644                kind: ObjectKind::Set(_),
645                ..
646            }
647        )
648    }
649
650    #[inline]
651    pub fn as_set_ref(&self) -> Option<&OrderedSet<JsValue>> {
652        match self.data {
653            ObjectData {
654                kind: ObjectKind::Set(ref set),
655                ..
656            } => Some(set),
657            _ => None,
658        }
659    }
660
661    #[inline]
662    pub fn as_set_mut(&mut self) -> Option<&mut OrderedSet<JsValue>> {
663        match &mut self.data {
664            ObjectData {
665                kind: ObjectKind::Set(set),
666                ..
667            } => Some(set),
668            _ => None,
669        }
670    }
671
672    #[inline]
673    pub fn as_set_iterator_mut(&mut self) -> Option<&mut SetIterator> {
674        match &mut self.data {
675            ObjectData {
676                kind: ObjectKind::SetIterator(iter),
677                ..
678            } => Some(iter),
679            _ => None,
680        }
681    }
682
683    /// Checks if it a `String` object.
684    #[inline]
685    pub fn is_string(&self) -> bool {
686        matches!(
687            self.data,
688            ObjectData {
689                kind: ObjectKind::String(_),
690                ..
691            }
692        )
693    }
694
695    #[inline]
696    pub fn as_string(&self) -> Option<JsString> {
697        match self.data {
698            ObjectData {
699                kind: ObjectKind::String(ref string),
700                ..
701            } => Some(string.clone()),
702            _ => None,
703        }
704    }
705
706    /// Checks if it a `Function` object.
707    #[inline]
708    pub fn is_function(&self) -> bool {
709        matches!(
710            self.data,
711            ObjectData {
712                kind: ObjectKind::Function(_),
713                ..
714            }
715        )
716    }
717
718    #[inline]
719    pub fn as_function(&self) -> Option<&Function> {
720        match self.data {
721            ObjectData {
722                kind: ObjectKind::Function(ref function),
723                ..
724            } => Some(function),
725            _ => None,
726        }
727    }
728
729    /// Checks if it a Symbol object.
730    #[inline]
731    pub fn is_symbol(&self) -> bool {
732        matches!(
733            self.data,
734            ObjectData {
735                kind: ObjectKind::Symbol(_),
736                ..
737            }
738        )
739    }
740
741    #[inline]
742    pub fn as_symbol(&self) -> Option<JsSymbol> {
743        match self.data {
744            ObjectData {
745                kind: ObjectKind::Symbol(ref symbol),
746                ..
747            } => Some(symbol.clone()),
748            _ => None,
749        }
750    }
751
752    /// Checks if it an Error object.
753    #[inline]
754    pub fn is_error(&self) -> bool {
755        matches!(
756            self.data,
757            ObjectData {
758                kind: ObjectKind::Error,
759                ..
760            }
761        )
762    }
763
764    #[inline]
765    pub fn as_error(&self) -> Option<()> {
766        match self.data {
767            ObjectData {
768                kind: ObjectKind::Error,
769                ..
770            } => Some(()),
771            _ => None,
772        }
773    }
774
775    /// Checks if it a Boolean object.
776    #[inline]
777    pub fn is_boolean(&self) -> bool {
778        matches!(
779            self.data,
780            ObjectData {
781                kind: ObjectKind::Boolean(_),
782                ..
783            }
784        )
785    }
786
787    #[inline]
788    pub fn as_boolean(&self) -> Option<bool> {
789        match self.data {
790            ObjectData {
791                kind: ObjectKind::Boolean(boolean),
792                ..
793            } => Some(boolean),
794            _ => None,
795        }
796    }
797
798    /// Checks if it a `Number` object.
799    #[inline]
800    pub fn is_number(&self) -> bool {
801        matches!(
802            self.data,
803            ObjectData {
804                kind: ObjectKind::Number(_),
805                ..
806            }
807        )
808    }
809
810    #[inline]
811    pub fn as_number(&self) -> Option<f64> {
812        match self.data {
813            ObjectData {
814                kind: ObjectKind::Number(number),
815                ..
816            } => Some(number),
817            _ => None,
818        }
819    }
820
821    /// Checks if it a `BigInt` object.
822    #[inline]
823    pub fn is_bigint(&self) -> bool {
824        matches!(
825            self.data,
826            ObjectData {
827                kind: ObjectKind::BigInt(_),
828                ..
829            }
830        )
831    }
832
833    #[inline]
834    pub fn as_bigint(&self) -> Option<&JsBigInt> {
835        match self.data {
836            ObjectData {
837                kind: ObjectKind::BigInt(ref bigint),
838                ..
839            } => Some(bigint),
840            _ => None,
841        }
842    }
843
844    #[inline]
845    pub fn is_date(&self) -> bool {
846        matches!(
847            self.data,
848            ObjectData {
849                kind: ObjectKind::Date(_),
850                ..
851            }
852        )
853    }
854
855    pub fn as_date(&self) -> Option<&Date> {
856        match self.data {
857            ObjectData {
858                kind: ObjectKind::Date(ref date),
859                ..
860            } => Some(date),
861            _ => None,
862        }
863    }
864
865    /// Checks if it a `RegExp` object.
866    #[inline]
867    pub fn is_regexp(&self) -> bool {
868        matches!(
869            self.data,
870            ObjectData {
871                kind: ObjectKind::RegExp(_),
872                ..
873            }
874        )
875    }
876
877    #[inline]
878    pub fn as_regexp(&self) -> Option<&RegExp> {
879        match self.data {
880            ObjectData {
881                kind: ObjectKind::RegExp(ref regexp),
882                ..
883            } => Some(regexp),
884            _ => None,
885        }
886    }
887
888    /// Checks if it an ordinary object.
889    #[inline]
890    pub fn is_ordinary(&self) -> bool {
891        matches!(
892            self.data,
893            ObjectData {
894                kind: ObjectKind::Ordinary,
895                ..
896            }
897        )
898    }
899
900    #[inline]
901    pub fn prototype_instance(&self) -> &JsValue {
902        &self.prototype
903    }
904
905    /// Sets the prototype instance of the object.
906    ///
907    /// [More information][spec]
908    ///
909    /// [spec]: https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods
910    #[inline]
911    #[track_caller]
912    pub fn set_prototype_instance(&mut self, prototype: JsValue) -> bool {
913        assert!(prototype.is_null() || prototype.is_object());
914        if self.extensible {
915            self.prototype = prototype;
916            true
917        } else {
918            // If target is non-extensible, [[SetPrototypeOf]] must return false
919            // unless V is the SameValue as the target's observed [[GetPrototypeOf]] value.
920            JsValue::same_value(&prototype, &self.prototype)
921        }
922    }
923
924    /// Similar to `Value::new_object`, but you can pass a prototype to create from, plus a kind
925    #[inline]
926    pub fn with_prototype(proto: JsValue, data: ObjectData) -> Object {
927        let mut object = Object::new();
928        object.data = data;
929        object.set_prototype_instance(proto);
930        object
931    }
932
933    /// Returns `true` if it holds an Rust type that implements `NativeObject`.
934    #[inline]
935    pub fn is_native_object(&self) -> bool {
936        matches!(
937            self.data,
938            ObjectData {
939                kind: ObjectKind::NativeObject(_),
940                ..
941            }
942        )
943    }
944
945    #[inline]
946    pub fn as_native_object(&self) -> Option<&dyn NativeObject> {
947        match self.data {
948            ObjectData {
949                kind: ObjectKind::NativeObject(ref object),
950                ..
951            } => Some(object.as_ref()),
952            _ => None,
953        }
954    }
955
956    /// Reeturn `true` if it is a native object and the native type is `T`.
957    #[inline]
958    pub fn is<T>(&self) -> bool
959    where
960        T: NativeObject,
961    {
962        match self.data {
963            ObjectData {
964                kind: ObjectKind::NativeObject(ref object),
965                ..
966            } => object.deref().as_any().is::<T>(),
967            _ => false,
968        }
969    }
970
971    /// Downcast a reference to the object,
972    /// if the object is type native object type `T`.
973    #[inline]
974    pub fn downcast_ref<T>(&self) -> Option<&T>
975    where
976        T: NativeObject,
977    {
978        match self.data {
979            ObjectData {
980                kind: ObjectKind::NativeObject(ref object),
981                ..
982            } => object.deref().as_any().downcast_ref::<T>(),
983            _ => None,
984        }
985    }
986
987    /// Downcast a mutable reference to the object,
988    /// if the object is type native object type `T`.
989    #[inline]
990    pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
991    where
992        T: NativeObject,
993    {
994        match self.data {
995            ObjectData {
996                kind: ObjectKind::NativeObject(ref mut object),
997                ..
998            } => object.deref_mut().as_mut_any().downcast_mut::<T>(),
999            _ => None,
1000        }
1001    }
1002
1003    #[inline]
1004    pub fn properties(&self) -> &PropertyMap {
1005        &self.properties
1006    }
1007
1008    /// Helper function for property insertion.
1009    #[inline]
1010    pub(crate) fn insert<K, P>(&mut self, key: K, property: P) -> Option<PropertyDescriptor>
1011    where
1012        K: Into<PropertyKey>,
1013        P: Into<PropertyDescriptor>,
1014    {
1015        self.properties.insert(key.into(), property.into())
1016    }
1017
1018    /// Helper function for property removal.
1019    #[inline]
1020    pub(crate) fn remove(&mut self, key: &PropertyKey) -> Option<PropertyDescriptor> {
1021        self.properties.remove(key)
1022    }
1023
1024    /// Inserts a field in the object `properties` without checking if it's writable.
1025    ///
1026    /// If a field was already in the object with the same name that a `Some` is returned
1027    /// with that field, otherwise None is retuned.
1028    #[inline]
1029    pub fn insert_property<K, P>(&mut self, key: K, property: P) -> Option<PropertyDescriptor>
1030    where
1031        K: Into<PropertyKey>,
1032        P: Into<PropertyDescriptor>,
1033    {
1034        self.insert(key, property)
1035    }
1036}
1037
1038/// The functions binding.
1039///
1040/// Specifies what is the name of the function object (`name` property),
1041/// and the binding name of the function object which can be different
1042/// from the function name.
1043///
1044/// The only way to construct this is with the `From` trait.
1045///
1046/// There are two implementations:
1047///  - From a single type `T` which implements `Into<FunctionBinding>` which sets the binding
1048/// name and the function name to the same value
1049///  - From a tuple `(B: Into<PropertyKey>, N: AsRef<str>)` the `B` is the binding name
1050/// and the `N` is the function name.
1051#[derive(Debug, Clone)]
1052pub struct FunctionBinding {
1053    binding: PropertyKey,
1054    name: JsString,
1055}
1056
1057impl From<&str> for FunctionBinding {
1058    #[inline]
1059    fn from(name: &str) -> Self {
1060        let name: JsString = name.into();
1061
1062        Self {
1063            binding: name.clone().into(),
1064            name,
1065        }
1066    }
1067}
1068
1069impl From<String> for FunctionBinding {
1070    #[inline]
1071    fn from(name: String) -> Self {
1072        let name: JsString = name.into();
1073
1074        Self {
1075            binding: name.clone().into(),
1076            name,
1077        }
1078    }
1079}
1080
1081impl From<JsString> for FunctionBinding {
1082    #[inline]
1083    fn from(name: JsString) -> Self {
1084        Self {
1085            binding: name.clone().into(),
1086            name,
1087        }
1088    }
1089}
1090
1091impl<B, N> From<(B, N)> for FunctionBinding
1092where
1093    B: Into<PropertyKey>,
1094    N: AsRef<str>,
1095{
1096    #[inline]
1097    fn from((binding, name): (B, N)) -> Self {
1098        Self {
1099            binding: binding.into(),
1100            name: name.as_ref().into(),
1101        }
1102    }
1103}
1104
1105/// Builder for creating native function objects
1106#[derive(Debug)]
1107pub struct FunctionBuilder<'context> {
1108    context: &'context mut Context,
1109    function: Option<Function>,
1110    name: JsString,
1111    length: usize,
1112}
1113
1114impl<'context> FunctionBuilder<'context> {
1115    /// Create a new `FunctionBuilder` for creating a native function.
1116    #[inline]
1117    pub fn native(context: &'context mut Context, function: NativeFunction) -> Self {
1118        Self {
1119            context,
1120            function: Some(Function::Native {
1121                function: function.into(),
1122                constructable: false,
1123            }),
1124            name: JsString::default(),
1125            length: 0,
1126        }
1127    }
1128
1129    /// Create a new `FunctionBuilder` for creating a closure function.
1130    #[inline]
1131    pub fn closure<F>(context: &'context mut Context, function: F) -> Self
1132    where
1133        F: Fn(&JsValue, &[JsValue], &mut Context) -> JsResult<JsValue> + Copy + 'static,
1134    {
1135        Self {
1136            context,
1137            function: Some(Function::Closure {
1138                function: Box::new(move |this, args, context, _| function(this, args, context)),
1139                constructable: false,
1140                captures: Captures::new(()),
1141            }),
1142            name: JsString::default(),
1143            length: 0,
1144        }
1145    }
1146
1147    /// Create a new closure function with additional captures.
1148    ///
1149    /// # Note
1150    ///
1151    /// You can only move variables that implement `Debug + Any + Trace + Clone`.
1152    /// In other words, only `NativeObject + Clone` objects are movable.
1153    #[inline]
1154    pub fn closure_with_captures<F, C>(
1155        context: &'context mut Context,
1156        function: F,
1157        captures: C,
1158    ) -> Self
1159    where
1160        F: Fn(&JsValue, &[JsValue], &mut Context, &mut C) -> JsResult<JsValue> + Copy + 'static,
1161        C: NativeObject + Clone,
1162    {
1163        Self {
1164            context,
1165            function: Some(Function::Closure {
1166                function: Box::new(move |this, args, context, mut captures: Captures| {
1167                    let data = captures.try_downcast_mut::<C>(context)?;
1168                    function(this, args, context, data)
1169                }),
1170                constructable: false,
1171                captures: Captures::new(captures),
1172            }),
1173            name: JsString::default(),
1174            length: 0,
1175        }
1176    }
1177
1178    /// Specify the name property of object function object.
1179    ///
1180    /// The default is `""` (empty string).
1181    #[inline]
1182    pub fn name<N>(&mut self, name: N) -> &mut Self
1183    where
1184        N: AsRef<str>,
1185    {
1186        self.name = name.as_ref().into();
1187        self
1188    }
1189
1190    /// Specify the length property of object function object.
1191    ///
1192    /// How many arguments this function takes.
1193    ///
1194    /// The default is `0`.
1195    #[inline]
1196    pub fn length(&mut self, length: usize) -> &mut Self {
1197        self.length = length;
1198        self
1199    }
1200
1201    /// Specify the whether the object function object can be called with `new` keyword.
1202    ///
1203    /// The default is `false`.
1204    #[inline]
1205    pub fn constructable(&mut self, yes: bool) -> &mut Self {
1206        match self.function.as_mut() {
1207            Some(Function::Native { constructable, .. }) => *constructable = yes,
1208            Some(Function::Closure { constructable, .. }) => *constructable = yes,
1209            _ => unreachable!(),
1210        }
1211        self
1212    }
1213
1214    /// Build the function object.
1215    #[inline]
1216    pub fn build(&mut self) -> JsObject {
1217        let mut function = Object::function(
1218            self.function.take().unwrap(),
1219            self.context
1220                .standard_objects()
1221                .function_object()
1222                .prototype()
1223                .into(),
1224        );
1225        let property = PropertyDescriptor::builder()
1226            .writable(false)
1227            .enumerable(false)
1228            .configurable(true);
1229        function.insert_property("name", property.clone().value(self.name.clone()));
1230        function.insert_property("length", property.value(self.length));
1231
1232        JsObject::new(function)
1233    }
1234
1235    /// Initializes the `Function.prototype` function object.
1236    pub(crate) fn build_function_prototype(&mut self, object: &JsObject) {
1237        let mut object = object.borrow_mut();
1238        object.data = ObjectData::function(self.function.take().unwrap());
1239        object.set_prototype_instance(
1240            self.context
1241                .standard_objects()
1242                .object_object()
1243                .prototype()
1244                .into(),
1245        );
1246
1247        let property = PropertyDescriptor::builder()
1248            .writable(false)
1249            .enumerable(false)
1250            .configurable(true);
1251        object.insert_property("name", property.clone().value(self.name.clone()));
1252        object.insert_property("length", property.value(self.length));
1253    }
1254}
1255
1256/// Builder for creating objects with properties.
1257///
1258/// # Examples
1259///
1260/// ```
1261/// # use boa::{Context, JsValue, object::ObjectInitializer, property::Attribute};
1262/// let mut context = Context::new();
1263/// let object = ObjectInitializer::new(&mut context)
1264///     .property(
1265///         "hello",
1266///         "world",
1267///         Attribute::all()
1268///     )
1269///     .property(
1270///         1,
1271///         1,
1272///         Attribute::all()
1273///     )
1274///     .function(|_, _, _| Ok(JsValue::undefined()), "func", 0)
1275///     .build();
1276/// ```
1277///
1278/// The equivalent in JavaScript would be:
1279/// ```text
1280/// let object = {
1281///     hello: "world",
1282///     "1": 1,
1283///     func: function() {}
1284/// }
1285/// ```
1286#[derive(Debug)]
1287pub struct ObjectInitializer<'context> {
1288    context: &'context mut Context,
1289    object: JsObject,
1290}
1291
1292impl<'context> ObjectInitializer<'context> {
1293    /// Create a new `ObjectBuilder`.
1294    #[inline]
1295    pub fn new(context: &'context mut Context) -> Self {
1296        let object = context.construct_object();
1297        Self { context, object }
1298    }
1299
1300    /// Add a function to the object.
1301    #[inline]
1302    pub fn function<B>(&mut self, function: NativeFunction, binding: B, length: usize) -> &mut Self
1303    where
1304        B: Into<FunctionBinding>,
1305    {
1306        let binding = binding.into();
1307        let function = FunctionBuilder::native(self.context, function)
1308            .name(binding.name)
1309            .length(length)
1310            .constructable(false)
1311            .build();
1312
1313        self.object.borrow_mut().insert_property(
1314            binding.binding,
1315            PropertyDescriptor::builder()
1316                .value(function)
1317                .writable(true)
1318                .enumerable(false)
1319                .configurable(true),
1320        );
1321        self
1322    }
1323
1324    /// Add a property to the object.
1325    #[inline]
1326    pub fn property<K, V>(&mut self, key: K, value: V, attribute: Attribute) -> &mut Self
1327    where
1328        K: Into<PropertyKey>,
1329        V: Into<JsValue>,
1330    {
1331        let property = PropertyDescriptor::builder()
1332            .value(value)
1333            .writable(attribute.writable())
1334            .enumerable(attribute.enumerable())
1335            .configurable(attribute.configurable());
1336        self.object.borrow_mut().insert(key, property);
1337        self
1338    }
1339
1340    /// Build the object.
1341    #[inline]
1342    pub fn build(&mut self) -> JsObject {
1343        self.object.clone()
1344    }
1345}
1346
1347/// Builder for creating constructors objects, like `Array`.
1348pub struct ConstructorBuilder<'context> {
1349    context: &'context mut Context,
1350    constructor_function: NativeFunction,
1351    constructor_object: JsObject,
1352    prototype: JsObject,
1353    name: JsString,
1354    length: usize,
1355    callable: bool,
1356    constructable: bool,
1357    inherit: Option<JsValue>,
1358}
1359
1360impl Debug for ConstructorBuilder<'_> {
1361    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1362        f.debug_struct("ConstructorBuilder")
1363            .field("name", &self.name)
1364            .field("length", &self.length)
1365            .field("constructor", &self.constructor_object)
1366            .field("prototype", &self.prototype)
1367            .field("inherit", &self.inherit)
1368            .field("callable", &self.callable)
1369            .field("constructable", &self.constructable)
1370            .finish()
1371    }
1372}
1373
1374impl<'context> ConstructorBuilder<'context> {
1375    /// Create a new `ConstructorBuilder`.
1376    #[inline]
1377    pub fn new(context: &'context mut Context, constructor: NativeFunction) -> Self {
1378        Self {
1379            context,
1380            constructor_function: constructor,
1381            constructor_object: JsObject::new(Object::default()),
1382            prototype: JsObject::new(Object::default()),
1383            length: 0,
1384            name: JsString::default(),
1385            callable: true,
1386            constructable: true,
1387            inherit: None,
1388        }
1389    }
1390
1391    #[inline]
1392    pub(crate) fn with_standard_object(
1393        context: &'context mut Context,
1394        constructor: NativeFunction,
1395        object: StandardConstructor,
1396    ) -> Self {
1397        Self {
1398            context,
1399            constructor_function: constructor,
1400            constructor_object: object.constructor,
1401            prototype: object.prototype,
1402            length: 0,
1403            name: JsString::default(),
1404            callable: true,
1405            constructable: true,
1406            inherit: None,
1407        }
1408    }
1409
1410    /// Add new method to the constructors prototype.
1411    #[inline]
1412    pub fn method<B>(&mut self, function: NativeFunction, binding: B, length: usize) -> &mut Self
1413    where
1414        B: Into<FunctionBinding>,
1415    {
1416        let binding = binding.into();
1417        let function = FunctionBuilder::native(self.context, function)
1418            .name(binding.name)
1419            .length(length)
1420            .constructable(false)
1421            .build();
1422
1423        self.prototype.borrow_mut().insert_property(
1424            binding.binding,
1425            PropertyDescriptor::builder()
1426                .value(function)
1427                .writable(true)
1428                .enumerable(false)
1429                .configurable(true),
1430        );
1431        self
1432    }
1433
1434    /// Add new static method to the constructors object itself.
1435    #[inline]
1436    pub fn static_method<B>(
1437        &mut self,
1438        function: NativeFunction,
1439        binding: B,
1440        length: usize,
1441    ) -> &mut Self
1442    where
1443        B: Into<FunctionBinding>,
1444    {
1445        let binding = binding.into();
1446        let function = FunctionBuilder::native(self.context, function)
1447            .name(binding.name)
1448            .length(length)
1449            .constructable(false)
1450            .build();
1451
1452        self.constructor_object.borrow_mut().insert_property(
1453            binding.binding,
1454            PropertyDescriptor::builder()
1455                .value(function)
1456                .writable(true)
1457                .enumerable(false)
1458                .configurable(true),
1459        );
1460        self
1461    }
1462
1463    /// Add new data property to the constructor's prototype.
1464    #[inline]
1465    pub fn property<K, V>(&mut self, key: K, value: V, attribute: Attribute) -> &mut Self
1466    where
1467        K: Into<PropertyKey>,
1468        V: Into<JsValue>,
1469    {
1470        let property = PropertyDescriptor::builder()
1471            .value(value)
1472            .writable(attribute.writable())
1473            .enumerable(attribute.enumerable())
1474            .configurable(attribute.configurable());
1475        self.prototype.borrow_mut().insert(key, property);
1476        self
1477    }
1478
1479    /// Add new static data property to the constructor object itself.
1480    #[inline]
1481    pub fn static_property<K, V>(&mut self, key: K, value: V, attribute: Attribute) -> &mut Self
1482    where
1483        K: Into<PropertyKey>,
1484        V: Into<JsValue>,
1485    {
1486        let property = PropertyDescriptor::builder()
1487            .value(value)
1488            .writable(attribute.writable())
1489            .enumerable(attribute.enumerable())
1490            .configurable(attribute.configurable());
1491        self.constructor_object.borrow_mut().insert(key, property);
1492        self
1493    }
1494
1495    /// Add new accessor property to the constructor's prototype.
1496    #[inline]
1497    pub fn accessor<K>(
1498        &mut self,
1499        key: K,
1500        get: Option<JsObject>,
1501        set: Option<JsObject>,
1502        attribute: Attribute,
1503    ) -> &mut Self
1504    where
1505        K: Into<PropertyKey>,
1506    {
1507        let property = PropertyDescriptor::builder()
1508            .maybe_get(get)
1509            .maybe_set(set)
1510            .enumerable(attribute.enumerable())
1511            .configurable(attribute.configurable());
1512        self.prototype.borrow_mut().insert(key, property);
1513        self
1514    }
1515
1516    /// Add new static accessor property to the constructor object itself.
1517    #[inline]
1518    pub fn static_accessor<K>(
1519        &mut self,
1520        key: K,
1521        get: Option<JsObject>,
1522        set: Option<JsObject>,
1523        attribute: Attribute,
1524    ) -> &mut Self
1525    where
1526        K: Into<PropertyKey>,
1527    {
1528        let property = PropertyDescriptor::builder()
1529            .maybe_get(get)
1530            .maybe_set(set)
1531            .enumerable(attribute.enumerable())
1532            .configurable(attribute.configurable());
1533        self.constructor_object.borrow_mut().insert(key, property);
1534        self
1535    }
1536
1537    /// Add new property to the constructor's prototype.
1538    #[inline]
1539    pub fn property_descriptor<K, P>(&mut self, key: K, property: P) -> &mut Self
1540    where
1541        K: Into<PropertyKey>,
1542        P: Into<PropertyDescriptor>,
1543    {
1544        let property = property.into();
1545        self.prototype.borrow_mut().insert(key, property);
1546        self
1547    }
1548
1549    /// Add new static property to the constructor object itself.
1550    #[inline]
1551    pub fn static_property_descriptor<K, P>(&mut self, key: K, property: P) -> &mut Self
1552    where
1553        K: Into<PropertyKey>,
1554        P: Into<PropertyDescriptor>,
1555    {
1556        let property = property.into();
1557        self.constructor_object.borrow_mut().insert(key, property);
1558        self
1559    }
1560
1561    /// Specify how many arguments the constructor function takes.
1562    ///
1563    /// Default is `0`.
1564    #[inline]
1565    pub fn length(&mut self, length: usize) -> &mut Self {
1566        self.length = length;
1567        self
1568    }
1569
1570    /// Specify the name of the constructor function.
1571    ///
1572    /// Default is `"[object]"`
1573    #[inline]
1574    pub fn name<N>(&mut self, name: N) -> &mut Self
1575    where
1576        N: AsRef<str>,
1577    {
1578        self.name = name.as_ref().into();
1579        self
1580    }
1581
1582    /// Specify whether the constructor function can be called.
1583    ///
1584    /// Default is `true`
1585    #[inline]
1586    pub fn callable(&mut self, callable: bool) -> &mut Self {
1587        self.callable = callable;
1588        self
1589    }
1590
1591    /// Specify whether the constructor function can be called with `new` keyword.
1592    ///
1593    /// Default is `true`
1594    #[inline]
1595    pub fn constructable(&mut self, constructable: bool) -> &mut Self {
1596        self.constructable = constructable;
1597        self
1598    }
1599
1600    /// Specify the prototype this constructor object inherits from.
1601    ///
1602    /// Default is `Object.prototype`
1603    #[inline]
1604    pub fn inherit(&mut self, prototype: JsValue) -> &mut Self {
1605        assert!(prototype.is_object() || prototype.is_null());
1606        self.inherit = Some(prototype);
1607        self
1608    }
1609
1610    /// Return the current context.
1611    #[inline]
1612    pub fn context(&mut self) -> &'_ mut Context {
1613        self.context
1614    }
1615
1616    /// Build the constructor function object.
1617    pub fn build(&mut self) -> JsObject {
1618        // Create the native function
1619        let function = Function::Native {
1620            function: self.constructor_function.into(),
1621            constructable: self.constructable,
1622        };
1623
1624        let length = PropertyDescriptor::builder()
1625            .value(self.length)
1626            .writable(false)
1627            .enumerable(false)
1628            .configurable(true);
1629        let name = PropertyDescriptor::builder()
1630            .value(self.name.clone())
1631            .writable(false)
1632            .enumerable(false)
1633            .configurable(true);
1634
1635        {
1636            let mut constructor = self.constructor_object.borrow_mut();
1637            constructor.data = ObjectData::function(function);
1638            constructor.insert("length", length);
1639            constructor.insert("name", name);
1640
1641            constructor.set_prototype_instance(
1642                self.context
1643                    .standard_objects()
1644                    .function_object()
1645                    .prototype()
1646                    .into(),
1647            );
1648
1649            constructor.insert_property(
1650                PROTOTYPE,
1651                PropertyDescriptor::builder()
1652                    .value(self.prototype.clone())
1653                    .writable(false)
1654                    .enumerable(false)
1655                    .configurable(false),
1656            );
1657        }
1658
1659        {
1660            let mut prototype = self.prototype.borrow_mut();
1661            prototype.insert_property(
1662                "constructor",
1663                PropertyDescriptor::builder()
1664                    .value(self.constructor_object.clone())
1665                    .writable(true)
1666                    .enumerable(false)
1667                    .configurable(true),
1668            );
1669
1670            if let Some(proto) = self.inherit.take() {
1671                prototype.set_prototype_instance(proto);
1672            } else {
1673                prototype.set_prototype_instance(
1674                    self.context
1675                        .standard_objects()
1676                        .object_object()
1677                        .prototype()
1678                        .into(),
1679                );
1680            }
1681        }
1682
1683        self.constructor_object.clone()
1684    }
1685}