space-data-module-sdk 0.8.6 → 0.8.8
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 +13 -0
- package/docs/AGENTS.md +5 -0
- package/docs/browser-wasmedge-isomorphic.md +65 -1
- package/docs/language-runtime-matrix.md +2 -2
- package/docs/provider-access-abi.md +600 -0
- package/package.json +15 -6
- package/schemas/orbpro/Propagator.fbs +19 -3
- package/src/browser.js +14 -4
- package/src/bundle/artifactBytes.js +44 -0
- package/src/bundle/index.js +1 -0
- package/src/compiler/compileModule.js +24 -1
- package/src/flow/flowCompiler.js +141 -2
- package/src/flow/flowRuntimeHost.js +7 -1
- package/src/flow/isomorphicFlowHost.js +1 -1
- package/src/flow/vendor/sdn-flow/MethodRegistry.js +6 -1
- package/src/generated/orbpro/propagator/propagator-source-description.js +2 -2
- package/src/generated/orbpro/propagator/propagator-source-description.ts +2 -2
- package/src/generated/orbpro/propagator/propagator-source-kind.js +13 -2
- package/src/generated/orbpro/propagator/propagator-source-kind.ts +13 -2
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts +18 -1
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts.map +1 -1
- package/src/generated/spacedatastandards/plg/pluginCategory.js +17 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.ts +21 -1
- package/src/{testing → host}/browserModuleHarness.js +69 -34
- package/src/host/index.js +6 -0
- package/src/host/isomorphicLoader.js +17 -45
- package/src/host/isomorphicLoaderBrowser.js +47 -0
- package/src/host/isomorphicLoaderCore.js +58 -0
- package/src/host/nodeBuiltinSpecifier.js +43 -0
- package/src/host/providerAccess.js +727 -0
- package/src/host/providerAccessAbi.js +403 -0
- package/src/host/providerAccessEngineAdapter.js +338 -0
- package/src/host/providerAccessFixtureAdapter.js +444 -0
- package/src/host/providerAccessTileStoreAdapter.js +366 -0
- package/src/host/sabHostcallChannel.js +1 -1
- package/src/host/terrainSourceSeam.js +205 -0
- package/src/host/wasiThreadHost.js +11 -1
- package/src/{testing → host}/workerModuleHarness.js +45 -12
- package/src/{testing → host}/workerModuleHarnessWorker.js +6 -5
- package/src/index.d.ts +29 -2
- package/src/standards/browser.js +95 -0
- package/src/standards/catalogCore.js +290 -0
- package/src/standards/index.js +27 -251
- package/src/testing/AGENTS.md +25 -2
- package/src/testing/browser.js +32 -0
- package/src/testing/index.d.ts +12 -1
- package/src/testing/index.js +3 -3
- package/src/testing/parityBrowserRunner.js +9 -2
- package/src/testing/parityHarness.js +1 -1
- package/templates/provider-access-module/include/space_data_provider_abi.h +227 -0
- /package/src/{testing → host}/moduleFlatbufferStreamPump.js +0 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Access ABI — constants, descriptor codec, and the guest import
|
|
3
|
+
* bridge. See docs/provider-access-abi.md for the normative contract.
|
|
4
|
+
*
|
|
5
|
+
* One generalized port for imagery/terrain providers, two planes:
|
|
6
|
+
*
|
|
7
|
+
* CONTROL provider.* operations on the existing space_data_module_host
|
|
8
|
+
* sync hostcall bridge (metadata only, JSON envelopes)
|
|
9
|
+
* DATA three dedicated imports on `space_data_provider` that write
|
|
10
|
+
* decoded provider bytes straight into guest linear memory
|
|
11
|
+
*
|
|
12
|
+
* Every parameter and every result across the boundary is i32. No i64 appears
|
|
13
|
+
* anywhere in a signature — the i64 legalization mismatch measured on this SDK
|
|
14
|
+
* is sidestepped by construction, not by convention. Every 64-bit quantity
|
|
15
|
+
* (rectangles, height extrema) travels inside the descriptor struct in guest
|
|
16
|
+
* memory as plain little-endian IEEE-754.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export const PROVIDER_IMPORT_MODULE = "space_data_provider";
|
|
20
|
+
|
|
21
|
+
/** Capability + scope. Both already exist; this ABI adds no new host capability. */
|
|
22
|
+
export const PROVIDER_CAPABILITY_ID = "scene_access";
|
|
23
|
+
export const PROVIDER_CAPABILITY_SCOPE = "provider.v1";
|
|
24
|
+
|
|
25
|
+
export const PROVIDER_ABI_VERSION = 1;
|
|
26
|
+
export const PROVIDER_TILE_DESC_MAGIC = 0x53445054; // 'SDPT'
|
|
27
|
+
export const PROVIDER_TILE_DESC_BYTES = 128;
|
|
28
|
+
|
|
29
|
+
export const ProviderKind = Object.freeze({
|
|
30
|
+
TERRAIN: 1,
|
|
31
|
+
IMAGERY: 2,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const ProviderEncoding = Object.freeze({
|
|
35
|
+
HEIGHT_F32: 1,
|
|
36
|
+
HEIGHT_F64: 2,
|
|
37
|
+
RGBA8: 16,
|
|
38
|
+
RGB8: 17,
|
|
39
|
+
GRAY8: 18,
|
|
40
|
+
GRAY16: 19,
|
|
41
|
+
RGBA_F32: 20,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const ProviderFlags = Object.freeze({
|
|
45
|
+
INTERPOLATED: 1 << 0,
|
|
46
|
+
STAGED: 1 << 1,
|
|
47
|
+
PARTIAL: 1 << 2,
|
|
48
|
+
DERIVED: 1 << 3,
|
|
49
|
+
FIXTURE: 1 << 4,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* What an acquire actually cost. `maxCost` on the request defaults to
|
|
54
|
+
* DEQUANTIZE — that default IS the "never re-fetch, never re-parse" rule,
|
|
55
|
+
* enforced by the ABI instead of by discipline.
|
|
56
|
+
*/
|
|
57
|
+
export const ProviderCost = Object.freeze({
|
|
58
|
+
RESIDENT: 0,
|
|
59
|
+
DEQUANTIZE: 1,
|
|
60
|
+
REDECODE: 2,
|
|
61
|
+
REFETCH: 3,
|
|
62
|
+
READBACK: 4,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export const DEFAULT_MAX_COST = ProviderCost.DEQUANTIZE;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* How the level was chosen. Carried in the DESCRIPTOR, not just in a JS
|
|
69
|
+
* return value, because the consumers that most need provenance are wasm
|
|
70
|
+
* modules. Names mirror the consumer's existing vocabulary verbatim.
|
|
71
|
+
*/
|
|
72
|
+
export const ProviderStrategy = Object.freeze({
|
|
73
|
+
DEFAULT: 0,
|
|
74
|
+
GRID_MATCHED_LEVEL: 1,
|
|
75
|
+
MOST_DETAILED: 2,
|
|
76
|
+
FIXED_LEVEL: 3,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const STRATEGY_NAMES = Object.freeze({
|
|
80
|
+
[ProviderStrategy.DEFAULT]: "default",
|
|
81
|
+
[ProviderStrategy.GRID_MATCHED_LEVEL]: "grid-matched-level",
|
|
82
|
+
[ProviderStrategy.MOST_DETAILED]: "most-detailed",
|
|
83
|
+
[ProviderStrategy.FIXED_LEVEL]: "fixed-level",
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export function providerStrategyName(strategy) {
|
|
87
|
+
return STRATEGY_NAMES[strategy] ?? "default";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const ProviderError = Object.freeze({
|
|
91
|
+
INVALID_REQUEST: -1,
|
|
92
|
+
NO_CAPABILITY: -2,
|
|
93
|
+
NO_PROVIDER: -3,
|
|
94
|
+
NOT_READY: -4,
|
|
95
|
+
NOT_AVAILABLE: -5,
|
|
96
|
+
BOUNDS: -6,
|
|
97
|
+
BAD_HANDLE: -7,
|
|
98
|
+
BAD_PLANE: -8,
|
|
99
|
+
UNSUPPORTED: -9,
|
|
100
|
+
TIMEOUT: -10,
|
|
101
|
+
HOST: -11,
|
|
102
|
+
PORT_UNAVAILABLE: -12,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const ERROR_NAMES = Object.freeze(
|
|
106
|
+
Object.fromEntries(
|
|
107
|
+
Object.entries(ProviderError).map(([name, code]) => [
|
|
108
|
+
code,
|
|
109
|
+
`SDM_PROVIDER_E_${name}`,
|
|
110
|
+
]),
|
|
111
|
+
),
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
export function providerErrorName(code) {
|
|
115
|
+
return ERROR_NAMES[code] ?? `SDM_PROVIDER_E_UNKNOWN(${code})`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* No-data sentinels. NaN is deliberately NOT used: WebAssembly does not
|
|
120
|
+
* canonicalize NaN payloads across every producing operation, so two runtimes
|
|
121
|
+
* can legitimately hold different bits for "a NaN" and a byte-identical-output
|
|
122
|
+
* assertion would fail on semantically equal values. -FLT_MAX / -DBL_MAX have
|
|
123
|
+
* exactly one encoding each and are never a real terrain height.
|
|
124
|
+
*/
|
|
125
|
+
export const PROVIDER_NO_DATA_F32 = -3.4028234663852886e38; // 0xFF7FFFFF
|
|
126
|
+
export const PROVIDER_NO_DATA_F64 = -Number.MAX_VALUE; // 0xFFEFFFFFFFFFFFFF
|
|
127
|
+
|
|
128
|
+
export function isProviderNoData(value) {
|
|
129
|
+
return value === PROVIDER_NO_DATA_F32 || value === PROVIDER_NO_DATA_F64;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Bytes per element for an encoding, and elements per pixel/sample. */
|
|
133
|
+
const ENCODING_LAYOUT = Object.freeze({
|
|
134
|
+
[ProviderEncoding.HEIGHT_F32]: { bytes: 4, components: 1 },
|
|
135
|
+
[ProviderEncoding.HEIGHT_F64]: { bytes: 8, components: 1 },
|
|
136
|
+
[ProviderEncoding.RGBA8]: { bytes: 4, components: 4 },
|
|
137
|
+
[ProviderEncoding.RGB8]: { bytes: 3, components: 3 },
|
|
138
|
+
[ProviderEncoding.GRAY8]: { bytes: 1, components: 1 },
|
|
139
|
+
[ProviderEncoding.GRAY16]: { bytes: 2, components: 1 },
|
|
140
|
+
[ProviderEncoding.RGBA_F32]: { bytes: 16, components: 4 },
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
export function encodingLayout(encoding) {
|
|
144
|
+
const layout = ENCODING_LAYOUT[encoding];
|
|
145
|
+
if (!layout) {
|
|
146
|
+
throw new RangeError(`Unknown provider encoding ${encoding}.`);
|
|
147
|
+
}
|
|
148
|
+
return layout;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Level selection from a TARGET SAMPLE SPACING, in metres.
|
|
153
|
+
*
|
|
154
|
+
* Callers know the stride they intend to march at; they do not know a
|
|
155
|
+
* provider's level scheme. Asking for "most detailed" everywhere is what makes
|
|
156
|
+
* a solve slow, and asking for coarser than the march stride is what makes it
|
|
157
|
+
* wrong — a coverage solve sampling at its output raster's spacing instead of
|
|
158
|
+
* its profile's mis-reported a 400 m ridge by 27 dB. So the caller states
|
|
159
|
+
* spacing and the port picks the coarsest level that satisfies it.
|
|
160
|
+
*
|
|
161
|
+
* Defined HERE, once, and shared by every adapter: if the browser and the host
|
|
162
|
+
* tile store chose levels by their own arithmetic they would sample different
|
|
163
|
+
* ground and byte parity would be lost for a reason no one could see.
|
|
164
|
+
*/
|
|
165
|
+
export const PROVIDER_EARTH_CIRCUMFERENCE_METERS = 40075016.6855785;
|
|
166
|
+
|
|
167
|
+
export function providerLevelForSpacing(spacingMeters, options = {}) {
|
|
168
|
+
const tileWidth = Math.max(2, options.tileWidth ?? 65);
|
|
169
|
+
const maxLevel = options.maxLevel ?? 20;
|
|
170
|
+
const minLevel = options.minLevel ?? 0;
|
|
171
|
+
const spacing = Number(spacingMeters);
|
|
172
|
+
if (!Number.isFinite(spacing) || spacing <= 0) return maxLevel;
|
|
173
|
+
|
|
174
|
+
for (let level = minLevel; level <= maxLevel; level += 1) {
|
|
175
|
+
// Level L has 2^(L+1) tiles around the equator, each covering
|
|
176
|
+
// (tileWidth - 1) sample intervals.
|
|
177
|
+
const tilesAcross = Math.pow(2, level + 1);
|
|
178
|
+
const levelSpacing =
|
|
179
|
+
PROVIDER_EARTH_CIRCUMFERENCE_METERS / (tilesAcross * (tileWidth - 1));
|
|
180
|
+
if (levelSpacing <= spacing) return level;
|
|
181
|
+
}
|
|
182
|
+
return maxLevel;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Resolve a request's level, and report HOW it was resolved. A consumer that
|
|
187
|
+
* cannot see which level answered cannot tell a solve that resolved the ridges
|
|
188
|
+
* from one that interpolated them away, so provenance is returned, never
|
|
189
|
+
* inferred.
|
|
190
|
+
*/
|
|
191
|
+
export function resolveRequestLevel(request, options = {}) {
|
|
192
|
+
const fallback = options.defaultLevel ?? options.maxLevel ?? 0;
|
|
193
|
+
const spacing = request?.spacing ?? request?.targetSpacingMeters;
|
|
194
|
+
if (spacing !== undefined && spacing !== null) {
|
|
195
|
+
return {
|
|
196
|
+
level: providerLevelForSpacing(spacing, options),
|
|
197
|
+
// Strategy names match the consumer's existing vocabulary verbatim
|
|
198
|
+
// (RfTerrainAnalysis surfaces them in coverage metadata and in the demo
|
|
199
|
+
// legend). A port that renamed them would force every consumer to keep a
|
|
200
|
+
// translation table.
|
|
201
|
+
strategy: "grid-matched-level",
|
|
202
|
+
strategyCode: ProviderStrategy.GRID_MATCHED_LEVEL,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
const level = request?.level;
|
|
206
|
+
if (level === "mostDetailed") {
|
|
207
|
+
return {
|
|
208
|
+
level: options.mostDetailedLevel ?? options.maxLevel ?? fallback,
|
|
209
|
+
strategy: "most-detailed",
|
|
210
|
+
strategyCode: ProviderStrategy.MOST_DETAILED,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (level === undefined || level === null) {
|
|
214
|
+
return { level: fallback, strategy: "default", strategyCode: ProviderStrategy.DEFAULT };
|
|
215
|
+
}
|
|
216
|
+
const numeric = Number(level);
|
|
217
|
+
if (!Number.isInteger(numeric) || numeric < 0) {
|
|
218
|
+
return { level: fallback, strategy: "default", strategyCode: ProviderStrategy.DEFAULT };
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
level: numeric,
|
|
222
|
+
strategy: "fixed-level",
|
|
223
|
+
strategyCode: ProviderStrategy.FIXED_LEVEL,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Normalize a request's positions into [lon, lat] pairs.
|
|
229
|
+
*
|
|
230
|
+
* Accepts the JSON `positions` array OR the binary `positionsBuffer`
|
|
231
|
+
* (interleaved f64 lon/lat) that the guest bridge materializes from a pointer.
|
|
232
|
+
* Shared by every adapter so a raster field is read identically everywhere.
|
|
233
|
+
*/
|
|
234
|
+
export function normalizeRequestPositions(request) {
|
|
235
|
+
const buffer = request?.positionsBuffer;
|
|
236
|
+
if (buffer && ArrayBuffer.isView(buffer)) {
|
|
237
|
+
const count = Math.floor(buffer.length / 2);
|
|
238
|
+
const positions = new Array(count);
|
|
239
|
+
for (let index = 0; index < count; index += 1) {
|
|
240
|
+
positions[index] = [buffer[index * 2], buffer[index * 2 + 1]];
|
|
241
|
+
}
|
|
242
|
+
return positions;
|
|
243
|
+
}
|
|
244
|
+
if (Array.isArray(request?.positions)) {
|
|
245
|
+
return request.positions.map((position) =>
|
|
246
|
+
Array.isArray(position)
|
|
247
|
+
? [Number(position[0]), Number(position[1])]
|
|
248
|
+
: [Number(position.longitude), Number(position.latitude)],
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** FNV-1a 32. Stable provider-id hash, identical in every runtime. */
|
|
255
|
+
export function providerSourceId(id) {
|
|
256
|
+
let hash = 0x811c9dc5;
|
|
257
|
+
const text = String(id ?? "");
|
|
258
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
259
|
+
hash ^= text.charCodeAt(index) & 0xff;
|
|
260
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
261
|
+
}
|
|
262
|
+
return hash >>> 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const DESC_OFFSETS = Object.freeze({
|
|
266
|
+
magic: 0,
|
|
267
|
+
version: 4,
|
|
268
|
+
kind: 8,
|
|
269
|
+
encoding: 12,
|
|
270
|
+
width: 16,
|
|
271
|
+
height: 20,
|
|
272
|
+
planeCount: 24,
|
|
273
|
+
bytesPerElement: 28,
|
|
274
|
+
rowStrideBytes: 32,
|
|
275
|
+
byteLength: 36,
|
|
276
|
+
flags: 40,
|
|
277
|
+
level: 44,
|
|
278
|
+
west: 48,
|
|
279
|
+
south: 56,
|
|
280
|
+
east: 64,
|
|
281
|
+
north: 72,
|
|
282
|
+
minValue: 80,
|
|
283
|
+
maxValue: 88,
|
|
284
|
+
tileX: 96,
|
|
285
|
+
tileY: 100,
|
|
286
|
+
hostCopies: 104,
|
|
287
|
+
sourceId: 108,
|
|
288
|
+
costClass: 112,
|
|
289
|
+
strategy: 116,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
export const PROVIDER_LEVEL_NONE = 0xffffffff;
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Serialize a tile descriptor into 128 little-endian bytes. Byte-identical for
|
|
296
|
+
* identical input in every runtime — this buffer is inside the parity envelope.
|
|
297
|
+
*/
|
|
298
|
+
export function encodeTileDescriptor(desc) {
|
|
299
|
+
const bytes = new Uint8Array(PROVIDER_TILE_DESC_BYTES);
|
|
300
|
+
const view = new DataView(bytes.buffer);
|
|
301
|
+
const u32 = (offset, value) => view.setUint32(offset, value >>> 0, true);
|
|
302
|
+
const f64 = (offset, value) => view.setFloat64(offset, Number(value), true);
|
|
303
|
+
|
|
304
|
+
u32(DESC_OFFSETS.magic, PROVIDER_TILE_DESC_MAGIC);
|
|
305
|
+
u32(DESC_OFFSETS.version, PROVIDER_ABI_VERSION);
|
|
306
|
+
u32(DESC_OFFSETS.kind, desc.kind);
|
|
307
|
+
u32(DESC_OFFSETS.encoding, desc.encoding);
|
|
308
|
+
u32(DESC_OFFSETS.width, desc.width);
|
|
309
|
+
u32(DESC_OFFSETS.height, desc.height);
|
|
310
|
+
u32(DESC_OFFSETS.planeCount, desc.planeCount ?? 1);
|
|
311
|
+
u32(DESC_OFFSETS.bytesPerElement, desc.bytesPerElement);
|
|
312
|
+
u32(DESC_OFFSETS.rowStrideBytes, desc.rowStrideBytes);
|
|
313
|
+
u32(DESC_OFFSETS.byteLength, desc.byteLength);
|
|
314
|
+
u32(DESC_OFFSETS.flags, desc.flags ?? 0);
|
|
315
|
+
u32(DESC_OFFSETS.level, desc.level ?? PROVIDER_LEVEL_NONE);
|
|
316
|
+
f64(DESC_OFFSETS.west, desc.west ?? 0);
|
|
317
|
+
f64(DESC_OFFSETS.south, desc.south ?? 0);
|
|
318
|
+
f64(DESC_OFFSETS.east, desc.east ?? 0);
|
|
319
|
+
f64(DESC_OFFSETS.north, desc.north ?? 0);
|
|
320
|
+
f64(DESC_OFFSETS.minValue, desc.minValue ?? 0);
|
|
321
|
+
f64(DESC_OFFSETS.maxValue, desc.maxValue ?? 0);
|
|
322
|
+
u32(DESC_OFFSETS.tileX, desc.tileX ?? PROVIDER_LEVEL_NONE);
|
|
323
|
+
u32(DESC_OFFSETS.tileY, desc.tileY ?? PROVIDER_LEVEL_NONE);
|
|
324
|
+
u32(DESC_OFFSETS.hostCopies, desc.hostCopies ?? 1);
|
|
325
|
+
u32(DESC_OFFSETS.sourceId, desc.sourceId ?? 0);
|
|
326
|
+
u32(DESC_OFFSETS.costClass, desc.costClass ?? ProviderCost.RESIDENT);
|
|
327
|
+
u32(DESC_OFFSETS.strategy, desc.strategy ?? ProviderStrategy.DEFAULT);
|
|
328
|
+
return bytes;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** Inverse of encodeTileDescriptor — used by tests and JS-side consumers. */
|
|
332
|
+
export function decodeTileDescriptor(bytes) {
|
|
333
|
+
if (bytes.byteLength < PROVIDER_TILE_DESC_BYTES) {
|
|
334
|
+
throw new RangeError(
|
|
335
|
+
`Tile descriptor requires ${PROVIDER_TILE_DESC_BYTES} bytes, got ${bytes.byteLength}.`,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
const view = new DataView(
|
|
339
|
+
bytes.buffer,
|
|
340
|
+
bytes.byteOffset,
|
|
341
|
+
PROVIDER_TILE_DESC_BYTES,
|
|
342
|
+
);
|
|
343
|
+
const u32 = (offset) => view.getUint32(offset, true);
|
|
344
|
+
const f64 = (offset) => view.getFloat64(offset, true);
|
|
345
|
+
const magic = u32(DESC_OFFSETS.magic);
|
|
346
|
+
if (magic !== PROVIDER_TILE_DESC_MAGIC) {
|
|
347
|
+
throw new Error(
|
|
348
|
+
`Tile descriptor magic mismatch: expected 0x${PROVIDER_TILE_DESC_MAGIC.toString(16)}, got 0x${magic.toString(16)}.`,
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
magic,
|
|
353
|
+
version: u32(DESC_OFFSETS.version),
|
|
354
|
+
kind: u32(DESC_OFFSETS.kind),
|
|
355
|
+
encoding: u32(DESC_OFFSETS.encoding),
|
|
356
|
+
width: u32(DESC_OFFSETS.width),
|
|
357
|
+
height: u32(DESC_OFFSETS.height),
|
|
358
|
+
planeCount: u32(DESC_OFFSETS.planeCount),
|
|
359
|
+
bytesPerElement: u32(DESC_OFFSETS.bytesPerElement),
|
|
360
|
+
rowStrideBytes: u32(DESC_OFFSETS.rowStrideBytes),
|
|
361
|
+
byteLength: u32(DESC_OFFSETS.byteLength),
|
|
362
|
+
flags: u32(DESC_OFFSETS.flags),
|
|
363
|
+
level: u32(DESC_OFFSETS.level),
|
|
364
|
+
west: f64(DESC_OFFSETS.west),
|
|
365
|
+
south: f64(DESC_OFFSETS.south),
|
|
366
|
+
east: f64(DESC_OFFSETS.east),
|
|
367
|
+
north: f64(DESC_OFFSETS.north),
|
|
368
|
+
minValue: f64(DESC_OFFSETS.minValue),
|
|
369
|
+
maxValue: f64(DESC_OFFSETS.maxValue),
|
|
370
|
+
tileX: u32(DESC_OFFSETS.tileX),
|
|
371
|
+
tileY: u32(DESC_OFFSETS.tileY),
|
|
372
|
+
hostCopies: u32(DESC_OFFSETS.hostCopies),
|
|
373
|
+
sourceId: u32(DESC_OFFSETS.sourceId),
|
|
374
|
+
costClass: u32(DESC_OFFSETS.costClass),
|
|
375
|
+
strategy: u32(DESC_OFFSETS.strategy),
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Error thrown by adapters that want to select a specific ABI code. Anything
|
|
381
|
+
* else an adapter throws becomes SDM_PROVIDER_E_HOST with the detail available
|
|
382
|
+
* through `provider.lastError`.
|
|
383
|
+
*/
|
|
384
|
+
export class ProviderAccessError extends Error {
|
|
385
|
+
constructor(code, message, options = {}) {
|
|
386
|
+
super(message);
|
|
387
|
+
this.name = "ProviderAccessError";
|
|
388
|
+
this.code = code;
|
|
389
|
+
this.providerErrorName = providerErrorName(code);
|
|
390
|
+
this.operation = options.operation ?? null;
|
|
391
|
+
this.providerId = options.providerId ?? null;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export function providerErrorCodeOf(error) {
|
|
396
|
+
if (error instanceof ProviderAccessError) {
|
|
397
|
+
return error.code;
|
|
398
|
+
}
|
|
399
|
+
if (typeof error?.code === "number" && error.code < 0 && error.code >= -12) {
|
|
400
|
+
return error.code;
|
|
401
|
+
}
|
|
402
|
+
return ProviderError.HOST;
|
|
403
|
+
}
|