Skip to content

Commit

Permalink
util: add isArrayBufferDetached method
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Nov 19, 2022
1 parent c74dbd2 commit 81b13d1
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 20 deletions.
17 changes: 17 additions & 0 deletions doc/api/util.md
Expand Up @@ -2024,6 +2024,23 @@ util.types.isAnyArrayBuffer(new ArrayBuffer()); // Returns true
util.types.isAnyArrayBuffer(new SharedArrayBuffer()); // Returns true
```
### `util.types.isArrayBufferDetached(value)`
<!-- YAML
added: REPLACEME
-->
* `value` {any}
* Returns: {boolean}
Returns `true` if the value is a built-in [`ArrayBuffer`][] and
is detached.
```js
util.types.isArrayBufferDetached(null); // Returns false
util.types.isArrayBufferDetached(new ArrayBuffer()); // Returns false
```
### `util.types.isArrayBufferView(value)`
<!-- YAML
Expand Down
18 changes: 17 additions & 1 deletion lib/internal/util/types.js
Expand Up @@ -2,10 +2,18 @@

const {
ArrayBufferIsView,
ArrayBufferPrototype,
ObjectDefineProperties,
ReflectGet,
TypedArrayPrototypeGetSymbolToStringTag,
} = primordials;

const { isArrayBufferDetached: _isArrayBufferDetached, ...internalTypes } = internalBinding('types');

function ArrayBufferGetByteLength(view) {
return ReflectGet(ArrayBufferPrototype, 'byteLength', view);
}

function isTypedArray(value) {
return TypedArrayPrototypeGetSymbolToStringTag(value) !== undefined;
}
Expand Down Expand Up @@ -54,8 +62,16 @@ function isBigUint64Array(value) {
return TypedArrayPrototypeGetSymbolToStringTag(value) === 'BigUint64Array';
}

function isArrayBufferDetached(value) {
if (ArrayBufferGetByteLength(value) === 0) {
return _isArrayBufferDetached(value);
}
return false;
}

module.exports = {
...internalBinding('types'),
...internalTypes,
isArrayBufferDetached,
isArrayBufferView: ArrayBufferIsView,
isTypedArray,
isUint8Array,
Expand Down
6 changes: 3 additions & 3 deletions lib/internal/webstreams/readablestream.js
Expand Up @@ -43,6 +43,7 @@ const {
} = internalBinding('messaging');

const {
isArrayBufferDetached,
isArrayBufferView,
isDataView,
} = require('internal/util/types');
Expand Down Expand Up @@ -104,7 +105,6 @@ const {
extractHighWaterMark,
extractSizeAlgorithm,
lazyTransfer,
isDetachedBuffer,
isViewedArrayBufferDetached,
isBrandCheck,
resetQueue,
Expand Down Expand Up @@ -669,7 +669,7 @@ class ReadableStreamBYOBRequest {
const viewBuffer = ArrayBufferViewGetBuffer(view);
const viewBufferByteLength = ArrayBufferGetByteLength(viewBuffer);

if (isDetachedBuffer(viewBuffer)) {
if (isArrayBufferDetached(viewBuffer)) {
throw new ERR_INVALID_STATE.TypeError('Viewed ArrayBuffer is detached');
}

Expand Down Expand Up @@ -2643,7 +2643,7 @@ function readableByteStreamControllerEnqueue(controller, chunk) {
if (pendingPullIntos.length) {
const firstPendingPullInto = pendingPullIntos[0];

if (isDetachedBuffer(firstPendingPullInto.buffer)) {
if (isArrayBufferDetached(firstPendingPullInto.buffer)) {
throw new ERR_INVALID_STATE.TypeError(
'Destination ArrayBuffer is detached',
);
Expand Down
17 changes: 2 additions & 15 deletions lib/internal/webstreams/util.js
Expand Up @@ -32,6 +32,7 @@ const {
} = internalBinding('buffer');

const {
isArrayBufferDetached,
isPromise,
} = require('internal/util/types');

Expand Down Expand Up @@ -139,23 +140,10 @@ function transferArrayBuffer(buffer) {
return res;
}

function isDetachedBuffer(buffer) {
if (ArrayBufferGetByteLength(buffer) === 0) {
// TODO(daeyeon): Consider using C++ builtin to improve performance.
try {
new Uint8Array(buffer);
} catch (error) {
assert(error.name === 'TypeError');
return true;
}
}
return false;
}

function isViewedArrayBufferDetached(view) {
return (
ArrayBufferViewGetByteLength(view) === 0 &&
isDetachedBuffer(ArrayBufferViewGetBuffer(view))
isArrayBufferDetached(ArrayBufferViewGetBuffer(view))
);
}

Expand Down Expand Up @@ -256,7 +244,6 @@ module.exports = {
extractSizeAlgorithm,
lazyTransfer,
isBrandCheck,
isDetachedBuffer,
isPromisePending,
isViewedArrayBufferDetached,
peekQueueValue,
Expand Down
13 changes: 13 additions & 0 deletions src/node_types.cc
Expand Up @@ -61,6 +61,16 @@ static void IsBoxedPrimitive(const FunctionCallbackInfo<Value>& args) {
args[0]->IsSymbolObject());
}

static void IsArrayBufferDetached(const FunctionCallbackInfo<Value>& args) {
if (args[0]->IsArrayBuffer()) {
auto buffer = args[0].As<v8::ArrayBuffer>();
args.GetReturnValue().Set(buffer->WasDetached());
return;
}

args.GetReturnValue().Set(false);
}

void InitializeTypes(Local<Object> target,
Local<Value> unused,
Local<Context> context,
Expand All @@ -71,6 +81,8 @@ void InitializeTypes(Local<Object> target,

SetMethodNoSideEffect(context, target, "isAnyArrayBuffer", IsAnyArrayBuffer);
SetMethodNoSideEffect(context, target, "isBoxedPrimitive", IsBoxedPrimitive);
SetMethodNoSideEffect(
context, target, "isArrayBufferDetached", IsArrayBufferDetached);
}

} // anonymous namespace
Expand All @@ -82,6 +94,7 @@ void RegisterTypesExternalReferences(ExternalReferenceRegistry* registry) {

registry->Register(IsAnyArrayBuffer);
registry->Register(IsBoxedPrimitive);
registry->Register(IsArrayBufferDetached);
}
} // namespace node

Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-util-types.js
Expand Up @@ -56,7 +56,7 @@ for (const [ value, _method ] of [
for (const key of Object.keys(types)) {
if ((types.isArrayBufferView(value) ||
types.isAnyArrayBuffer(value)) && key.includes('Array') ||
key === 'isBoxedPrimitive') {
key === 'isBoxedPrimitive' || key === 'isArrayBufferDetached') {
continue;
}

Expand Down
1 change: 1 addition & 0 deletions typings/internalBinding/types.d.ts
Expand Up @@ -5,6 +5,7 @@ declare function InternalBinding(binding: 'types'): {
isArrayBuffer(value: unknown): value is ArrayBuffer;
isArgumentsObject(value: unknown): value is ArrayLike<unknown>;
isBoxedPrimitive(value: unknown): value is (BigInt | Boolean | Number | String | Symbol);
isArrayBufferDetached(value: unknown): boolean;
isDataView(value: unknown): value is DataView;
isExternal(value: unknown): value is Object;
isMap(value: unknown): value is Map<unknown, unknown>;
Expand Down

0 comments on commit 81b13d1

Please sign in to comment.