1use 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
45pub static PROTOTYPE: &str = "prototype";
47
48pub trait NativeObject: Debug + Any + Trace {
52 fn as_any(&self) -> &dyn Any;
54
55 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#[derive(Debug, Trace, Finalize)]
73pub struct Object {
74 pub data: ObjectData,
76 properties: PropertyMap,
77 prototype: JsValue,
79 extensible: bool,
81}
82
83#[derive(Trace, Finalize)]
85pub struct ObjectData {
86 kind: ObjectKind,
87 internal_methods: &'static InternalObjectMethods,
88}
89
90#[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 pub fn array() -> Self {
119 Self {
120 kind: ObjectKind::Array,
121 internal_methods: &ARRAY_EXOTIC_INTERNAL_METHODS,
122 }
123 }
124
125 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 pub fn map(map: OrderedMap<JsValue>) -> Self {
135 Self {
136 kind: ObjectKind::Map(map),
137 internal_methods: &ORDINARY_INTERNAL_METHODS,
138 }
139 }
140
141 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 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 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 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 pub fn boolean(boolean: bool) -> Self {
175 Self {
176 kind: ObjectKind::Boolean(boolean),
177 internal_methods: &ORDINARY_INTERNAL_METHODS,
178 }
179 }
180
181 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 pub fn function(function: Function) -> Self {
191 Self {
192 kind: ObjectKind::Function(function),
193 internal_methods: &ORDINARY_INTERNAL_METHODS,
194 }
195 }
196
197 pub fn set(set: OrderedSet<JsValue>) -> Self {
199 Self {
200 kind: ObjectKind::Set(set),
201 internal_methods: &ORDINARY_INTERNAL_METHODS,
202 }
203 }
204
205 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 pub fn string(string: JsString) -> Self {
215 Self {
216 kind: ObjectKind::String(string),
217 internal_methods: &STRING_EXOTIC_INTERNAL_METHODS,
218 }
219 }
220
221 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 pub fn number(number: f64) -> Self {
231 Self {
232 kind: ObjectKind::Number(number),
233 internal_methods: &ORDINARY_INTERNAL_METHODS,
234 }
235 }
236
237 pub fn symbol(symbol: JsSymbol) -> Self {
239 Self {
240 kind: ObjectKind::Symbol(symbol),
241 internal_methods: &ORDINARY_INTERNAL_METHODS,
242 }
243 }
244
245 pub fn error() -> Self {
247 Self {
248 kind: ObjectKind::Error,
249 internal_methods: &ORDINARY_INTERNAL_METHODS,
250 }
251 }
252
253 pub fn ordinary() -> Self {
255 Self {
256 kind: ObjectKind::Ordinary,
257 internal_methods: &ORDINARY_INTERNAL_METHODS,
258 }
259 }
260
261 pub fn date(date: Date) -> Self {
263 Self {
264 kind: ObjectKind::Date(date),
265 internal_methods: &ORDINARY_INTERNAL_METHODS,
266 }
267 }
268
269 pub fn global() -> Self {
271 Self {
272 kind: ObjectKind::Global,
273 internal_methods: &ORDINARY_INTERNAL_METHODS,
274 }
275 }
276
277 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 #[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 #[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 #[inline]
367 pub fn create(proto: JsValue) -> Self {
368 let mut obj = Self::new();
369 obj.prototype = proto;
370 obj
371 }
372
373 #[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 #[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 #[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 #[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 #[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 #[inline]
446 pub fn is_callable(&self) -> bool {
449 matches!(
450 self.data,
451 ObjectData {
452 kind: ObjectKind::Function(_),
453 ..
454 }
455 )
456 }
457
458 #[inline]
465 pub fn is_constructable(&self) -> bool {
468 matches!(self.data, ObjectData{kind: ObjectKind::Function(ref f), ..} if f.is_constructable())
469 }
470
471 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 JsValue::same_value(&prototype, &self.prototype)
921 }
922 }
923
924 #[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 #[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 #[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 #[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 #[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 #[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 #[inline]
1020 pub(crate) fn remove(&mut self, key: &PropertyKey) -> Option<PropertyDescriptor> {
1021 self.properties.remove(key)
1022 }
1023
1024 #[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#[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#[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 #[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 #[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 #[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 #[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 #[inline]
1196 pub fn length(&mut self, length: usize) -> &mut Self {
1197 self.length = length;
1198 self
1199 }
1200
1201 #[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 #[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 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#[derive(Debug)]
1287pub struct ObjectInitializer<'context> {
1288 context: &'context mut Context,
1289 object: JsObject,
1290}
1291
1292impl<'context> ObjectInitializer<'context> {
1293 #[inline]
1295 pub fn new(context: &'context mut Context) -> Self {
1296 let object = context.construct_object();
1297 Self { context, object }
1298 }
1299
1300 #[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 #[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 #[inline]
1342 pub fn build(&mut self) -> JsObject {
1343 self.object.clone()
1344 }
1345}
1346
1347pub 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline]
1565 pub fn length(&mut self, length: usize) -> &mut Self {
1566 self.length = length;
1567 self
1568 }
1569
1570 #[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 #[inline]
1586 pub fn callable(&mut self, callable: bool) -> &mut Self {
1587 self.callable = callable;
1588 self
1589 }
1590
1591 #[inline]
1595 pub fn constructable(&mut self, constructable: bool) -> &mut Self {
1596 self.constructable = constructable;
1597 self
1598 }
1599
1600 #[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 #[inline]
1612 pub fn context(&mut self) -> &'_ mut Context {
1613 self.context
1614 }
1615
1616 pub fn build(&mut self) -> JsObject {
1618 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}