char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
067c81e
main
1import { 2ArrayBufferPrototypeGetResizable as resizable , 3Map , 4MapPrototypeDelete as mapDelete , 5MapPrototypeGet as mapGet , 6MapPrototypeSet as mapSet , 7ObjectDefineProperty as define , 8ReflectApply as apply , 9TypedArrayPrototypeGetBuffer as buffer , 10TypedArrayPrototypeGetTag as tag , 11TypeError , 12Uint8Array , 13} from "ext:core/primordials" ; 14import { 15op_wasm_streaming_abort as abort , 16op_wasm_streaming_finish as finish , 17op_wasm_streaming_register as register , 18op_wasm_streaming_url as setUrl , 19op_wasm_streaming_write as write , 20} from "ext:core/ops" ; 21import { markPromiseHandled , safePromise } from "ext:core/promises" ; 22import { onRuntimeStart } from "ext:core/bootstrap" ; 23import { messageState , usable } from "ext:http_types/body.js" ; 24import { getHeader } from "ext:http_types/headers.js" ; 25import { extractMime } from "ext:http_types/mime.js" ; 26import { 27read , 28readerCancel , 29release , 30streamReader , 31} from "ext:webstreams/streams.js" ; 32import type { 33ReadableStreamDefaultReader , 34} from "ext:webstreams/streams.js" ; 35import type { ResponseState } from "ext:http_types/body.js" ; 36import type { 37CompileOptions , 38CompileStreaming , 39Imports , 40InstantiateStreaming , 41InstantiatedSource , 42WasmModule , 43WasmNamespace , 44} from "./types.js" ; 45 46declare const WebAssembly :WasmNamespace ; 47 48let wasm :WasmNamespace ; 49let nativeCompileStreaming :CompileStreaming ; 50let nativeInstantiateStreaming :InstantiateStreaming ; 51const pending = new Map < unknown , unknown >(); 52const maxToken = 9_007_199_254_740_991 ; 53let nextToken = 0 ; 54 55function setLength < T extends Function > ( fn :T , name :string , length :number ) :T { 56define ( fn , "name" , { value :name }); 57define ( fn , "length" , { value :length }); 58return fn ; 59} 60 61async function consume ( id :number , source :unknown ) :Promise < void > { 62let reader :ReadableStreamDefaultReader < unknown > | undefined ; 63let body :ResponseState [ "body" ]; 64try { 65const state :ResponseState = messageState ( source , "response" ); 66body = state . body ; 67setUrl ([ id , state . url ]); 68usable ( body ); 69if ( body . stream === null ) { 70finish ( id ); 71return ; 72} 73body . used = true ; 74reader = streamReader ( body . stream ); 75while ( true ) { 76const result = await safePromise ( read ( reader )); 77if ( result . done ) break ; 78if ( tag ( result . value ) !== "Uint8Array" ) { 79throw new TypeError ( 80"Response body stream must contain Uint8Array chunks" , 81); 82} 83let bytes = result . value as Uint8Array < ArrayBufferLike >, copy :boolean ; 84try { 85copy = resizable ( buffer ( bytes )); 86} catch { 87copy = true ; 88} 89if ( copy ) bytes = new Uint8Array ( bytes ); 90write ( id , bytes as Uint8Array < ArrayBuffer >); 91} 92finish ( id ); 93} catch ( error ) { 94if ( reader !== undefined ) { 95try { 96markPromiseHandled ( readerCancel ( reader , error )); 97} catch ( error ) { 98void error ; 99} 100} 101try { 102abort ( id , error ); 103} catch ( error ) { 104void error ; 105} 106} finally { 107if ( reader !== undefined ) { 108try { 109release ( reader ); 110} catch ( error ) { 111void error ; 112} 113} 114} 115} 116 117function onNativeStart ( token :unknown , id :number ) :void { 118const response = mapGet ( pending , token ); 119mapDelete ( pending , token ); 120if ( response === undefined ) { 121abort ( id , new TypeError ( "Missing WebAssembly streaming response" )); 122return ; 123} 124consume ( id , response ); 125} 126 127interface StreamingState { 128active :boolean ; 129token :string | undefined ; 130} 131 132async function validatedSource ( 133source :unknown , 134state :StreamingState , 135) :Promise < string > { 136const response = await safePromise ( source ); 137if ( ! state . active ) return "avril-wasm-stream-inactive" ; 138const responseState = messageState ( response , "response" ); 139if ( responseState . status < 200 || responseState . status > 299 ) { 140throw new TypeError ( "WebAssembly response status is not successful" ); 141} 142const mime = extractMime ( getHeader ( responseState . headers , "content-type" )); 143if ( mime ?. essence !== "application/wasm" ) { 144throw new TypeError ( "WebAssembly response has an invalid MIME type" ); 145} 146if ( nextToken >= maxToken ) { 147throw new TypeError ( "WebAssembly streaming token space exhausted" ); 148} 149const token = `avril-wasm-stream- ${ ++ nextToken } ` ; 150state . token = token ; 151mapSet ( pending , token , response ); 152return token ; 153} 154 155async function streamingCall < T > ( 156source :unknown , 157invoke :( sourcePromise :unknown ) => T , 158) :Promise < Awaited < T >> { 159const state :StreamingState = { active :true , token :undefined }; 160const sourcePromise = validatedSource ( source , state ); 161markPromiseHandled ( sourcePromise ); 162try { 163return await safePromise ( invoke ( safePromise ( sourcePromise ))); 164} finally { 165state . active = false ; 166if ( state . token !== undefined ) mapDelete ( pending , state . token ); 167} 168} 169const methods :{ 170compileStreaming :CompileStreaming ; 171instantiateStreaming :InstantiateStreaming ; 172} = { 173compileStreaming ( source :unknown , options ?:CompileOptions ) { 174return streamingCall ( 175source , 176( sourcePromise ) => 177apply ( nativeCompileStreaming , wasm , [ sourcePromise , options ]) as Promise < 178WasmModule 179>, 180); 181}, 182instantiateStreaming ( 183source :unknown , 184imports ?:Imports , 185options ?:CompileOptions , 186) { 187return streamingCall ( 188source , 189( sourcePromise ) => 190apply ( nativeInstantiateStreaming , wasm , [ 191sourcePromise , 192imports , 193options , 194]) as Promise < InstantiatedSource >, 195); 196}, 197}; 198const { compileStreaming, instantiateStreaming} = methods ; 199 200onRuntimeStart (() => { 201// V8 exposes WebAssembly only in live contexts, not snapshot-building contexts. 202wasm = WebAssembly ; 203nativeCompileStreaming = wasm . compileStreaming ; 204nativeInstantiateStreaming = wasm . instantiateStreaming ; 205register ( onNativeStart ); 206define ( wasm , "compileStreaming" , { 207value :setLength ( compileStreaming , "compileStreaming" , 1 ), 208writable :true , 209enumerable :true , 210configurable :true , 211}); 212define ( wasm , "instantiateStreaming" , { 213value :setLength ( instantiateStreaming , "instantiateStreaming" , 2 ), 214writable :true , 215enumerable :true , 216configurable :true , 217}); 218});