Skip to main content

v8/
object.rs

1use crate::AccessorConfiguration;
2use crate::AccessorNameGetterCallback;
3use crate::AccessorNameSetterCallback;
4use crate::Array;
5use crate::Context;
6use crate::Data;
7use crate::GetPropertyNamesArgs;
8use crate::IndexFilter;
9use crate::KeyCollectionMode;
10use crate::KeyConversionMode;
11use crate::Local;
12use crate::Map;
13use crate::Name;
14use crate::Object;
15use crate::Private;
16use crate::PropertyAttribute;
17use crate::PropertyDescriptor;
18use crate::PropertyFilter;
19use crate::Set;
20use crate::String;
21use crate::Value;
22use crate::binding::RustObj;
23use crate::cppgc::GarbageCollected;
24use crate::cppgc::GetRustObj;
25use crate::cppgc::UnsafePtr;
26use crate::isolate::Isolate;
27use crate::isolate::RealIsolate;
28use crate::scope::PinScope;
29use crate::support::MapFnTo;
30use crate::support::Maybe;
31use crate::support::MaybeBool;
32use crate::support::int;
33use std::convert::TryFrom;
34use std::ffi::c_void;
35use std::mem::MaybeUninit;
36use std::num::NonZeroI32;
37use std::ptr::null;
38
39unsafe extern "C" {
40  fn v8__Object__New(isolate: *mut RealIsolate) -> *const Object;
41  fn v8__Object__New__with_prototype_and_properties(
42    isolate: *mut RealIsolate,
43    prototype_or_null: *const Value,
44    names: *const *const Name,
45    values: *const *const Value,
46    length: usize,
47  ) -> *const Object;
48  fn v8__Object__SetAccessor(
49    this: *const Object,
50    context: *const Context,
51    key: *const Name,
52    getter: AccessorNameGetterCallback,
53    setter: Option<AccessorNameSetterCallback>,
54    data_or_null: *const Value,
55    attr: PropertyAttribute,
56  ) -> MaybeBool;
57  fn v8__Object__Get(
58    this: *const Object,
59    context: *const Context,
60    key: *const Value,
61  ) -> *const Value;
62  fn v8__Object__GetWithReceiver(
63    this: *const Object,
64    context: *const Context,
65    key: *const Value,
66    receiver: *const Object,
67  ) -> *const Value;
68  fn v8__Object__GetIndex(
69    this: *const Object,
70    context: *const Context,
71    index: u32,
72  ) -> *const Value;
73  fn v8__Object__GetPrototype(this: *const Object) -> *const Value;
74  fn v8__Object__Set(
75    this: *const Object,
76    context: *const Context,
77    key: *const Value,
78    value: *const Value,
79  ) -> MaybeBool;
80  fn v8__Object__SetWithReceiver(
81    this: *const Object,
82    context: *const Context,
83    key: *const Value,
84    value: *const Value,
85    receiver: *const Object,
86  ) -> MaybeBool;
87  fn v8__Object__SetIndex(
88    this: *const Object,
89    context: *const Context,
90    index: u32,
91    value: *const Value,
92  ) -> MaybeBool;
93  fn v8__Object__SetPrototype(
94    this: *const Object,
95    context: *const Context,
96    prototype: *const Value,
97  ) -> MaybeBool;
98  fn v8__Object__GetConstructorName(this: *const Object) -> *const String;
99  fn v8__Object__CreateDataProperty(
100    this: *const Object,
101    context: *const Context,
102    key: *const Name,
103    value: *const Value,
104  ) -> MaybeBool;
105  fn v8__Object__DefineOwnProperty(
106    this: *const Object,
107    context: *const Context,
108    key: *const Name,
109    value: *const Value,
110    attr: PropertyAttribute,
111  ) -> MaybeBool;
112  fn v8__Object__DefineProperty(
113    this: *const Object,
114    context: *const Context,
115    key: *const Name,
116    desc: *const PropertyDescriptor,
117  ) -> MaybeBool;
118  fn v8__Object__GetIdentityHash(this: *const Object) -> int;
119  fn v8__Object__GetCreationContext(this: *const Object) -> *const Context;
120  fn v8__Object__GetOwnPropertyNames(
121    this: *const Object,
122    context: *const Context,
123    filter: PropertyFilter,
124    key_conversion: KeyConversionMode,
125  ) -> *const Array;
126  fn v8__Object__GetPropertyNames(
127    this: *const Object,
128    context: *const Context,
129    mode: KeyCollectionMode,
130    property_filter: PropertyFilter,
131    index_filter: IndexFilter,
132    key_conversion: KeyConversionMode,
133  ) -> *const Array;
134  fn v8__Object__Has(
135    this: *const Object,
136    context: *const Context,
137    key: *const Value,
138  ) -> MaybeBool;
139  fn v8__Object__HasIndex(
140    this: *const Object,
141    context: *const Context,
142    index: u32,
143  ) -> MaybeBool;
144  fn v8__Object__HasOwnProperty(
145    this: *const Object,
146    context: *const Context,
147    key: *const Name,
148  ) -> MaybeBool;
149  fn v8__Object__Delete(
150    this: *const Object,
151    context: *const Context,
152    key: *const Value,
153  ) -> MaybeBool;
154  fn v8__Object__DeleteIndex(
155    this: *const Object,
156    context: *const Context,
157    index: u32,
158  ) -> MaybeBool;
159  fn v8__Object__InternalFieldCount(this: *const Object) -> int;
160  fn v8__Object__GetInternalField(
161    this: *const Object,
162    index: int,
163  ) -> *const Data;
164  fn v8__Object__GetAlignedPointerFromInternalField(
165    this: *const Object,
166    index: int,
167  ) -> *const c_void;
168  fn v8__Object__SetAlignedPointerInInternalField(
169    this: *const Object,
170    index: int,
171    value: *const c_void,
172  );
173  fn v8__Object__SetIntegrityLevel(
174    this: *const Object,
175    context: *const Context,
176    level: IntegrityLevel,
177  ) -> MaybeBool;
178  fn v8__Object__SetInternalField(
179    this: *const Object,
180    index: int,
181    data: *const Data,
182  );
183  fn v8__Object__GetPrivate(
184    this: *const Object,
185    context: *const Context,
186    key: *const Private,
187  ) -> *const Value;
188  fn v8__Object__SetPrivate(
189    this: *const Object,
190    context: *const Context,
191    key: *const Private,
192    value: *const Value,
193  ) -> MaybeBool;
194  fn v8__Object__DeletePrivate(
195    this: *const Object,
196    context: *const Context,
197    key: *const Private,
198  ) -> MaybeBool;
199  fn v8__Object__HasPrivate(
200    this: *const Object,
201    context: *const Context,
202    key: *const Private,
203  ) -> MaybeBool;
204  fn v8__Object__GetPropertyAttributes(
205    this: *const Object,
206    context: *const Context,
207    key: *const Value,
208    out: *mut Maybe<PropertyAttribute>,
209  );
210  fn v8__Object__GetOwnPropertyDescriptor(
211    this: *const Object,
212    context: *const Context,
213    key: *const Name,
214  ) -> *const Value;
215  fn v8__Object__PreviewEntries(
216    this: *const Object,
217    is_key_value: *mut bool,
218  ) -> *const Array;
219  fn v8__Object__GetRealNamedProperty(
220    this: *const Object,
221    context: *const Context,
222    key: *const Name,
223  ) -> *const Value;
224  fn v8__Object__HasRealNamedProperty(
225    this: *const Object,
226    context: *const Context,
227    key: *const Name,
228  ) -> MaybeBool;
229  fn v8__Object__GetRealNamedPropertyAttributes(
230    this: *const Object,
231    context: *const Context,
232    key: *const Name,
233    out: *mut Maybe<PropertyAttribute>,
234  );
235  fn v8__Object__Wrap(
236    isolate: *const RealIsolate,
237    wrapper: *const Object,
238    value: *const RustObj,
239    tag: u16,
240  );
241  fn v8__Object__Unwrap(
242    isolate: *const RealIsolate,
243    wrapper: *const Object,
244    tag: u16,
245  ) -> *mut RustObj;
246  fn v8__Object__IsApiWrapper(this: *const Object) -> bool;
247
248  fn v8__Array__New(isolate: *mut RealIsolate, length: int) -> *const Array;
249  fn v8__Array__New_with_elements(
250    isolate: *mut RealIsolate,
251    elements: *const *const Value,
252    length: usize,
253  ) -> *const Array;
254  fn v8__Array__Length(array: *const Array) -> u32;
255  fn v8__Map__New(isolate: *mut RealIsolate) -> *const Map;
256  fn v8__Map__Clear(this: *const Map);
257  fn v8__Map__Get(
258    this: *const Map,
259    context: *const Context,
260    key: *const Value,
261  ) -> *const Value;
262  fn v8__Map__Set(
263    this: *const Map,
264    context: *const Context,
265    key: *const Value,
266    value: *const Value,
267  ) -> *const Map;
268  fn v8__Map__Has(
269    this: *const Map,
270    context: *const Context,
271    key: *const Value,
272  ) -> MaybeBool;
273  fn v8__Map__Delete(
274    this: *const Map,
275    context: *const Context,
276    key: *const Value,
277  ) -> MaybeBool;
278  fn v8__Map__Size(map: *const Map) -> usize;
279  fn v8__Map__As__Array(this: *const Map) -> *const Array;
280  fn v8__Set__New(isolate: *mut RealIsolate) -> *const Set;
281  fn v8__Set__Clear(this: *const Set);
282  fn v8__Set__Add(
283    this: *const Set,
284    context: *const Context,
285    key: *const Value,
286  ) -> *const Set;
287  fn v8__Set__Has(
288    this: *const Set,
289    context: *const Context,
290    key: *const Value,
291  ) -> MaybeBool;
292  fn v8__Set__Delete(
293    this: *const Set,
294    context: *const Context,
295    key: *const Value,
296  ) -> MaybeBool;
297  fn v8__Set__Size(map: *const Set) -> usize;
298  fn v8__Set__As__Array(this: *const Set) -> *const Array;
299}
300
301const LAST_TAG: u16 = 0x7fff;
302
303impl Object {
304  /// Creates an empty object.
305  #[inline(always)]
306  pub fn new<'s>(scope: &PinScope<'s, '_>) -> Local<'s, Object> {
307    unsafe { scope.cast_local(|sd| v8__Object__New(sd.get_isolate_ptr())) }
308      .unwrap()
309  }
310
311  /// Creates a JavaScript object with the given properties, and the given
312  /// prototype_or_null (which can be any JavaScript value, and if it's null,
313  /// the newly created object won't have a prototype at all). This is similar
314  /// to Object.create(). All properties will be created as enumerable,
315  /// configurable and writable properties.
316  #[inline(always)]
317  pub fn with_prototype_and_properties<'s>(
318    scope: &PinScope<'s, '_>,
319    prototype_or_null: Local<'s, Value>,
320    names: &[Local<Name>],
321    values: &[Local<Value>],
322  ) -> Local<'s, Object> {
323    assert_eq!(names.len(), values.len());
324    let names = Local::slice_into_raw(names);
325    let values = Local::slice_into_raw(values);
326    unsafe {
327      scope.cast_local(|sd| {
328        v8__Object__New__with_prototype_and_properties(
329          sd.get_isolate_ptr(),
330          &*prototype_or_null,
331          names.as_ptr(),
332          values.as_ptr(),
333          names.len(),
334        )
335      })
336    }
337    .unwrap()
338  }
339
340  /// Set only return Just(true) or Empty(), so if it should never fail, use
341  /// result.Check().
342  #[inline(always)]
343  pub fn set(
344    &self,
345    scope: &PinScope<'_, '_>,
346    key: Local<Value>,
347    value: Local<Value>,
348  ) -> Option<bool> {
349    unsafe {
350      v8__Object__Set(self, &*scope.get_current_context(), &*key, &*value)
351    }
352    .into()
353  }
354
355  /// SetWithReceiver only return Just(true) or Empty(), so if it should never fail, use
356  /// result.Check().
357  #[inline(always)]
358  pub fn set_with_receiver(
359    &self,
360    scope: &PinScope<'_, '_>,
361    key: Local<Value>,
362    value: Local<Value>,
363    receiver: Local<Object>,
364  ) -> Option<bool> {
365    unsafe {
366      v8__Object__SetWithReceiver(
367        self,
368        &*scope.get_current_context(),
369        &*key,
370        &*value,
371        &*receiver,
372      )
373    }
374    .into()
375  }
376
377  /// Set only return Just(true) or Empty(), so if it should never fail, use
378  /// result.Check().
379  #[inline(always)]
380  pub fn set_index(
381    &self,
382    scope: &PinScope<'_, '_>,
383    index: u32,
384    value: Local<Value>,
385  ) -> Option<bool> {
386    unsafe {
387      v8__Object__SetIndex(self, &*scope.get_current_context(), index, &*value)
388    }
389    .into()
390  }
391
392  /// Set the prototype object. This does not skip objects marked to be
393  /// skipped by proto and it does not consult the security handler.
394  #[inline(always)]
395  pub fn set_prototype(
396    &self,
397    scope: &PinScope<'_, '_>,
398    prototype: Local<Value>,
399  ) -> Option<bool> {
400    unsafe {
401      v8__Object__SetPrototype(self, &*scope.get_current_context(), &*prototype)
402    }
403    .into()
404  }
405
406  /// Returns the name of the function invoked as a constructor for this object.
407  #[inline(always)]
408  pub fn get_constructor_name(&self) -> Local<'_, String> {
409    unsafe { Local::from_raw(v8__Object__GetConstructorName(self)) }.unwrap()
410  }
411
412  /// Implements CreateDataProperty (ECMA-262, 7.3.4).
413  ///
414  /// Defines a configurable, writable, enumerable property with the given value
415  /// on the object unless the property already exists and is not configurable
416  /// or the object is not extensible.
417  ///
418  /// Returns true on success.
419  #[inline(always)]
420  pub fn create_data_property(
421    &self,
422    scope: &PinScope<'_, '_>,
423    key: Local<Name>,
424    value: Local<Value>,
425  ) -> Option<bool> {
426    unsafe {
427      v8__Object__CreateDataProperty(
428        self,
429        &*scope.get_current_context(),
430        &*key,
431        &*value,
432      )
433    }
434    .into()
435  }
436
437  /// Implements DefineOwnProperty.
438  ///
439  /// In general, CreateDataProperty will be faster, however, does not allow
440  /// for specifying attributes.
441  ///
442  /// Returns true on success.
443  #[inline(always)]
444  pub fn define_own_property(
445    &self,
446    scope: &PinScope<'_, '_>,
447    key: Local<Name>,
448    value: Local<Value>,
449    attr: PropertyAttribute,
450  ) -> Option<bool> {
451    unsafe {
452      v8__Object__DefineOwnProperty(
453        self,
454        &*scope.get_current_context(),
455        &*key,
456        &*value,
457        attr,
458      )
459    }
460    .into()
461  }
462
463  #[inline(always)]
464  pub fn define_property(
465    &self,
466    scope: &PinScope<'_, '_>,
467    key: Local<Name>,
468    descriptor: &PropertyDescriptor,
469  ) -> Option<bool> {
470    unsafe {
471      v8__Object__DefineProperty(
472        self,
473        &*scope.get_current_context(),
474        &*key,
475        descriptor,
476      )
477      .into()
478    }
479  }
480
481  #[inline(always)]
482  pub fn get<'s>(
483    &self,
484    scope: &PinScope<'s, '_>,
485    key: Local<Value>,
486  ) -> Option<Local<'s, Value>> {
487    unsafe {
488      scope
489        .cast_local(|sd| v8__Object__Get(self, sd.get_current_context(), &*key))
490    }
491  }
492
493  #[inline(always)]
494  pub fn get_with_receiver<'s>(
495    &self,
496    scope: &PinScope<'s, '_>,
497    key: Local<Value>,
498    receiver: Local<Object>,
499  ) -> Option<Local<'s, Value>> {
500    unsafe {
501      scope.cast_local(|sd| {
502        v8__Object__GetWithReceiver(
503          self,
504          sd.get_current_context(),
505          &*key,
506          &*receiver,
507        )
508      })
509    }
510  }
511
512  #[inline(always)]
513  pub fn get_index<'s>(
514    &self,
515    scope: &PinScope<'s, '_>,
516    index: u32,
517  ) -> Option<Local<'s, Value>> {
518    unsafe {
519      scope.cast_local(|sd| {
520        v8__Object__GetIndex(self, sd.get_current_context(), index)
521      })
522    }
523  }
524
525  /// Get the prototype object. This does not skip objects marked to be
526  /// skipped by proto and it does not consult the security handler.
527  #[inline(always)]
528  pub fn get_prototype<'s>(
529    &self,
530    scope: &PinScope<'s, '_>,
531  ) -> Option<Local<'s, Value>> {
532    unsafe { scope.cast_local(|_| v8__Object__GetPrototype(self)) }
533  }
534
535  /// Note: SideEffectType affects the getter only, not the setter.
536  #[inline(always)]
537  pub fn set_accessor(
538    &self,
539    scope: &PinScope<'_, '_>,
540    name: Local<Name>,
541    getter: impl MapFnTo<AccessorNameGetterCallback>,
542  ) -> Option<bool> {
543    self.set_accessor_with_configuration(
544      scope,
545      name,
546      AccessorConfiguration::new(getter),
547    )
548  }
549
550  #[inline(always)]
551  pub fn set_accessor_with_setter(
552    &self,
553    scope: &PinScope<'_, '_>,
554    name: Local<Name>,
555    getter: impl MapFnTo<AccessorNameGetterCallback>,
556    setter: impl MapFnTo<AccessorNameSetterCallback>,
557  ) -> Option<bool> {
558    self.set_accessor_with_configuration(
559      scope,
560      name,
561      AccessorConfiguration::new(getter).setter(setter),
562    )
563  }
564  #[inline(always)]
565  pub fn set_accessor_with_configuration(
566    &self,
567    scope: &PinScope<'_, '_>,
568    name: Local<Name>,
569    configuration: AccessorConfiguration,
570  ) -> Option<bool> {
571    unsafe {
572      v8__Object__SetAccessor(
573        self,
574        &*scope.get_current_context(),
575        &*name,
576        configuration.getter,
577        configuration.setter,
578        configuration.data.map_or_else(null, |p| &*p),
579        configuration.property_attribute,
580      )
581    }
582    .into()
583  }
584
585  /// Returns the V8 hash value for this value. The current implementation
586  /// uses a hidden property to store the identity hash.
587  ///
588  /// The return value will never be 0. Also, it is not guaranteed to be
589  /// unique.
590  #[inline(always)]
591  pub fn get_identity_hash(&self) -> NonZeroI32 {
592    unsafe { NonZeroI32::new_unchecked(v8__Object__GetIdentityHash(self)) }
593  }
594
595  /// Returns the context in which the object was created.
596  #[inline(always)]
597  pub fn get_creation_context<'s>(
598    &self,
599    scope: &PinScope<'s, '_>,
600  ) -> Option<Local<'s, Context>> {
601    unsafe { scope.cast_local(|_| v8__Object__GetCreationContext(self)) }
602  }
603
604  /// This function has the same functionality as GetPropertyNames but the
605  /// returned array doesn't contain the names of properties from prototype
606  /// objects.
607  #[inline(always)]
608  pub fn get_own_property_names<'s>(
609    &self,
610    scope: &PinScope<'s, '_>,
611    args: GetPropertyNamesArgs,
612  ) -> Option<Local<'s, Array>> {
613    unsafe {
614      scope.cast_local(|sd| {
615        v8__Object__GetOwnPropertyNames(
616          self,
617          sd.get_current_context(),
618          args.property_filter,
619          args.key_conversion,
620        )
621      })
622    }
623  }
624
625  /// Returns an array containing the names of the filtered properties of this
626  /// object, including properties from prototype objects. The array returned by
627  /// this method contains the same values as would be enumerated by a for-in
628  /// statement over this object.
629  #[inline(always)]
630  pub fn get_property_names<'s>(
631    &self,
632    scope: &PinScope<'s, '_>,
633    args: GetPropertyNamesArgs,
634  ) -> Option<Local<'s, Array>> {
635    unsafe {
636      scope.cast_local(|sd| {
637        v8__Object__GetPropertyNames(
638          self,
639          sd.get_current_context(),
640          args.mode,
641          args.property_filter,
642          args.index_filter,
643          args.key_conversion,
644        )
645      })
646    }
647  }
648
649  // Calls the abstract operation HasProperty(O, P) described in ECMA-262,
650  // 7.3.10. Returns true, if the object has the property, either own or on the
651  // prototype chain. Interceptors, i.e., PropertyQueryCallbacks, are called if
652  // present.
653  //
654  // This function has the same side effects as JavaScript's variable in object.
655  // For example, calling this on a revoked proxy will throw an exception.
656  //
657  // Note: This function converts the key to a name, which possibly calls back
658  // into JavaScript.
659  #[inline(always)]
660  pub fn has(
661    &self,
662    scope: &PinScope<'_, '_>,
663    key: Local<Value>,
664  ) -> Option<bool> {
665    unsafe { v8__Object__Has(self, &*scope.get_current_context(), &*key) }
666      .into()
667  }
668
669  #[inline(always)]
670  pub fn has_index(
671    &self,
672    scope: &PinScope<'_, '_>,
673    index: u32,
674  ) -> Option<bool> {
675    unsafe { v8__Object__HasIndex(self, &*scope.get_current_context(), index) }
676      .into()
677  }
678
679  /// HasOwnProperty() is like JavaScript's Object.prototype.hasOwnProperty().
680  #[inline(always)]
681  pub fn has_own_property(
682    &self,
683    scope: &PinScope<'_, '_>,
684    key: Local<Name>,
685  ) -> Option<bool> {
686    unsafe {
687      v8__Object__HasOwnProperty(self, &*scope.get_current_context(), &*key)
688    }
689    .into()
690  }
691
692  #[inline(always)]
693  pub fn delete(
694    &self,
695    scope: &PinScope<'_, '_>,
696    key: Local<Value>,
697  ) -> Option<bool> {
698    unsafe { v8__Object__Delete(self, &*scope.get_current_context(), &*key) }
699      .into()
700  }
701
702  #[inline]
703  pub fn delete_index(
704    &self,
705    scope: &PinScope<'_, '_>,
706    index: u32,
707  ) -> Option<bool> {
708    unsafe {
709      v8__Object__DeleteIndex(self, &*scope.get_current_context(), index)
710    }
711    .into()
712  }
713
714  /// Gets the number of internal fields for this Object.
715  #[inline(always)]
716  pub fn internal_field_count(&self) -> usize {
717    let count = unsafe { v8__Object__InternalFieldCount(self) };
718    usize::try_from(count).expect("bad internal field count") // Can't happen.
719  }
720
721  /// Gets the data from an internal field.
722  #[inline(always)]
723  pub fn get_internal_field<'s>(
724    &self,
725    scope: &PinScope<'s, '_>,
726    index: usize,
727  ) -> Option<Local<'s, Data>> {
728    // Trying to access out-of-bounds internal fields makes V8 abort
729    // in debug mode and access out-of-bounds memory in release mode.
730    // The C++ API takes an i32 but doesn't check for indexes < 0, which
731    // results in an out-of-bounds access in both debug and release mode.
732    if index < self.internal_field_count()
733      && let Ok(index) = int::try_from(index)
734    {
735      return unsafe {
736        scope.cast_local(|_| v8__Object__GetInternalField(self, index))
737      };
738    }
739    None
740  }
741
742  /// Gets a 2-byte-aligned native pointer from an internal field.
743  ///
744  /// # Safety
745  /// This field must have been set by SetAlignedPointerInInternalField, everything else leads to undefined behavior.
746  #[inline(always)]
747  pub unsafe fn get_aligned_pointer_from_internal_field(
748    &self,
749    index: i32,
750  ) -> *const c_void {
751    unsafe { v8__Object__GetAlignedPointerFromInternalField(self, index) }
752  }
753
754  /// Sets a 2-byte-aligned native pointer in an internal field.
755  /// To retrieve such a field, GetAlignedPointerFromInternalField must be used.
756  #[allow(clippy::not_unsafe_ptr_arg_deref)]
757  #[inline(always)]
758  pub fn set_aligned_pointer_in_internal_field(
759    &self,
760    index: i32,
761    value: *const c_void,
762  ) {
763    unsafe { v8__Object__SetAlignedPointerInInternalField(self, index, value) }
764  }
765
766  /// Wraps a JS wrapper with a C++ instance.
767  ///
768  /// # Safety
769  ///
770  /// The `TAG` must be unique to the caller within the heap.
771  #[inline(always)]
772  pub unsafe fn wrap<const TAG: u16, T: GarbageCollected>(
773    isolate: &mut Isolate,
774    wrapper: Local<Object>,
775    value: &impl GetRustObj<T>,
776  ) {
777    const {
778      assert!(TAG < LAST_TAG);
779    }
780    let ptr = value.get_rust_obj();
781    unsafe { v8__Object__Wrap(isolate.as_real_ptr(), &*wrapper, ptr, TAG) }
782  }
783
784  /// Unwraps a JS wrapper object.
785  ///
786  /// # Safety
787  ///
788  /// The caller must ensure that the returned pointer is always stored on
789  /// the stack, or is safely moved into one of the other cppgc pointer types.
790  #[inline(always)]
791  pub unsafe fn unwrap<const TAG: u16, T: GarbageCollected>(
792    isolate: &mut Isolate,
793    wrapper: Local<Object>,
794  ) -> Option<UnsafePtr<T>> {
795    const {
796      assert!(TAG < LAST_TAG);
797    }
798    let ptr =
799      unsafe { v8__Object__Unwrap(isolate.as_real_ptr(), &*wrapper, TAG) };
800    unsafe { UnsafePtr::new(&ptr) }
801  }
802
803  /// Returns true if this object can be generally used to wrap object objects.
804  /// This means that the object either follows the convention of using embedder
805  /// fields to denote type/instance pointers or is using the Wrap()/Unwrap()
806  /// APIs for the same purpose. Returns false otherwise.
807  ///
808  /// Note that there may be other objects that use embedder fields but are not
809  /// used as API wrapper objects. E.g., v8::Promise may in certain configuration
810  /// use embedder fields but promises are not generally supported as API
811  /// wrappers. The method will return false in those cases.
812  #[inline(always)]
813  pub fn is_api_wrapper(&self) -> bool {
814    unsafe { v8__Object__IsApiWrapper(self) }
815  }
816
817  /// Sets the integrity level of the object.
818  #[inline(always)]
819  pub fn set_integrity_level(
820    &self,
821    scope: &PinScope<'_, '_>,
822    level: IntegrityLevel,
823  ) -> Option<bool> {
824    unsafe {
825      v8__Object__SetIntegrityLevel(self, &*scope.get_current_context(), level)
826    }
827    .into()
828  }
829
830  /// Sets the data in an internal field. Returns false when the index
831  /// is out of bounds, true otherwise.
832  #[inline(always)]
833  pub fn set_internal_field(&self, index: usize, data: Local<Data>) -> bool {
834    // Trying to access out-of-bounds internal fields makes V8 abort
835    // in debug mode and access out-of-bounds memory in release mode.
836    // The C++ API takes an i32 but doesn't check for indexes < 0, which
837    // results in an out-of-bounds access in both debug and release mode.
838    if index < self.internal_field_count()
839      && let Ok(index) = int::try_from(index)
840    {
841      unsafe { v8__Object__SetInternalField(self, index, &*data) };
842      return true;
843    }
844    false
845  }
846
847  /// Functionality for private properties.
848  /// This is an experimental feature, use at your own risk.
849  /// Note: Private properties are not inherited. Do not rely on this, since it
850  /// may change.
851  #[inline(always)]
852  pub fn get_private<'s>(
853    &self,
854    scope: &PinScope<'s, '_>,
855    key: Local<Private>,
856  ) -> Option<Local<'s, Value>> {
857    unsafe {
858      scope.cast_local(|sd| {
859        v8__Object__GetPrivate(self, sd.get_current_context(), &*key)
860      })
861    }
862  }
863
864  /// Functionality for private properties.
865  /// This is an experimental feature, use at your own risk.
866  /// Note: Private properties are not inherited. Do not rely on this, since it
867  /// may change.
868  #[inline(always)]
869  pub fn set_private(
870    &self,
871    scope: &PinScope<'_, '_>,
872    key: Local<Private>,
873    value: Local<Value>,
874  ) -> Option<bool> {
875    unsafe {
876      v8__Object__SetPrivate(
877        self,
878        &*scope.get_current_context(),
879        &*key,
880        &*value,
881      )
882    }
883    .into()
884  }
885
886  /// Functionality for private properties.
887  /// This is an experimental feature, use at your own risk.
888  /// Note: Private properties are not inherited. Do not rely on this, since it
889  /// may change.
890  #[inline(always)]
891  pub fn delete_private(
892    &self,
893    scope: &PinScope<'_, '_>,
894    key: Local<Private>,
895  ) -> Option<bool> {
896    unsafe {
897      v8__Object__DeletePrivate(self, &*scope.get_current_context(), &*key)
898    }
899    .into()
900  }
901
902  /// Functionality for private properties.
903  /// This is an experimental feature, use at your own risk.
904  /// Note: Private properties are not inherited. Do not rely on this, since it
905  /// may change.
906  #[inline(always)]
907  pub fn has_private(
908    &self,
909    scope: &PinScope<'_, '_>,
910    key: Local<Private>,
911  ) -> Option<bool> {
912    unsafe {
913      v8__Object__HasPrivate(self, &*scope.get_current_context(), &*key)
914    }
915    .into()
916  }
917
918  /// Gets the property attributes of a property which can be
919  /// [PropertyAttribute::NONE] or any combination of
920  /// [PropertyAttribute::READ_ONLY], [PropertyAttribute::DONT_ENUM] and
921  /// [PropertyAttribute::DONT_DELETE].
922  /// Returns [PropertyAttribute::NONE] when the property doesn't exist.
923  pub fn get_property_attributes(
924    &self,
925    scope: &PinScope<'_, '_>,
926    key: Local<Value>,
927  ) -> Option<PropertyAttribute> {
928    let mut out = Maybe::<PropertyAttribute>::default();
929    unsafe {
930      v8__Object__GetPropertyAttributes(
931        self,
932        &*scope.get_current_context(),
933        &*key,
934        &mut out,
935      );
936    };
937    out.into()
938  }
939
940  /// Implements Object.getOwnPropertyDescriptor(O, P), see
941  /// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor.
942  #[inline]
943  pub fn get_own_property_descriptor<'s>(
944    &self,
945    scope: &PinScope<'s, '_>,
946    key: Local<Name>,
947  ) -> Option<Local<'s, Value>> {
948    unsafe {
949      scope.cast_local(|sd| {
950        v8__Object__GetOwnPropertyDescriptor(
951          self,
952          sd.get_current_context(),
953          &*key,
954        )
955      })
956    }
957  }
958
959  /// If this object is a Set, Map, WeakSet or WeakMap, this returns a
960  /// representation of the elements of this object as an array.
961  /// If this object is a SetIterator or MapIterator, this returns all elements
962  /// of the underlying collection, starting at the iterator's current position.
963  ///
964  /// Also returns a boolean, indicating whether the returned array contains
965  /// key & values (for example when the value is Set.entries()).
966  #[inline]
967  pub fn preview_entries<'s>(
968    &self,
969    scope: &PinScope<'s, '_>,
970  ) -> (Option<Local<'s, Array>>, bool) {
971    let mut is_key_value = MaybeUninit::uninit();
972    unsafe {
973      let val = scope.cast_local(|_| {
974        v8__Object__PreviewEntries(self, is_key_value.as_mut_ptr())
975      });
976      let is_key_value = is_key_value.assume_init();
977
978      (val, is_key_value)
979    }
980  }
981
982  /// If result.IsEmpty() no real property was located on the object or
983  /// in the prototype chain.
984  /// This means interceptors in the prototype chain are not called.
985  #[inline(always)]
986  pub fn get_real_named_property<'s>(
987    &self,
988    scope: &PinScope<'s, '_>,
989    key: Local<Name>,
990  ) -> Option<Local<'s, Value>> {
991    unsafe {
992      scope.cast_local(|sd| {
993        v8__Object__GetRealNamedProperty(self, sd.get_current_context(), &*key)
994      })
995    }
996  }
997
998  #[inline(always)]
999  pub fn has_real_named_property(
1000    &self,
1001    scope: &PinScope<'_, '_>,
1002    key: Local<Name>,
1003  ) -> Option<bool> {
1004    unsafe {
1005      v8__Object__HasRealNamedProperty(
1006        self,
1007        &*scope.get_current_context(),
1008        &*key,
1009      )
1010    }
1011    .into()
1012  }
1013
1014  /// Gets the property attributes of a real property which can be
1015  /// None or any combination of ReadOnly, DontEnum and DontDelete.
1016  /// Interceptors in the prototype chain are not called.
1017  #[inline(always)]
1018  pub fn get_real_named_property_attributes(
1019    &self,
1020    scope: &PinScope<'_, '_>,
1021    key: Local<Name>,
1022  ) -> Option<PropertyAttribute> {
1023    let mut out = Maybe::<PropertyAttribute>::default();
1024    unsafe {
1025      v8__Object__GetRealNamedPropertyAttributes(
1026        self,
1027        &*scope.get_current_context(),
1028        &*key,
1029        &mut out,
1030      );
1031    }
1032    out.into()
1033  }
1034}
1035
1036/// Object integrity levels can be used to restrict what can be done to an
1037/// object's properties.
1038#[derive(Debug)]
1039#[repr(C)]
1040pub enum IntegrityLevel {
1041  /// Frozen objects are like Sealed objects, except all existing properties are
1042  /// also made non-writable.
1043  Frozen,
1044  /// Sealed objects prevent addition of any new property on the object, makes
1045  /// all existing properties non-configurable, meaning they cannot be deleted,
1046  /// have their enumerability, configurability, or writability changed.
1047  Sealed,
1048}
1049
1050impl Array {
1051  /// Creates a JavaScript array with the given length. If the length
1052  /// is negative the returned array will have length 0.
1053  #[inline(always)]
1054  pub fn new<'s>(scope: &PinScope<'s, '_>, length: i32) -> Local<'s, Array> {
1055    unsafe {
1056      scope.cast_local(|sd| v8__Array__New(sd.get_isolate_ptr(), length))
1057    }
1058    .unwrap()
1059  }
1060
1061  /// Creates a JavaScript array out of a Local<Value> array with a known
1062  /// length.
1063  #[inline(always)]
1064  pub fn new_with_elements<'s>(
1065    scope: &PinScope<'s, '_>,
1066    elements: &[Local<Value>],
1067  ) -> Local<'s, Array> {
1068    if elements.is_empty() {
1069      return Self::new(scope, 0);
1070    }
1071    let elements = Local::slice_into_raw(elements);
1072    unsafe {
1073      scope.cast_local(|sd| {
1074        v8__Array__New_with_elements(
1075          sd.get_isolate_ptr(),
1076          elements.as_ptr(),
1077          elements.len(),
1078        )
1079      })
1080    }
1081    .unwrap()
1082  }
1083
1084  #[inline(always)]
1085  pub fn length(&self) -> u32 {
1086    unsafe { v8__Array__Length(self) }
1087  }
1088}
1089
1090impl Map {
1091  #[inline(always)]
1092  pub fn new<'s>(scope: &PinScope<'s, '_>) -> Local<'s, Map> {
1093    unsafe { scope.cast_local(|sd| v8__Map__New(sd.get_isolate_ptr())) }
1094      .unwrap()
1095  }
1096
1097  #[inline(always)]
1098  pub fn size(&self) -> usize {
1099    unsafe { v8__Map__Size(self) }
1100  }
1101
1102  #[inline(always)]
1103  pub fn clear(&self) {
1104    unsafe { v8__Map__Clear(self) }
1105  }
1106
1107  #[inline(always)]
1108  pub fn get<'s>(
1109    &self,
1110    scope: &PinScope<'s, '_>,
1111    key: Local<Value>,
1112  ) -> Option<Local<'s, Value>> {
1113    unsafe {
1114      scope.cast_local(|sd| v8__Map__Get(self, sd.get_current_context(), &*key))
1115    }
1116  }
1117
1118  #[inline(always)]
1119  pub fn set<'s>(
1120    &self,
1121    scope: &PinScope<'s, '_>,
1122    key: Local<Value>,
1123    value: Local<Value>,
1124  ) -> Option<Local<'s, Map>> {
1125    unsafe {
1126      scope.cast_local(|sd| {
1127        v8__Map__Set(self, sd.get_current_context(), &*key, &*value)
1128      })
1129    }
1130  }
1131
1132  #[inline(always)]
1133  pub fn has(
1134    &self,
1135    scope: &PinScope<'_, '_>,
1136    key: Local<Value>,
1137  ) -> Option<bool> {
1138    unsafe { v8__Map__Has(self, &*scope.get_current_context(), &*key) }.into()
1139  }
1140
1141  #[inline(always)]
1142  pub fn delete(
1143    &self,
1144    scope: &PinScope<'_, '_>,
1145    key: Local<Value>,
1146  ) -> Option<bool> {
1147    unsafe { v8__Map__Delete(self, &*scope.get_current_context(), &*key) }
1148      .into()
1149  }
1150
1151  /// Returns an array of length size() * 2, where index N is the Nth key and
1152  /// index N + 1 is the Nth value.
1153  #[inline(always)]
1154  pub fn as_array<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Array> {
1155    unsafe { scope.cast_local(|_| v8__Map__As__Array(self)) }.unwrap()
1156  }
1157}
1158
1159impl Set {
1160  #[inline(always)]
1161  pub fn new<'s>(scope: &PinScope<'s, '_>) -> Local<'s, Set> {
1162    unsafe { scope.cast_local(|sd| v8__Set__New(sd.get_isolate_ptr())) }
1163      .unwrap()
1164  }
1165
1166  #[inline(always)]
1167  pub fn size(&self) -> usize {
1168    unsafe { v8__Set__Size(self) }
1169  }
1170
1171  #[inline(always)]
1172  pub fn clear(&self) {
1173    unsafe { v8__Set__Clear(self) }
1174  }
1175
1176  #[inline(always)]
1177  pub fn add<'s>(
1178    &self,
1179    scope: &PinScope<'s, '_>,
1180    key: Local<Value>,
1181  ) -> Option<Local<'s, Set>> {
1182    unsafe {
1183      scope.cast_local(|sd| v8__Set__Add(self, sd.get_current_context(), &*key))
1184    }
1185  }
1186
1187  #[inline(always)]
1188  pub fn has(
1189    &self,
1190    scope: &PinScope<'_, '_>,
1191    key: Local<Value>,
1192  ) -> Option<bool> {
1193    unsafe { v8__Set__Has(self, &*scope.get_current_context(), &*key) }.into()
1194  }
1195
1196  #[inline(always)]
1197  pub fn delete(
1198    &self,
1199    scope: &PinScope<'_, '_>,
1200    key: Local<Value>,
1201  ) -> Option<bool> {
1202    unsafe { v8__Set__Delete(self, &*scope.get_current_context(), &*key) }
1203      .into()
1204  }
1205
1206  /// Returns an array of length size() * 2, where index N is the Nth key and
1207  /// index N + 1 is the Nth value.
1208  #[inline(always)]
1209  pub fn as_array<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Array> {
1210    unsafe { scope.cast_local(|_| v8__Set__As__Array(self)) }.unwrap()
1211  }
1212}