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