[go: up one dir, main page]

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