2021-01-10 21:59:07 -05:00
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
2021-02-04 17:18:32 -05:00
"use strict" ;
2019-03-26 08:22:07 -04:00
2020-03-28 13:03:49 -04:00
( ( window ) => {
2019-08-05 07:23:41 -04:00
// Available on start due to bindings.
2020-05-12 11:09:28 -04:00
const core = window . Deno . core ;
const { recv , send } = core ;
2019-03-26 08:22:07 -04:00
2020-06-21 10:34:43 -04:00
let opsCache = { } ;
2021-03-31 10:37:38 -04:00
const errorMap = { } ;
let nextPromiseId = 1 ;
2021-04-07 08:38:54 -04:00
const promiseMap = new Map ( ) ;
const RING _SIZE = 4 * 1024 ;
const NO _PROMISE = null ; // Alias to null is faster than plain nulls
const promiseRing = new Array ( RING _SIZE ) . fill ( NO _PROMISE ) ;
2019-04-24 21:43:06 -04:00
function init ( ) {
2020-05-12 11:09:28 -04:00
recv ( handleAsyncMsgFromRust ) ;
2019-04-24 21:43:06 -04:00
}
2019-03-14 19:17:52 -04:00
2021-04-07 08:38:54 -04:00
function setPromise ( promiseId ) {
const idx = promiseId % RING _SIZE ;
// Move old promise from ring to map
const oldPromise = promiseRing [ idx ] ;
if ( oldPromise !== NO _PROMISE ) {
const oldPromiseId = promiseId - RING _SIZE ;
promiseMap . set ( oldPromiseId , oldPromise ) ;
}
// Set new promise
return promiseRing [ idx ] = newPromise ( ) ;
}
function getPromise ( promiseId ) {
// Check if out of ring bounds, fallback to map
const outOfBounds = promiseId < nextPromiseId - RING _SIZE ;
if ( outOfBounds ) {
const promise = promiseMap . get ( promiseId ) ;
promiseMap . delete ( promiseId ) ;
return promise ;
}
// Otherwise take from ring
const idx = promiseId % RING _SIZE ;
const promise = promiseRing [ idx ] ;
promiseRing [ idx ] = NO _PROMISE ;
return promise ;
}
function newPromise ( ) {
let resolve , reject ;
const promise = new Promise ( ( resolve _ , reject _ ) => {
resolve = resolve _ ;
reject = reject _ ;
} ) ;
promise . resolve = resolve ;
promise . reject = reject ;
return promise ;
}
2019-09-30 14:59:44 -04:00
function ops ( ) {
2020-01-02 07:48:46 -05:00
// op id 0 is a special value to retrieve the map of registered ops.
2021-03-31 10:37:38 -04:00
const newOpsCache = Object . fromEntries ( send ( 0 ) ) ;
opsCache = Object . freeze ( newOpsCache ) ;
return opsCache ;
2019-03-14 19:17:52 -04:00
}
2021-03-31 10:37:38 -04:00
function handleAsyncMsgFromRust ( ) {
for ( let i = 0 ; i < arguments . length ; i += 2 ) {
opAsyncHandler ( arguments [ i ] , arguments [ i + 1 ] ) ;
2019-03-14 19:17:52 -04:00
}
}
2021-03-31 10:37:38 -04:00
function dispatch ( opName , promiseId , control , zeroCopy ) {
return send ( opsCache [ opName ] , promiseId , control , zeroCopy ) ;
2019-03-14 19:17:52 -04:00
}
2021-03-20 12:51:08 -04:00
function registerErrorClass ( errorName , className , args ) {
if ( typeof errorMap [ errorName ] !== "undefined" ) {
throw new TypeError ( ` Error class for " ${ errorName } " already registered ` ) ;
}
errorMap [ errorName ] = [ className , args ? ? [ ] ] ;
}
2021-03-31 10:37:38 -04:00
function getErrorClassAndArgs ( errorName ) {
return errorMap [ errorName ] ? ? [ undefined , [ ] ] ;
2019-03-14 19:17:52 -04:00
}
2021-03-31 10:37:38 -04:00
function processResponse ( res ) {
2021-04-01 07:24:30 -04:00
if ( ! isErr ( res ) ) {
return res ;
2021-02-23 07:08:50 -05:00
}
2021-04-01 07:24:30 -04:00
throw processErr ( res ) ;
}
// .$err_class_name is a special key that should only exist on errors
function isErr ( res ) {
return ! ! ( res && res . $err _class _name ) ;
2019-03-14 19:17:52 -04:00
}
2021-03-31 10:37:38 -04:00
function processErr ( err ) {
2021-04-01 07:24:30 -04:00
const className = err . $err _class _name ;
const [ ErrorClass , args ] = getErrorClassAndArgs ( className ) ;
2021-03-31 10:37:38 -04:00
if ( ! ErrorClass ) {
return new Error (
2021-04-01 07:24:30 -04:00
` Unregistered error class: " ${ className } " \n ${ err . message } \n Classes of errors returned from ops should be registered via Deno.core.registerErrorClass(). ` ,
2021-03-31 10:37:38 -04:00
) ;
2020-08-07 16:47:18 -04:00
}
2021-03-31 10:37:38 -04:00
return new ErrorClass ( err . message , ... args ) ;
2020-08-07 16:47:18 -04:00
}
2021-03-31 10:37:38 -04:00
function jsonOpAsync ( opName , args = null , zeroCopy = null ) {
const promiseId = nextPromiseId ++ ;
const maybeError = dispatch ( opName , promiseId , args , zeroCopy ) ;
// Handle sync error (e.g: error parsing args)
if ( maybeError ) processResponse ( maybeError ) ;
2021-04-07 08:38:54 -04:00
return setPromise ( promiseId ) ;
2020-08-07 16:47:18 -04:00
}
2021-03-31 10:37:38 -04:00
function jsonOpSync ( opName , args = null , zeroCopy = null ) {
return processResponse ( dispatch ( opName , null , args , zeroCopy ) ) ;
2020-08-20 09:45:59 -04:00
}
2021-03-31 10:37:38 -04:00
function opAsyncHandler ( promiseId , res ) {
2021-04-07 08:38:54 -04:00
const promise = getPromise ( promiseId ) ;
2021-04-01 07:24:30 -04:00
if ( ! isErr ( res ) ) {
promise . resolve ( res ) ;
2021-03-20 12:51:08 -04:00
} else {
2021-04-01 07:24:30 -04:00
promise . reject ( processErr ( res ) ) ;
2021-03-20 12:51:08 -04:00
}
}
2021-03-31 10:37:38 -04:00
function binOpSync ( opName , args = null , zeroCopy = null ) {
return jsonOpSync ( opName , args , zeroCopy ) ;
2021-03-20 12:51:08 -04:00
}
2021-03-31 10:37:38 -04:00
function binOpAsync ( opName , args = null , zeroCopy = null ) {
return jsonOpAsync ( opName , args , zeroCopy ) ;
2020-08-20 09:45:59 -04:00
}
2020-09-17 12:09:50 -04:00
function resources ( ) {
2021-04-05 23:17:00 -04:00
return Object . fromEntries ( jsonOpSync ( "op_resources" ) ) ;
2020-09-17 12:09:50 -04:00
}
2021-03-31 10:37:38 -04:00
2020-09-17 12:09:50 -04:00
function close ( rid ) {
2021-04-05 23:17:00 -04:00
jsonOpSync ( "op_close" , rid ) ;
2020-09-17 12:09:50 -04:00
}
2020-05-12 11:09:28 -04:00
Object . assign ( window . Deno . core , {
2021-03-20 12:51:08 -04:00
binOpAsync ,
binOpSync ,
2021-03-31 10:37:38 -04:00
jsonOpAsync ,
jsonOpSync ,
dispatch : send ,
dispatchByName : dispatch ,
2020-05-12 11:09:28 -04:00
ops ,
2020-09-17 12:09:50 -04:00
close ,
resources ,
2020-08-07 16:47:18 -04:00
registerErrorClass ,
2021-03-31 10:37:38 -04:00
init ,
2020-05-12 11:09:28 -04:00
} ) ;
2019-04-24 21:43:06 -04:00
} ) ( this ) ;