1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::HandleScope;
use crate::Isolate;
use crate::Local;
use crate::String;
use crate::Symbol;
use crate::Value;

extern "C" {
  fn v8__Symbol__New(
    isolate: *mut Isolate,
    description: *const String,
  ) -> *const Symbol;
  fn v8__Symbol__ForApi(
    isolate: *mut Isolate,
    description: *const String,
  ) -> *const Symbol;
  fn v8__Symbol__Description(
    this: *const Symbol,
    isolate: *mut Isolate,
  ) -> *const Value;
}

macro_rules! well_known {
  ($name:ident, $binding:ident) => {
    pub fn $name<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, Symbol> {
      extern "C" {
        fn $binding(isolate: *mut Isolate) -> *const Symbol;
      }
      unsafe { scope.cast_local(|sd| $binding(sd.get_isolate_ptr())) }.unwrap()
    }
  };
}

impl Symbol {
  /// Create a symbol. If description is not empty, it will be used as the
  /// description.
  #[inline(always)]
  pub fn new<'s>(
    scope: &mut HandleScope<'s, ()>,
    description: Option<Local<String>>,
  ) -> Local<'s, Symbol> {
    unsafe {
      scope.cast_local(|sd| {
        v8__Symbol__New(
          sd.get_isolate_ptr(),
          description.map_or_else(std::ptr::null, |v| &*v),
        )
      })
    }
    .unwrap()
  }

  /// Access global symbol registry.
  /// Note that symbols created this way are never collected, so
  /// they should only be used for statically fixed properties.
  /// Also, there is only one global description space for the descriptions used as
  /// keys.
  /// To minimize the potential for clashes, use qualified descriptions as keys.
  /// Corresponds to v8::Symbol::For() in C++.
  #[inline(always)]
  pub fn for_global<'s>(
    scope: &mut HandleScope<'s, ()>,
    description: Local<String>,
  ) -> Local<'s, Symbol> {
    unsafe {
      scope.cast_local(|sd| {
        v8__Symbol__ForApi(sd.get_isolate_ptr(), &*description)
      })
    }
    .unwrap()
  }

  /// Returns the description string of the symbol, or undefined if none.
  #[inline(always)]
  pub fn description<'s>(
    &self,
    scope: &mut HandleScope<'s, ()>,
  ) -> Local<'s, Value> {
    unsafe {
      scope
        .cast_local(|sd| v8__Symbol__Description(&*self, sd.get_isolate_ptr()))
    }
    .unwrap()
  }

  well_known!(get_async_iterator, v8__Symbol__GetAsyncIterator);
  well_known!(get_has_instance, v8__Symbol__GetHasInstance);
  well_known!(get_is_concat_spreadable, v8__Symbol__GetIsConcatSpreadable);
  well_known!(get_iterator, v8__Symbol__GetIterator);
  well_known!(get_match, v8__Symbol__GetMatch);
  well_known!(get_replace, v8__Symbol__GetReplace);
  well_known!(get_search, v8__Symbol__GetSearch);
  well_known!(get_split, v8__Symbol__GetSplit);
  well_known!(get_to_primitive, v8__Symbol__GetToPrimitive);
  well_known!(get_to_string_tag, v8__Symbol__GetToStringTag);
  well_known!(get_unscopables, v8__Symbol__GetUnscopables);
}