circuitjson-toolkit 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/docs/api.md +19 -3
- package/docs/model-format.md +4 -4
- package/docs/release-notes-v1.4.2.md +32 -0
- package/package.json +2 -1
- package/src/core/SelfAdjustingComputation.mjs +89 -100
- package/src/core/context/CircuitJsonExtensionBoundary.mjs +1 -1
- package/src/core/context/StructuredCloneAdoption.mjs +9 -25
- package/src/core/context/StructuredCloneTextAccounting.mjs +38 -0
- package/src/core/contracts/DocumentResult.mjs +9 -0
- package/src/core/worker/NativeParserWorkerTransport.mjs +201 -0
- package/src/core/worker/ParserWorkerClient.mjs +18 -20
- package/src/core/worker/WorkerBinaryData.mjs +201 -0
- package/src/core/worker/WorkerRequestData.mjs +64 -213
- package/src/core/worker/WorkerResponseData.mjs +9 -2
- package/src/core/worker/WorkerResultShape.mjs +6 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { TOOLKIT_WORKER_PROTOCOL } from './ToolkitWorkerProtocol.mjs'
|
|
2
|
+
|
|
3
|
+
const REFLECT_APPLY = Reflect.apply
|
|
4
|
+
const REFLECT_CONSTRUCT = Reflect.construct
|
|
5
|
+
const REFLECT_OWN_KEYS = Reflect.ownKeys
|
|
6
|
+
const GET_PROTOTYPE = Object.getPrototypeOf
|
|
7
|
+
const GET_DESCRIPTORS = Object.getOwnPropertyDescriptors
|
|
8
|
+
const HAS_OWN = Object.hasOwn
|
|
9
|
+
const OBJECT_PROTOTYPE = Object.prototype
|
|
10
|
+
const WEAK_MAP_GET = WeakMap.prototype.get
|
|
11
|
+
const WEAK_MAP_SET = WeakMap.prototype.set
|
|
12
|
+
const WEAK_MAP_DELETE = WeakMap.prototype.delete
|
|
13
|
+
const WORKER_CONSTRUCTOR = globalThis.Worker
|
|
14
|
+
const WORKER_POST = WORKER_CONSTRUCTOR?.prototype?.postMessage
|
|
15
|
+
const WORKER_TERMINATE = WORKER_CONSTRUCTOR?.prototype?.terminate
|
|
16
|
+
const ADD_EVENT_LISTENER = EventTarget.prototype.addEventListener
|
|
17
|
+
const REMOVE_EVENT_LISTENER = EventTarget.prototype.removeEventListener
|
|
18
|
+
const MESSAGE_DATA = Object.getOwnPropertyDescriptor(
|
|
19
|
+
MessageEvent.prototype,
|
|
20
|
+
'data'
|
|
21
|
+
)?.get
|
|
22
|
+
const EVENT_CURRENT_TARGET = Object.getOwnPropertyDescriptor(
|
|
23
|
+
Event.prototype,
|
|
24
|
+
'currentTarget'
|
|
25
|
+
)?.get
|
|
26
|
+
const EVENT_TRUSTED =
|
|
27
|
+
Object.getOwnPropertyDescriptor(new Event('message'), 'isTrusted')?.get ||
|
|
28
|
+
Object.getOwnPropertyDescriptor(Event.prototype, 'isTrusted')?.get
|
|
29
|
+
const ERROR_DATA =
|
|
30
|
+
typeof ErrorEvent === 'function'
|
|
31
|
+
? Object.getOwnPropertyDescriptor(ErrorEvent.prototype, 'error')?.get
|
|
32
|
+
: null
|
|
33
|
+
const RECEIVED_RESULTS = new WeakMap()
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Keeps native workers and their unexposed structured-clone results private.
|
|
37
|
+
* A custom factory cannot mint the one-use result capabilities created here.
|
|
38
|
+
*/
|
|
39
|
+
export class NativeParserWorkerTransport {
|
|
40
|
+
#worker
|
|
41
|
+
#listeners = new Map()
|
|
42
|
+
#nativeListeners = new Map()
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Constructs an isolated transport using the captured native constructor.
|
|
46
|
+
* @param {string | URL} url Worker module URL.
|
|
47
|
+
*/
|
|
48
|
+
constructor(url) {
|
|
49
|
+
this.#worker = REFLECT_CONSTRUCT(WORKER_CONSTRUCTOR, [
|
|
50
|
+
url,
|
|
51
|
+
{ type: 'module' }
|
|
52
|
+
])
|
|
53
|
+
for (const type of ['message', 'error', 'messageerror']) {
|
|
54
|
+
const listener = (event) => this.#receive(type, event)
|
|
55
|
+
this.#nativeListeners.set(type, listener)
|
|
56
|
+
REFLECT_APPLY(ADD_EVENT_LISTENER, this.#worker, [type, listener])
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Uses private native transport only while the captured host is unchanged.
|
|
62
|
+
* Replaced or emulated Worker constructors retain generic validation.
|
|
63
|
+
* @param {string | URL} url Worker module URL.
|
|
64
|
+
* @returns {object} Browser-compatible worker transport.
|
|
65
|
+
*/
|
|
66
|
+
static create(url) {
|
|
67
|
+
const Constructor = globalThis.Worker
|
|
68
|
+
if (
|
|
69
|
+
Constructor !== WORKER_CONSTRUCTOR ||
|
|
70
|
+
typeof WORKER_POST !== 'function' ||
|
|
71
|
+
typeof WORKER_TERMINATE !== 'function' ||
|
|
72
|
+
!MESSAGE_DATA ||
|
|
73
|
+
!EVENT_CURRENT_TARGET ||
|
|
74
|
+
!EVENT_TRUSTED
|
|
75
|
+
) {
|
|
76
|
+
return REFLECT_CONSTRUCT(Constructor, [url, { type: 'module' }])
|
|
77
|
+
}
|
|
78
|
+
return new NativeParserWorkerTransport(url)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Consumes an opaque result exactly once. The returned data has never been
|
|
83
|
+
* exposed outside this transport; exposing it here destroys its capability.
|
|
84
|
+
* @param {unknown} token Result candidate.
|
|
85
|
+
* @returns {{ value: unknown } | null} Privately received data, if proven.
|
|
86
|
+
*/
|
|
87
|
+
static consumeResult(token) {
|
|
88
|
+
const received = REFLECT_APPLY(WEAK_MAP_GET, RECEIVED_RESULTS, [token])
|
|
89
|
+
if (!received) return null
|
|
90
|
+
REFLECT_APPLY(WEAK_MAP_DELETE, RECEIVED_RESULTS, [token])
|
|
91
|
+
return received
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** @param {string} type Event type. @param {Function} listener Listener. @returns {void} */
|
|
95
|
+
addEventListener(type, listener) {
|
|
96
|
+
if (!this.#listeners.has(type)) this.#listeners.set(type, new Set())
|
|
97
|
+
this.#listeners.get(type).add(listener)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** @param {string} type Event type. @param {Function} listener Listener. @returns {void} */
|
|
101
|
+
removeEventListener(type, listener) {
|
|
102
|
+
this.#listeners.get(type)?.delete(listener)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** @param {unknown} message Request. @param {Transferable[]} [transfer] Transfer list. @returns {void} */
|
|
106
|
+
postMessage(message, transfer = []) {
|
|
107
|
+
REFLECT_APPLY(WORKER_POST, this.#worker, [message, transfer])
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Detaches native listeners and terminates the private worker. @returns {void} */
|
|
111
|
+
terminate() {
|
|
112
|
+
for (const [type, listener] of this.#nativeListeners) {
|
|
113
|
+
REFLECT_APPLY(REMOVE_EVENT_LISTENER, this.#worker, [type, listener])
|
|
114
|
+
}
|
|
115
|
+
this.#nativeListeners.clear()
|
|
116
|
+
this.#listeners.clear()
|
|
117
|
+
REFLECT_APPLY(WORKER_TERMINATE, this.#worker, [])
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Hides the native target and result graph before invoking any consumer.
|
|
122
|
+
* Synthetic events and invalid envelopes never receive a capability.
|
|
123
|
+
* @param {string} type Event type.
|
|
124
|
+
* @param {Event} event Native event.
|
|
125
|
+
* @returns {void}
|
|
126
|
+
*/
|
|
127
|
+
#receive(type, event) {
|
|
128
|
+
let forwarded = {}
|
|
129
|
+
if (type === 'message') {
|
|
130
|
+
const data = REFLECT_APPLY(MESSAGE_DATA, event, [])
|
|
131
|
+
forwarded = { data }
|
|
132
|
+
if (
|
|
133
|
+
REFLECT_APPLY(EVENT_TRUSTED, event, []) === true &&
|
|
134
|
+
REFLECT_APPLY(EVENT_CURRENT_TARGET, event, []) === this.#worker
|
|
135
|
+
) {
|
|
136
|
+
try {
|
|
137
|
+
const message =
|
|
138
|
+
NativeParserWorkerTransport.#resultMessage(data)
|
|
139
|
+
if (message) {
|
|
140
|
+
const token = Object.freeze(Object.create(null))
|
|
141
|
+
REFLECT_APPLY(WEAK_MAP_SET, RECEIVED_RESULTS, [
|
|
142
|
+
token,
|
|
143
|
+
{ value: message.value }
|
|
144
|
+
])
|
|
145
|
+
message.value = token
|
|
146
|
+
forwarded = { data: message }
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
// The ordinary client boundary reports malformed envelopes.
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} else if (type === 'error') {
|
|
153
|
+
forwarded = {
|
|
154
|
+
error: ERROR_DATA ? REFLECT_APPLY(ERROR_DATA, event, []) : null
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (const listener of this.#listeners.get(type) || []) {
|
|
158
|
+
REFLECT_APPLY(listener, undefined, [forwarded])
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Captures only exact native result headers without calling replaceable
|
|
164
|
+
* exported helpers that could introduce caller-owned values into the graph.
|
|
165
|
+
* @param {unknown} data Privately received native event data.
|
|
166
|
+
* @returns {object | null} Result envelope safe to hide behind a capability.
|
|
167
|
+
*/
|
|
168
|
+
static #resultMessage(data) {
|
|
169
|
+
if (!data || typeof data !== 'object') return null
|
|
170
|
+
const prototype = GET_PROTOTYPE(data)
|
|
171
|
+
if (prototype !== OBJECT_PROTOTYPE && prototype !== null) return null
|
|
172
|
+
const descriptors = GET_DESCRIPTORS(data)
|
|
173
|
+
if (REFLECT_OWN_KEYS(descriptors).length !== 4) return null
|
|
174
|
+
for (const key of ['protocol', 'type', 'requestId', 'value']) {
|
|
175
|
+
const descriptor = descriptors[key]
|
|
176
|
+
if (
|
|
177
|
+
!descriptor ||
|
|
178
|
+
!HAS_OWN(descriptor, 'value') ||
|
|
179
|
+
descriptor.enumerable !== true
|
|
180
|
+
) {
|
|
181
|
+
return null
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const protocol = descriptors.protocol.value
|
|
185
|
+
const type = descriptors.type.value
|
|
186
|
+
const requestId = descriptors.requestId.value
|
|
187
|
+
if (
|
|
188
|
+
protocol !== TOOLKIT_WORKER_PROTOCOL ||
|
|
189
|
+
type !== 'result' ||
|
|
190
|
+
typeof requestId !== 'string' ||
|
|
191
|
+
!requestId ||
|
|
192
|
+
requestId.length > 256
|
|
193
|
+
) {
|
|
194
|
+
return null
|
|
195
|
+
}
|
|
196
|
+
return { protocol, type, requestId, value: descriptors.value.value }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
Object.freeze(NativeParserWorkerTransport.prototype)
|
|
201
|
+
Object.freeze(NativeParserWorkerTransport)
|
|
@@ -3,6 +3,7 @@ import { RuntimeProxyBoundary } from '../contracts/RuntimeProxyBoundary.mjs'
|
|
|
3
3
|
import { TOOLKIT_WORKER_PROTOCOL } from './ToolkitWorkerProtocol.mjs'
|
|
4
4
|
import { WorkerRequestData } from './WorkerRequestData.mjs'
|
|
5
5
|
import { WorkerResponseData } from './WorkerResponseData.mjs'
|
|
6
|
+
import { NativeParserWorkerTransport } from './NativeParserWorkerTransport.mjs'
|
|
6
7
|
|
|
7
8
|
const ABORTED_GETTER = Object.getOwnPropertyDescriptor(
|
|
8
9
|
AbortSignal.prototype,
|
|
@@ -73,14 +74,22 @@ export class ParserWorkerClient {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
/**
|
|
77
|
-
* Returns the process-local default client, creating it lazily.
|
|
78
|
-
* @returns {ParserWorkerClient} Default worker client.
|
|
79
|
-
*/
|
|
77
|
+
/** @returns {ParserWorkerClient} Lazily-created process-local default client. */
|
|
80
78
|
static defaultClient() {
|
|
81
79
|
return ParserWorkerClient.#defaultClientFor(null)
|
|
82
80
|
}
|
|
83
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Creates a client whose native worker and received graphs remain private.
|
|
84
|
+
* @param {string | URL} workerUrl Worker module URL.
|
|
85
|
+
* @returns {ParserWorkerClient} Client using native clone provenance.
|
|
86
|
+
*/
|
|
87
|
+
static fromWorkerUrl(workerUrl) {
|
|
88
|
+
return new ParserWorkerClient({
|
|
89
|
+
createWorker: () => NativeParserWorkerTransport.create(workerUrl)
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
84
93
|
/**
|
|
85
94
|
* Returns the process-local default client for one internal attempt.
|
|
86
95
|
* @param {object | null} attemptToken Internal attempt identity.
|
|
@@ -91,26 +100,15 @@ export class ParserWorkerClient {
|
|
|
91
100
|
throw ParserWorkerClient.#unavailableError(attemptToken)
|
|
92
101
|
}
|
|
93
102
|
if (!ParserWorkerClient.#defaultClient) {
|
|
94
|
-
ParserWorkerClient.#defaultClient =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
new URL(
|
|
99
|
-
'../../workers/parser.worker.mjs',
|
|
100
|
-
import.meta.url
|
|
101
|
-
),
|
|
102
|
-
{ type: 'module' }
|
|
103
|
-
])
|
|
104
|
-
}
|
|
105
|
-
})
|
|
103
|
+
ParserWorkerClient.#defaultClient =
|
|
104
|
+
ParserWorkerClient.fromWorkerUrl(
|
|
105
|
+
new URL('../../workers/parser.worker.mjs', import.meta.url)
|
|
106
|
+
)
|
|
106
107
|
}
|
|
107
108
|
return ParserWorkerClient.#defaultClient
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
/**
|
|
111
|
-
* Disposes the process-local default worker client when one exists.
|
|
112
|
-
* @returns {void}
|
|
113
|
-
*/
|
|
111
|
+
/** Disposes the process-local default worker client. @returns {void} */
|
|
114
112
|
static disposeDefault() {
|
|
115
113
|
ParserWorkerClient.#defaultClient?.dispose()
|
|
116
114
|
ParserWorkerClient.#defaultClient = null
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
const ARRAY_BUFFER_BYTE_LENGTH_GETTER = Object.getOwnPropertyDescriptor(
|
|
2
|
+
ArrayBuffer.prototype,
|
|
3
|
+
'byteLength'
|
|
4
|
+
)?.get
|
|
5
|
+
const ARRAY_BUFFER_RESIZABLE_GETTER = Object.getOwnPropertyDescriptor(
|
|
6
|
+
ArrayBuffer.prototype,
|
|
7
|
+
'resizable'
|
|
8
|
+
)?.get
|
|
9
|
+
const SHARED_ARRAY_BUFFER_BYTE_LENGTH_GETTER =
|
|
10
|
+
typeof SharedArrayBuffer === 'function'
|
|
11
|
+
? Object.getOwnPropertyDescriptor(
|
|
12
|
+
SharedArrayBuffer.prototype,
|
|
13
|
+
'byteLength'
|
|
14
|
+
)?.get
|
|
15
|
+
: null
|
|
16
|
+
const TYPED_ARRAY_PROTOTYPE = Object.getPrototypeOf(Uint8Array.prototype)
|
|
17
|
+
const TYPED_ARRAY_BUFFER_GETTER = Object.getOwnPropertyDescriptor(
|
|
18
|
+
TYPED_ARRAY_PROTOTYPE,
|
|
19
|
+
'buffer'
|
|
20
|
+
)?.get
|
|
21
|
+
const TYPED_ARRAY_BYTE_LENGTH_GETTER = Object.getOwnPropertyDescriptor(
|
|
22
|
+
TYPED_ARRAY_PROTOTYPE,
|
|
23
|
+
'byteLength'
|
|
24
|
+
)?.get
|
|
25
|
+
const TYPED_ARRAY_BYTE_OFFSET_GETTER = Object.getOwnPropertyDescriptor(
|
|
26
|
+
TYPED_ARRAY_PROTOTYPE,
|
|
27
|
+
'byteOffset'
|
|
28
|
+
)?.get
|
|
29
|
+
const TYPED_ARRAY_TAG_GETTER = Object.getOwnPropertyDescriptor(
|
|
30
|
+
TYPED_ARRAY_PROTOTYPE,
|
|
31
|
+
Symbol.toStringTag
|
|
32
|
+
)?.get
|
|
33
|
+
const DATA_VIEW_BUFFER_GETTER = Object.getOwnPropertyDescriptor(
|
|
34
|
+
DataView.prototype,
|
|
35
|
+
'buffer'
|
|
36
|
+
)?.get
|
|
37
|
+
const DATA_VIEW_BYTE_LENGTH_GETTER = Object.getOwnPropertyDescriptor(
|
|
38
|
+
DataView.prototype,
|
|
39
|
+
'byteLength'
|
|
40
|
+
)?.get
|
|
41
|
+
const DATA_VIEW_BYTE_OFFSET_GETTER = Object.getOwnPropertyDescriptor(
|
|
42
|
+
DataView.prototype,
|
|
43
|
+
'byteOffset'
|
|
44
|
+
)?.get
|
|
45
|
+
const DATA_VIEW_CONSTRUCTOR = DataView
|
|
46
|
+
const UINT8_ARRAY_CONSTRUCTOR = Uint8Array
|
|
47
|
+
const UINT8_ARRAY_SET = Uint8Array.prototype.set
|
|
48
|
+
const ARRAY_BUFFER_IS_VIEW = ArrayBuffer.isView
|
|
49
|
+
const OBJECT_GET_PROTOTYPE_OF = Object.getPrototypeOf
|
|
50
|
+
const OBJECT_PROTOTYPE = Object.prototype
|
|
51
|
+
const TYPED_ARRAYS = new Map(
|
|
52
|
+
[
|
|
53
|
+
Int8Array,
|
|
54
|
+
Uint8Array,
|
|
55
|
+
Uint8ClampedArray,
|
|
56
|
+
Int16Array,
|
|
57
|
+
Uint16Array,
|
|
58
|
+
Int32Array,
|
|
59
|
+
Uint32Array,
|
|
60
|
+
Float32Array,
|
|
61
|
+
Float64Array,
|
|
62
|
+
typeof BigInt64Array === 'function' ? BigInt64Array : null,
|
|
63
|
+
typeof BigUint64Array === 'function' ? BigUint64Array : null
|
|
64
|
+
]
|
|
65
|
+
.filter(Boolean)
|
|
66
|
+
.map((Constructor) => [Constructor.name, Constructor])
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Inspects and isolates worker binary data through captured intrinsic slots.
|
|
71
|
+
*/
|
|
72
|
+
export class WorkerBinaryData {
|
|
73
|
+
/**
|
|
74
|
+
* Classifies records only in a privately received native clone graph.
|
|
75
|
+
* Generic inputs must still use exact brands, even with these prototypes.
|
|
76
|
+
* @param {object} value Proven native-clone value.
|
|
77
|
+
* @returns {boolean} Whether it has a normalized plain-record prototype.
|
|
78
|
+
*/
|
|
79
|
+
static isStandardRecord(value) {
|
|
80
|
+
const prototype = OBJECT_GET_PROTOTYPE_OF(value)
|
|
81
|
+
return prototype === OBJECT_PROTOTYPE || prototype === null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Recreates one intrinsic view on an exact isolated backing buffer.
|
|
86
|
+
* @param {{ byteLength: number, tag: string }} view View fields.
|
|
87
|
+
* @param {ArrayBuffer} buffer Exact copied buffer.
|
|
88
|
+
* @returns {ArrayBufferView} Recreated view.
|
|
89
|
+
*/
|
|
90
|
+
static recreateView(view, buffer) {
|
|
91
|
+
if (view.tag === 'DataView') return new DATA_VIEW_CONSTRUCTOR(buffer)
|
|
92
|
+
const Constructor = TYPED_ARRAYS.get(view.tag)
|
|
93
|
+
if (!Constructor || view.byteLength % Constructor.BYTES_PER_ELEMENT) {
|
|
94
|
+
throw new TypeError('Worker request binary view is unsupported.')
|
|
95
|
+
}
|
|
96
|
+
return new Constructor(
|
|
97
|
+
buffer,
|
|
98
|
+
0,
|
|
99
|
+
view.byteLength / Constructor.BYTES_PER_ELEMENT
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Reads genuine typed-array or DataView internal slots.
|
|
105
|
+
* @param {unknown} value View candidate.
|
|
106
|
+
* @returns {{ buffer: ArrayBufferLike, byteOffset: number, byteLength: number, tag: string } | null} Intrinsic view fields.
|
|
107
|
+
*/
|
|
108
|
+
static view(value) {
|
|
109
|
+
if (!ARRAY_BUFFER_IS_VIEW(value)) return null
|
|
110
|
+
try {
|
|
111
|
+
const tag = TYPED_ARRAY_TAG_GETTER?.call(value)
|
|
112
|
+
if (TYPED_ARRAYS.has(tag)) {
|
|
113
|
+
return {
|
|
114
|
+
buffer: TYPED_ARRAY_BUFFER_GETTER.call(value),
|
|
115
|
+
byteOffset: TYPED_ARRAY_BYTE_OFFSET_GETTER.call(value),
|
|
116
|
+
byteLength: TYPED_ARRAY_BYTE_LENGTH_GETTER.call(value),
|
|
117
|
+
tag
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (
|
|
121
|
+
DATA_VIEW_BUFFER_GETTER &&
|
|
122
|
+
DATA_VIEW_BYTE_OFFSET_GETTER &&
|
|
123
|
+
DATA_VIEW_BYTE_LENGTH_GETTER
|
|
124
|
+
) {
|
|
125
|
+
const buffer = DATA_VIEW_BUFFER_GETTER.call(value)
|
|
126
|
+
return {
|
|
127
|
+
buffer,
|
|
128
|
+
byteOffset: DATA_VIEW_BYTE_OFFSET_GETTER.call(value),
|
|
129
|
+
byteLength: DATA_VIEW_BYTE_LENGTH_GETTER.call(value),
|
|
130
|
+
tag: 'DataView'
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} catch {
|
|
134
|
+
return null
|
|
135
|
+
}
|
|
136
|
+
return null
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** @param {unknown} value Candidate. @returns {number | null} Byte length. */
|
|
140
|
+
static bufferLength(value) {
|
|
141
|
+
if (!ARRAY_BUFFER_BYTE_LENGTH_GETTER) return null
|
|
142
|
+
try {
|
|
143
|
+
return ARRAY_BUFFER_BYTE_LENGTH_GETTER.call(value)
|
|
144
|
+
} catch {
|
|
145
|
+
return null
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** @param {unknown} value Candidate. @returns {number | null} Byte length. */
|
|
150
|
+
static sharedBufferLength(value) {
|
|
151
|
+
if (!SHARED_ARRAY_BUFFER_BYTE_LENGTH_GETTER) return null
|
|
152
|
+
try {
|
|
153
|
+
return SHARED_ARRAY_BUFFER_BYTE_LENGTH_GETTER.call(value)
|
|
154
|
+
} catch {
|
|
155
|
+
return null
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Returns whether a genuine ArrayBuffer can change size after accounting.
|
|
161
|
+
* @param {unknown} value Buffer candidate.
|
|
162
|
+
* @returns {boolean} Whether the buffer is resizable.
|
|
163
|
+
*/
|
|
164
|
+
static isResizableBuffer(value) {
|
|
165
|
+
if (!ARRAY_BUFFER_RESIZABLE_GETTER) return false
|
|
166
|
+
try {
|
|
167
|
+
return ARRAY_BUFFER_RESIZABLE_GETTER.call(value) === true
|
|
168
|
+
} catch {
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Copies one already-accounted intrinsic byte range into a fixed buffer.
|
|
175
|
+
* The explicit range prevents a growable backing store from widening the
|
|
176
|
+
* copy between its limit check and snapshot.
|
|
177
|
+
* @param {ArrayBufferLike} buffer Source buffer.
|
|
178
|
+
* @param {number} byteOffset Captured byte offset.
|
|
179
|
+
* @param {number} byteLength Captured byte length.
|
|
180
|
+
* @returns {ArrayBuffer} Fixed owned snapshot.
|
|
181
|
+
*/
|
|
182
|
+
static copyBuffer(buffer, byteOffset, byteLength) {
|
|
183
|
+
try {
|
|
184
|
+
const source = new UINT8_ARRAY_CONSTRUCTOR(
|
|
185
|
+
buffer,
|
|
186
|
+
byteOffset,
|
|
187
|
+
byteLength
|
|
188
|
+
)
|
|
189
|
+
const copy = new UINT8_ARRAY_CONSTRUCTOR(byteLength)
|
|
190
|
+
UINT8_ARRAY_SET.call(copy, source)
|
|
191
|
+
return TYPED_ARRAY_BUFFER_GETTER.call(copy)
|
|
192
|
+
} catch {
|
|
193
|
+
throw new TypeError(
|
|
194
|
+
'Worker request binary data changed while it was copied.'
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
Object.freeze(WorkerBinaryData.prototype)
|
|
201
|
+
Object.freeze(WorkerBinaryData)
|