Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ArrayBuffer::Detach() and ::IsDetached() #659

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions doc/array_buffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,20 @@ void* Napi::ArrayBuffer::Data() const;

Returns a pointer the wrapped data.

### Detach

```cpp
void Napi::ArrayBuffer::Detach();
```

Invokes the `ArrayBuffer` detach operation on a detachable `ArrayBuffer`.

### IsDetached

```cpp
bool Napi::ArrayBuffer::IsDetached() const;
```

Returns `true` if this `ArrayBuffer` has been detached.

[`Napi::Object`]: ./object.md
14 changes: 14 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,20 @@ inline size_t ArrayBuffer::ByteLength() {
return length;
}

#if NAPI_VERSION >= 7
inline bool ArrayBuffer::IsDetached() const {
bool detached;
napi_status status = napi_is_detached_arraybuffer(_env, _value, &detached);
NAPI_THROW_IF_FAILED(_env, status, false);
return detached;
}

inline void ArrayBuffer::Detach() {
napi_status status = napi_detach_arraybuffer(_env, _value);
NAPI_THROW_IF_FAILED_VOID(_env, status);
}
#endif // NAPI_VERSION >= 7

////////////////////////////////////////////////////////////////////////////////
// DataView class
////////////////////////////////////////////////////////////////////////////////
Expand Down
5 changes: 5 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,11 @@ namespace Napi {

void* Data(); ///< Gets a pointer to the data buffer.
size_t ByteLength(); ///< Gets the length of the array buffer in bytes.

#if NAPI_VERSION >= 7
bool IsDetached() const;
void Detach();
#endif // NAPI_VERSION >= 7
};

/// A JavaScript typed-array value with unknown array type.
Expand Down
38 changes: 31 additions & 7 deletions test/arraybuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,43 @@ void CheckDetachUpdatesData(const CallbackInfo& info) {
return;
}

if (!info[1].IsFunction()) {
Error::New(info.Env(), "A function was expected.").ThrowAsJavaScriptException();
return;
}

ArrayBuffer buffer = info[0].As<ArrayBuffer>();
Function detach = info[1].As<Function>();

// This potentially causes the buffer to cache its data pointer and length.
buffer.Data();
buffer.ByteLength();

detach.Call({});
#if NAPI_VERSION >= 7
if (buffer.IsDetached()) {
Error::New(info.Env(), "Buffer should not be detached.").ThrowAsJavaScriptException();
return;
}
#endif

if (info.Length() == 2) {
// Detach externally (in JavaScript).
if (!info[1].IsFunction()) {
Error::New(info.Env(), "A function was expected.").ThrowAsJavaScriptException();
return;
}

Function detach = info[1].As<Function>();
detach.Call({});
} else {
#if NAPI_VERSION >= 7
// Detach directly.
buffer.Detach();
#else
return;
#endif
}

#if NAPI_VERSION >= 7
if (!buffer.IsDetached()) {
Error::New(info.Env(), "Buffer should be detached.").ThrowAsJavaScriptException();
return;
}
#endif

if (buffer.Data() != nullptr) {
Error::New(info.Env(), "Incorrect data pointer.").ThrowAsJavaScriptException();
Expand Down
5 changes: 5 additions & 0 deletions test/arraybuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,13 @@ function test(binding) {

'ArrayBuffer updates data pointer and length when detached',
() => {
// Detach the ArrayBuffer in JavaScript.
const mem = new WebAssembly.Memory({ initial: 1 });
binding.arraybuffer.checkDetachUpdatesData(mem.buffer, () => mem.grow(1));

// Let C++ detach the ArrayBuffer.
const extBuffer = binding.arraybuffer.createExternalBuffer();
binding.arraybuffer.checkDetachUpdatesData(extBuffer);
},
]);
}