Skip to content

Commit 82eb56a

Browse files
committed
feat: sync node-addon-api
1 parent 596e322 commit 82eb56a

2 files changed

Lines changed: 333 additions & 14 deletions

File tree

include/napi-inl.h

Lines changed: 242 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@
1818
#if NAPI_HAS_THREADS
1919
#include <mutex>
2020
#endif // NAPI_HAS_THREADS
21+
#include <string_view>
2122
#include <type_traits>
2223
#include <utility>
2324

25+
#if defined(__clang__) || defined(__GNUC__)
26+
#define NAPI_NO_SANITIZE_VPTR __attribute__((no_sanitize("vptr")))
27+
#else
28+
#define NAPI_NO_SANITIZE_VPTR
29+
#endif
30+
2431
namespace Napi {
2532

2633
#ifdef NAPI_CPP_CUSTOM_NAMESPACE
@@ -939,6 +946,19 @@ inline bool Value::IsExternal() const {
939946
return Type() == napi_external;
940947
}
941948

949+
#ifdef NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER
950+
inline bool Value::IsSharedArrayBuffer() const {
951+
if (IsEmpty()) {
952+
return false;
953+
}
954+
955+
bool result;
956+
napi_status status = node_api_is_sharedarraybuffer(_env, _value, &result);
957+
NAPI_THROW_IF_FAILED(_env, status, false);
958+
return result;
959+
}
960+
#endif
961+
942962
template <typename T>
943963
inline T Value::As() const {
944964
#ifdef NODE_ADDON_API_ENABLE_TYPE_CHECK_ON_AS
@@ -1185,6 +1205,13 @@ inline Date Date::New(napi_env env, double val) {
11851205
return Date(env, value);
11861206
}
11871207

1208+
inline Date Date::New(napi_env env, std::chrono::system_clock::time_point tp) {
1209+
using namespace std::chrono;
1210+
auto ms = static_cast<double>(
1211+
duration_cast<milliseconds>(tp.time_since_epoch()).count());
1212+
return Date::New(env, ms);
1213+
}
1214+
11881215
inline void Date::CheckCast(napi_env env, napi_value value) {
11891216
NAPI_CHECK(value != nullptr, "Date::CheckCast", "empty value");
11901217

@@ -1241,6 +1268,10 @@ inline String String::New(napi_env env, const std::u16string& val) {
12411268
return String::New(env, val.c_str(), val.size());
12421269
}
12431270

1271+
inline String String::New(napi_env env, std::string_view val) {
1272+
return String::New(env, val.data(), val.size());
1273+
}
1274+
12441275
inline String String::New(napi_env env, const char* val) {
12451276
// TODO(@gabrielschulhof) Remove if-statement when core's error handling is
12461277
// available in all supported versions.
@@ -1350,6 +1381,11 @@ inline Symbol Symbol::New(napi_env env, const std::string& description) {
13501381
return Symbol::New(env, descriptionValue);
13511382
}
13521383

1384+
inline Symbol Symbol::New(napi_env env, std::string_view description) {
1385+
napi_value descriptionValue = String::New(env, description);
1386+
return Symbol::New(env, descriptionValue);
1387+
}
1388+
13531389
inline Symbol Symbol::New(napi_env env, String description) {
13541390
napi_value descriptionValue = description;
13551391
return Symbol::New(env, descriptionValue);
@@ -1391,6 +1427,12 @@ inline MaybeOrValue<Symbol> Symbol::For(napi_env env,
13911427
return Symbol::For(env, descriptionValue);
13921428
}
13931429

1430+
inline MaybeOrValue<Symbol> Symbol::For(napi_env env,
1431+
std::string_view description) {
1432+
napi_value descriptionValue = String::New(env, description);
1433+
return Symbol::For(env, descriptionValue);
1434+
}
1435+
13941436
inline MaybeOrValue<Symbol> Symbol::For(napi_env env, const char* description) {
13951437
napi_value descriptionValue = String::New(env, description);
13961438
return Symbol::For(env, descriptionValue);
@@ -1952,6 +1994,19 @@ inline MaybeOrValue<bool> Object::Seal() const {
19521994
}
19531995
#endif // NAPI_VERSION >= 8
19541996

1997+
inline MaybeOrValue<Object> Object::GetPrototype() const {
1998+
napi_value result;
1999+
napi_status status = napi_get_prototype(_env, _value, &result);
2000+
NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, Object(_env, result), Object);
2001+
}
2002+
2003+
#ifdef NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE
2004+
inline MaybeOrValue<bool> Object::SetPrototype(const Object& value) const {
2005+
napi_status status = node_api_set_prototype(_env, _value, value);
2006+
NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool);
2007+
}
2008+
#endif
2009+
19552010
////////////////////////////////////////////////////////////////////////////////
19562011
// External class
19572012
////////////////////////////////////////////////////////////////////////////////
@@ -2073,6 +2128,55 @@ inline uint32_t Array::Length() const {
20732128
return result;
20742129
}
20752130

2131+
#ifdef NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER
2132+
////////////////////////////////////////////////////////////////////////////////
2133+
// SharedArrayBuffer class
2134+
////////////////////////////////////////////////////////////////////////////////
2135+
2136+
inline SharedArrayBuffer::SharedArrayBuffer() : Object() {}
2137+
2138+
inline SharedArrayBuffer::SharedArrayBuffer(napi_env env, napi_value value)
2139+
: Object(env, value) {}
2140+
2141+
inline void SharedArrayBuffer::CheckCast(napi_env env, napi_value value) {
2142+
NAPI_CHECK(value != nullptr, "SharedArrayBuffer::CheckCast", "empty value");
2143+
2144+
bool result;
2145+
napi_status status = node_api_is_sharedarraybuffer(env, value, &result);
2146+
NAPI_CHECK(status == napi_ok,
2147+
"SharedArrayBuffer::CheckCast",
2148+
"node_api_is_sharedarraybuffer failed");
2149+
NAPI_CHECK(
2150+
result, "SharedArrayBuffer::CheckCast", "value is not sharedarraybuffer");
2151+
}
2152+
2153+
inline SharedArrayBuffer SharedArrayBuffer::New(napi_env env,
2154+
size_t byteLength) {
2155+
napi_value value;
2156+
void* data;
2157+
napi_status status =
2158+
node_api_create_sharedarraybuffer(env, byteLength, &data, &value);
2159+
NAPI_THROW_IF_FAILED(env, status, SharedArrayBuffer());
2160+
2161+
return SharedArrayBuffer(env, value);
2162+
}
2163+
2164+
inline void* SharedArrayBuffer::Data() {
2165+
void* data;
2166+
napi_status status = napi_get_arraybuffer_info(_env, _value, &data, nullptr);
2167+
NAPI_THROW_IF_FAILED(_env, status, nullptr);
2168+
return data;
2169+
}
2170+
2171+
inline size_t SharedArrayBuffer::ByteLength() {
2172+
size_t length;
2173+
napi_status status =
2174+
napi_get_arraybuffer_info(_env, _value, nullptr, &length);
2175+
NAPI_THROW_IF_FAILED(_env, status, 0);
2176+
return length;
2177+
}
2178+
#endif // NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER
2179+
20762180
////////////////////////////////////////////////////////////////////////////////
20772181
// ArrayBuffer class
20782182
////////////////////////////////////////////////////////////////////////////////
@@ -2227,6 +2331,39 @@ inline DataView DataView::New(napi_env env,
22272331
return DataView(env, value);
22282332
}
22292333

2334+
#ifdef NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER
2335+
inline DataView DataView::New(napi_env env,
2336+
Napi::SharedArrayBuffer arrayBuffer) {
2337+
return New(env, arrayBuffer, 0, arrayBuffer.ByteLength());
2338+
}
2339+
2340+
inline DataView DataView::New(napi_env env,
2341+
Napi::SharedArrayBuffer arrayBuffer,
2342+
size_t byteOffset) {
2343+
if (byteOffset > arrayBuffer.ByteLength()) {
2344+
NAPI_THROW(RangeError::New(
2345+
env, "Start offset is outside the bounds of the buffer"),
2346+
DataView());
2347+
}
2348+
return New(
2349+
env, arrayBuffer, byteOffset, arrayBuffer.ByteLength() - byteOffset);
2350+
}
2351+
2352+
inline DataView DataView::New(napi_env env,
2353+
Napi::SharedArrayBuffer arrayBuffer,
2354+
size_t byteOffset,
2355+
size_t byteLength) {
2356+
if (byteOffset + byteLength > arrayBuffer.ByteLength()) {
2357+
NAPI_THROW(RangeError::New(env, "Invalid DataView length"), DataView());
2358+
}
2359+
napi_value value;
2360+
napi_status status =
2361+
napi_create_dataview(env, byteLength, arrayBuffer, byteOffset, &value);
2362+
NAPI_THROW_IF_FAILED(env, status, DataView());
2363+
return DataView(env, value);
2364+
}
2365+
#endif // NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER
2366+
22302367
inline void DataView::CheckCast(napi_env env, napi_value value) {
22312368
NAPI_CHECK(value != nullptr, "DataView::CheckCast", "empty value");
22322369

@@ -2250,15 +2387,19 @@ inline DataView::DataView(napi_env env, napi_value value) : Object(env, value) {
22502387
}
22512388

22522389
inline Napi::ArrayBuffer DataView::ArrayBuffer() const {
2390+
return Buffer().As<Napi::ArrayBuffer>();
2391+
}
2392+
2393+
inline Napi::Value DataView::Buffer() const {
22532394
napi_value arrayBuffer;
22542395
napi_status status = napi_get_dataview_info(_env,
22552396
_value /* dataView */,
22562397
nullptr /* byteLength */,
22572398
nullptr /* data */,
22582399
&arrayBuffer /* arrayBuffer */,
22592400
nullptr /* byteOffset */);
2260-
NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer());
2261-
return Napi::ArrayBuffer(_env, arrayBuffer);
2401+
NAPI_THROW_IF_FAILED(_env, status, Napi::Value());
2402+
return Napi::Value(_env, arrayBuffer);
22622403
}
22632404

22642405
inline size_t DataView::ByteOffset() const {
@@ -2819,8 +2960,95 @@ inline void Promise::CheckCast(napi_env env, napi_value value) {
28192960
NAPI_CHECK(result, "Promise::CheckCast", "value is not promise");
28202961
}
28212962

2963+
inline Promise::Promise() : Object() {}
2964+
28222965
inline Promise::Promise(napi_env env, napi_value value) : Object(env, value) {}
28232966

2967+
inline MaybeOrValue<Promise> Promise::Then(napi_value onFulfilled) const {
2968+
EscapableHandleScope scope(_env);
2969+
#ifdef NODE_ADDON_API_ENABLE_MAYBE
2970+
Value thenMethod;
2971+
if (!Get("then").UnwrapTo(&thenMethod)) {
2972+
return Nothing<Promise>();
2973+
}
2974+
MaybeOrValue<Value> result =
2975+
thenMethod.As<Function>().Call(*this, {onFulfilled});
2976+
if (result.IsJust()) {
2977+
return Just(scope.Escape(result.Unwrap()).As<Promise>());
2978+
}
2979+
return Nothing<Promise>();
2980+
#else
2981+
Function thenMethod = Get("then").As<Function>();
2982+
MaybeOrValue<Value> result = thenMethod.Call(*this, {onFulfilled});
2983+
if (scope.Env().IsExceptionPending()) {
2984+
return Promise();
2985+
}
2986+
return scope.Escape(result).As<Promise>();
2987+
#endif
2988+
}
2989+
2990+
inline MaybeOrValue<Promise> Promise::Then(napi_value onFulfilled,
2991+
napi_value onRejected) const {
2992+
EscapableHandleScope scope(_env);
2993+
#ifdef NODE_ADDON_API_ENABLE_MAYBE
2994+
Value thenMethod;
2995+
if (!Get("then").UnwrapTo(&thenMethod)) {
2996+
return Nothing<Promise>();
2997+
}
2998+
MaybeOrValue<Value> result =
2999+
thenMethod.As<Function>().Call(*this, {onFulfilled, onRejected});
3000+
if (result.IsJust()) {
3001+
return Just(scope.Escape(result.Unwrap()).As<Promise>());
3002+
}
3003+
return Nothing<Promise>();
3004+
#else
3005+
Function thenMethod = Get("then").As<Function>();
3006+
MaybeOrValue<Value> result =
3007+
thenMethod.Call(*this, {onFulfilled, onRejected});
3008+
if (scope.Env().IsExceptionPending()) {
3009+
return Promise();
3010+
}
3011+
return scope.Escape(result).As<Promise>();
3012+
#endif
3013+
}
3014+
3015+
inline MaybeOrValue<Promise> Promise::Catch(napi_value onRejected) const {
3016+
EscapableHandleScope scope(_env);
3017+
#ifdef NODE_ADDON_API_ENABLE_MAYBE
3018+
Value catchMethod;
3019+
if (!Get("catch").UnwrapTo(&catchMethod)) {
3020+
return Nothing<Promise>();
3021+
}
3022+
MaybeOrValue<Value> result =
3023+
catchMethod.As<Function>().Call(*this, {onRejected});
3024+
if (result.IsJust()) {
3025+
return Just(scope.Escape(result.Unwrap()).As<Promise>());
3026+
}
3027+
return Nothing<Promise>();
3028+
#else
3029+
Function catchMethod = Get("catch").As<Function>();
3030+
MaybeOrValue<Value> result = catchMethod.Call(*this, {onRejected});
3031+
if (scope.Env().IsExceptionPending()) {
3032+
return Promise();
3033+
}
3034+
return scope.Escape(result).As<Promise>();
3035+
#endif
3036+
}
3037+
3038+
inline MaybeOrValue<Promise> Promise::Then(const Function& onFulfilled) const {
3039+
return Then(static_cast<napi_value>(onFulfilled));
3040+
}
3041+
3042+
inline MaybeOrValue<Promise> Promise::Then(const Function& onFulfilled,
3043+
const Function& onRejected) const {
3044+
return Then(static_cast<napi_value>(onFulfilled),
3045+
static_cast<napi_value>(onRejected));
3046+
}
3047+
3048+
inline MaybeOrValue<Promise> Promise::Catch(const Function& onRejected) const {
3049+
return Catch(static_cast<napi_value>(onRejected));
3050+
}
3051+
28243052
////////////////////////////////////////////////////////////////////////////////
28253053
// Buffer<T> class
28263054
////////////////////////////////////////////////////////////////////////////////
@@ -3670,8 +3898,8 @@ inline MaybeOrValue<bool> ObjectReference::Set(const std::string& utf8name,
36703898
return Value().Set(utf8name, value);
36713899
}
36723900

3673-
inline MaybeOrValue<bool> ObjectReference::Set(const std::string& utf8name,
3674-
std::string& utf8value) const {
3901+
inline MaybeOrValue<bool> ObjectReference::Set(
3902+
const std::string& utf8name, const std::string& utf8value) const {
36753903
HandleScope scope(_env);
36763904
return Value().Set(utf8name, utf8value);
36773905
}
@@ -4653,7 +4881,8 @@ inline napi_value InstanceWrap<T>::WrappedMethod(
46534881
////////////////////////////////////////////////////////////////////////////////
46544882

46554883
template <typename T>
4656-
inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
4884+
inline NAPI_NO_SANITIZE_VPTR ObjectWrap<T>::ObjectWrap(
4885+
const Napi::CallbackInfo& callbackInfo) {
46574886
napi_env env = callbackInfo.Env();
46584887
napi_value wrapper = callbackInfo.This();
46594888
napi_status status;
@@ -4671,7 +4900,7 @@ inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
46714900
}
46724901

46734902
template <typename T>
4674-
inline ObjectWrap<T>::~ObjectWrap() {
4903+
inline NAPI_NO_SANITIZE_VPTR ObjectWrap<T>::~ObjectWrap() {
46754904
// If the JS object still exists at this point, remove the finalizer added
46764905
// through `napi_wrap()`.
46774906
if (!IsEmpty() && !_finalized) {
@@ -4684,8 +4913,12 @@ inline ObjectWrap<T>::~ObjectWrap() {
46844913
}
46854914
}
46864915

4916+
// with RTTI turned on, modern compilers check to see if virtual function
4917+
// pointers are stripped of RTTI by void casts. this is intrinsic to how Unwrap
4918+
// works, so we inject a compiler pragma to turn off that check just for the
4919+
// affected methods. this compiler check is on by default in Android NDK 29.
46874920
template <typename T>
4688-
inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
4921+
inline NAPI_NO_SANITIZE_VPTR T* ObjectWrap<T>::Unwrap(Object wrapper) {
46894922
void* unwrapped;
46904923
napi_status status = napi_unwrap(wrapper.Env(), wrapper, &unwrapped);
46914924
NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr);
@@ -6984,4 +7217,6 @@ inline void BasicEnv::PostFinalizer(FinalizerType finalizeCallback,
69847217

69857218
} // namespace Napi
69867219

7220+
#undef NAPI_NO_SANITIZE_VPTR
7221+
69877222
#endif // SRC_NAPI_INL_H_

0 commit comments

Comments
 (0)