1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-01 09:24:20 -04:00
denoland-deno/runtime/js/10_dispatch_buffer.js

151 lines
4.8 KiB
JavaScript
Raw Normal View History

// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
"use strict";
((window) => {
const core = window.Deno.core;
function assert(cond) {
if (!cond) {
throw Error("assert");
}
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// General async handling //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// General Async response handling
let nextRequestId = 1;
const promiseTable = {};
function opAsync(opName, opRequestBuilder, opResultParser) {
// Make sure requests of this type are handled by the asyncHandler
// The asyncHandler's role is to call the "promiseTable[requestId]" function
core.setAsyncHandlerByName(opName, (bufUi8, _) => {
const [requestId, result, error] = opResultParser(bufUi8, true);
if (error !== null) {
promiseTable[requestId][1](error);
} else {
promiseTable[requestId][0](result);
}
delete promiseTable[requestId];
});
const requestId = nextRequestId++;
// Create and store promise
const promise = new Promise((resolve, reject) => {
promiseTable[requestId] = [resolve, reject];
});
// Synchronously dispatch async request
core.dispatchByName(opName, ...opRequestBuilder(requestId));
// Wait for async response
return promise;
}
function opSync(opName, opRequestBuilder, opResultParser) {
const rawResult = core.dispatchByName(opName, ...opRequestBuilder());
const [_, result, error] = opResultParser(rawResult, false);
if (error !== null) throw error;
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Error handling /////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
function handleError(className, message) {
const [ErrorClass, args] = core.getErrorClassAndArgs(className);
if (!ErrorClass) {
return new Error(
`Unregistered error class: "${className}"\n` +
` ${message}\n` +
` Classes of errors returned from ops should be registered via Deno.core.registerErrorClass().`,
);
}
return new ErrorClass(message, ...args);
}
////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Buffer ops handling //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
const scratchBytes = new ArrayBuffer(3 * 4);
const scratchView = new DataView(
scratchBytes,
scratchBytes.byteOffset,
scratchBytes.byteLength,
);
function bufferOpBuildRequest(requestId, argument, zeroCopy) {
scratchView.setBigUint64(0, BigInt(requestId), true);
scratchView.setUint32(8, argument, true);
return [scratchView, ...zeroCopy];
}
function bufferOpParseResult(bufUi8, isCopyNeeded) {
// Decode header value from ui8 buffer
const headerByteLength = 4 * 4;
assert(bufUi8.byteLength >= headerByteLength);
assert(bufUi8.byteLength % 4 == 0);
const view = new DataView(
bufUi8.buffer,
bufUi8.byteOffset + bufUi8.byteLength - headerByteLength,
headerByteLength,
);
const requestId = Number(view.getBigUint64(0, true));
const status = view.getUint32(8, true);
const result = view.getUint32(12, true);
// Error handling
if (status !== 0) {
const className = core.decode(bufUi8.subarray(0, result));
const message = core.decode(bufUi8.subarray(result, -headerByteLength))
.trim();
return [requestId, null, handleError(className, message)];
}
if (bufUi8.byteLength === headerByteLength) {
return [requestId, result, null];
}
// Rest of response buffer is passed as reference or as a copy
let respBuffer = null;
if (isCopyNeeded) {
// Copy part of the response array (if sent through shared array buf)
respBuffer = bufUi8.slice(0, result);
} else {
// Create view on existing array (if sent through overflow)
respBuffer = bufUi8.subarray(0, result);
}
return [requestId, respBuffer, null];
}
function bufferOpAsync(opName, argument = 0, ...zeroCopy) {
return opAsync(
opName,
(requestId) => bufferOpBuildRequest(requestId, argument, zeroCopy),
bufferOpParseResult,
);
}
function bufferOpSync(opName, argument = 0, ...zeroCopy) {
return opSync(
opName,
() => bufferOpBuildRequest(0, argument, zeroCopy),
bufferOpParseResult,
);
}
window.__bootstrap.dispatchBuffer = {
bufferOpSync,
bufferOpAsync,
};
})(this);