@slatedb/uniffi 0.12.0

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.
@@ -0,0 +1,120 @@
1
+ export declare const UniffiHandle: "uint64_t";
2
+ export declare const VoidPointer: "void *";
3
+ export declare const RustBuffer: unknown;
4
+ export declare const ForeignBytes: unknown;
5
+ export declare const RustCallStatus: unknown;
6
+
7
+ export interface RustBufferStruct {
8
+ capacity: bigint;
9
+ len: bigint;
10
+ data: unknown | null;
11
+ }
12
+
13
+ export interface ForeignBytesStruct {
14
+ len: number;
15
+ data: unknown | null;
16
+ }
17
+
18
+ export interface RustCallStatusStruct {
19
+ code: number;
20
+ error_buf: RustBufferStruct;
21
+ }
22
+
23
+ export declare const RustCallStatusCodes: Readonly<{
24
+ SUCCESS: 0;
25
+ ERROR: 1;
26
+ UNEXPECTED_ERROR: 2;
27
+ CANCELLED: 3;
28
+ }>;
29
+
30
+ export declare const EMPTY_RUST_BUFFER: Readonly<RustBufferStruct>;
31
+ export declare const EMPTY_FOREIGN_BYTES: Readonly<ForeignBytesStruct>;
32
+ export declare const EMPTY_RUST_CALL_STATUS: Readonly<RustCallStatusStruct>;
33
+
34
+ export declare function normalizeInt64(value: bigint | number | null | undefined): bigint | null | undefined;
35
+ export declare function normalizeUInt64(value: bigint | number | null | undefined): bigint | null | undefined;
36
+ export declare function normalizeHandle(value: bigint | number | null | undefined): bigint | null | undefined;
37
+ export declare function pointerAddress(pointer: unknown | null | undefined): bigint;
38
+ export declare function isNullPointer(pointer: unknown | null | undefined): boolean;
39
+ export declare function assertSafeArrayLength(value: bigint | number, label?: string): number;
40
+ export declare function normalizeRustBuffer(
41
+ buffer: RustBufferStruct | null | undefined,
42
+ ): RustBufferStruct | null | undefined;
43
+ export declare function normalizeForeignBytes(
44
+ bytes: ForeignBytesStruct | null | undefined,
45
+ ): ForeignBytesStruct | null | undefined;
46
+ export declare function normalizeRustCallStatus(
47
+ status: RustCallStatusStruct | null | undefined,
48
+ ): RustCallStatusStruct | null | undefined;
49
+ export declare function createEmptyRustBuffer(): Readonly<RustBufferStruct>;
50
+ export declare function createRustBuffer(
51
+ buffer?: RustBufferStruct | null,
52
+ ): Readonly<RustBufferStruct>;
53
+ export declare function createForeignBytes(
54
+ value?: ForeignBytesStruct | ArrayBuffer | ArrayBufferView | number[] | null,
55
+ ): Readonly<ForeignBytesStruct>;
56
+ export declare function createRustCallStatus(
57
+ code?: number,
58
+ error_buf?: RustBufferStruct | null,
59
+ ): Readonly<RustCallStatusStruct>;
60
+ export declare function rustBufferNeedsFree(buffer: RustBufferStruct | null | undefined): boolean;
61
+ export declare function coerceUint8Array(
62
+ value: ArrayBuffer | ArrayBufferView | number[] | null | undefined,
63
+ label?: string,
64
+ ): Uint8Array;
65
+ export declare function copyUint8Array(
66
+ value: ArrayBuffer | ArrayBufferView | number[] | null | undefined,
67
+ label?: string,
68
+ ): Uint8Array;
69
+ export declare function viewPointerBytes(
70
+ pointer: unknown | null | undefined,
71
+ length: bigint | number,
72
+ label?: string,
73
+ ): Uint8Array;
74
+ export declare function readPointerBytes(
75
+ pointer: unknown | null | undefined,
76
+ length: bigint | number,
77
+ label?: string,
78
+ ): Uint8Array;
79
+ export declare function readForeignBytes(
80
+ bytes: ForeignBytesStruct | null | undefined,
81
+ label?: string,
82
+ ): Uint8Array;
83
+ export declare function readRustBufferBytes(
84
+ buffer: RustBufferStruct | null | undefined,
85
+ label?: string,
86
+ ): Uint8Array;
87
+ export declare function defineOpaquePointer(name: string): unknown;
88
+ export declare function defineStructType(
89
+ name: string,
90
+ fields: Readonly<Record<string, unknown>>,
91
+ ): unknown;
92
+ export declare function defineCallbackVtable(
93
+ name: string,
94
+ fields: Readonly<Record<string, unknown>>,
95
+ ): unknown;
96
+ export declare function defineCallbackPrototype(
97
+ name: string,
98
+ returnType: unknown,
99
+ argumentTypes: ReadonlyArray<unknown>,
100
+ ): unknown;
101
+
102
+ export declare class RustBufferValue {
103
+ constructor(buffer?: RustBufferStruct | null);
104
+ static empty(): RustBufferValue;
105
+ toStruct(): Readonly<RustBufferStruct>;
106
+ isEmpty(): boolean;
107
+ byteLength(): number;
108
+ toUint8Array(): Uint8Array;
109
+ free(freeRustBuffer: (buffer: RustBufferStruct) => void): boolean;
110
+ consumeIntoUint8Array(freeRustBuffer: (buffer: RustBufferStruct) => void): Uint8Array;
111
+ }
112
+
113
+ export declare class ForeignBytesValue {
114
+ constructor(bytes?: ForeignBytesStruct | null);
115
+ static empty(): ForeignBytesValue;
116
+ toStruct(): Readonly<ForeignBytesStruct>;
117
+ isEmpty(): boolean;
118
+ byteLength(): number;
119
+ toUint8Array(): Uint8Array;
120
+ }
@@ -0,0 +1,456 @@
1
+ import koffi from "koffi";
2
+ import {
3
+ BufferOverflowError,
4
+ ConverterRangeError,
5
+ UnexpectedNullPointer,
6
+ } from "./errors.js";
7
+
8
+ export const UniffiHandle = "uint64_t";
9
+ export const VoidPointer = "void *";
10
+
11
+ export const RustBuffer = koffi.struct("RustBuffer", {
12
+ capacity: "uint64_t",
13
+ len: "uint64_t",
14
+ data: VoidPointer,
15
+ });
16
+
17
+ export const ForeignBytes = koffi.struct("ForeignBytes", {
18
+ len: "int32_t",
19
+ data: VoidPointer,
20
+ });
21
+
22
+ export const RustCallStatus = koffi.struct("RustCallStatus", {
23
+ code: "int8_t",
24
+ error_buf: RustBuffer,
25
+ });
26
+
27
+ // Koffi keeps named type and prototype definitions process-wide. Reuse them
28
+ // across load/unload cycles so manual-load packages do not accumulate duplicates.
29
+ const NAMED_POINTER_TYPES = new Map();
30
+ const NAMED_STRUCT_TYPES = new Map();
31
+ const NAMED_CALLBACK_VTABLE_TYPES = new Map();
32
+ const NAMED_CALLBACK_PROTOTYPES = new Map();
33
+
34
+ const MAX_SAFE_LENGTH = BigInt(Number.MAX_SAFE_INTEGER);
35
+ const MAX_UINT64 = (1n << 64n) - 1n;
36
+ const MAX_INT64 = (1n << 63n) - 1n;
37
+ const MIN_INT64 = -(1n << 63n);
38
+ const MAX_FOREIGN_BYTES_LEN = 0x7fffffff;
39
+
40
+ export const RustCallStatusCodes = Object.freeze({
41
+ SUCCESS: 0,
42
+ ERROR: 1,
43
+ UNEXPECTED_ERROR: 2,
44
+ CANCELLED: 3,
45
+ });
46
+
47
+ export const EMPTY_RUST_BUFFER = Object.freeze({
48
+ capacity: 0n,
49
+ len: 0n,
50
+ data: null,
51
+ });
52
+
53
+ export const EMPTY_FOREIGN_BYTES = Object.freeze({
54
+ len: 0,
55
+ data: null,
56
+ });
57
+
58
+ export const EMPTY_RUST_CALL_STATUS = Object.freeze({
59
+ code: RustCallStatusCodes.SUCCESS,
60
+ error_buf: EMPTY_RUST_BUFFER,
61
+ });
62
+
63
+ function bigintFromNumber(value, label) {
64
+ if (!Number.isSafeInteger(value)) {
65
+ throw new ConverterRangeError(
66
+ `${label} must be a safe integer, got ${String(value)}.`,
67
+ );
68
+ }
69
+ return BigInt(value);
70
+ }
71
+
72
+ function isByteSource(value) {
73
+ return ArrayBuffer.isView(value) || value instanceof ArrayBuffer;
74
+ }
75
+
76
+ function normalizeByteSourceLength(value, label) {
77
+ if (ArrayBuffer.isView(value)) {
78
+ return value.byteLength;
79
+ }
80
+ if (value instanceof ArrayBuffer) {
81
+ return value.byteLength;
82
+ }
83
+ throw new ConverterRangeError(`${label} is not backed by byte-addressable memory.`);
84
+ }
85
+
86
+ export function normalizeInt64(value) {
87
+ if (value == null) {
88
+ return value;
89
+ }
90
+
91
+ const normalized =
92
+ typeof value === "bigint" ? value : bigintFromNumber(value, "int64");
93
+ if (normalized < MIN_INT64 || normalized > MAX_INT64) {
94
+ throw new ConverterRangeError(
95
+ `int64 value ${String(value)} is outside the supported range.`,
96
+ );
97
+ }
98
+ return normalized;
99
+ }
100
+
101
+ export function normalizeUInt64(value) {
102
+ if (value == null) {
103
+ return value;
104
+ }
105
+
106
+ const normalized =
107
+ typeof value === "bigint" ? value : bigintFromNumber(value, "uint64");
108
+ if (normalized < 0n || normalized > MAX_UINT64) {
109
+ throw new ConverterRangeError(
110
+ `uint64 value ${String(value)} is outside the supported range.`,
111
+ );
112
+ }
113
+ return normalized;
114
+ }
115
+
116
+ export function normalizeHandle(value) {
117
+ return normalizeUInt64(value);
118
+ }
119
+
120
+ function normalizeForeignBytesLength(value) {
121
+ const normalized =
122
+ typeof value === "bigint"
123
+ ? value
124
+ : bigintFromNumber(value, "ForeignBytes length");
125
+ if (normalized < 0n || normalized > BigInt(MAX_FOREIGN_BYTES_LEN)) {
126
+ throw new ConverterRangeError(
127
+ `ForeignBytes length ${String(value)} is outside the supported int32 range.`,
128
+ );
129
+ }
130
+ return Number(normalized);
131
+ }
132
+
133
+ export function pointerAddress(pointer) {
134
+ if (pointer == null) {
135
+ return 0n;
136
+ }
137
+ if (typeof pointer === "bigint" || typeof pointer === "number") {
138
+ return normalizeUInt64(pointer);
139
+ }
140
+ return koffi.address(pointer);
141
+ }
142
+
143
+ export function isNullPointer(pointer) {
144
+ if (pointer == null) {
145
+ return true;
146
+ }
147
+ if (isByteSource(pointer)) {
148
+ return normalizeByteSourceLength(pointer, "byte source") === 0;
149
+ }
150
+ return pointerAddress(pointer) === 0n;
151
+ }
152
+
153
+ export function assertSafeArrayLength(value, label = "length") {
154
+ const normalized = normalizeUInt64(value);
155
+ if (normalized > MAX_SAFE_LENGTH) {
156
+ throw new ConverterRangeError(
157
+ `${label} ${String(value)} exceeds Number.MAX_SAFE_INTEGER.`,
158
+ );
159
+ }
160
+ return Number(normalized);
161
+ }
162
+
163
+ export function normalizeRustBuffer(buffer) {
164
+ if (buffer == null) {
165
+ return buffer;
166
+ }
167
+
168
+ const capacity = normalizeUInt64(buffer.capacity ?? 0);
169
+ const len = normalizeUInt64(buffer.len ?? 0);
170
+ const data = buffer.data ?? null;
171
+
172
+ if (len > capacity) {
173
+ throw new BufferOverflowError(
174
+ `RustBuffer length ${String(len)} exceeds capacity ${String(capacity)}.`,
175
+ );
176
+ }
177
+ if (data == null && (len !== 0n || capacity !== 0n)) {
178
+ throw new UnexpectedNullPointer(
179
+ "RustBuffer data is null but the buffer is not empty.",
180
+ );
181
+ }
182
+
183
+ return {
184
+ capacity,
185
+ len,
186
+ data,
187
+ };
188
+ }
189
+
190
+ export function normalizeForeignBytes(bytes) {
191
+ if (bytes == null) {
192
+ return bytes;
193
+ }
194
+
195
+ const len = normalizeForeignBytesLength(bytes.len ?? 0);
196
+ const data = bytes.data ?? null;
197
+ if (data == null && len !== 0) {
198
+ throw new UnexpectedNullPointer(
199
+ "ForeignBytes data is null but the byte view is not empty.",
200
+ );
201
+ }
202
+
203
+ return {
204
+ len,
205
+ data,
206
+ };
207
+ }
208
+
209
+ export function normalizeRustCallStatus(status) {
210
+ if (status == null) {
211
+ return status;
212
+ }
213
+
214
+ return {
215
+ code: status.code,
216
+ error_buf: normalizeRustBuffer(status.error_buf) ?? EMPTY_RUST_BUFFER,
217
+ };
218
+ }
219
+
220
+ export function createEmptyRustBuffer() {
221
+ return EMPTY_RUST_BUFFER;
222
+ }
223
+
224
+ export function createRustBuffer(buffer = EMPTY_RUST_BUFFER) {
225
+ return Object.freeze(normalizeRustBuffer(buffer) ?? EMPTY_RUST_BUFFER);
226
+ }
227
+
228
+ export function createForeignBytes(value = EMPTY_FOREIGN_BYTES) {
229
+ if (value === EMPTY_FOREIGN_BYTES || value == null) {
230
+ return EMPTY_FOREIGN_BYTES;
231
+ }
232
+
233
+ if (typeof value === "object" && "len" in value && "data" in value) {
234
+ return Object.freeze(normalizeForeignBytes(value));
235
+ }
236
+
237
+ const bytes = coerceUint8Array(value);
238
+ return Object.freeze({
239
+ len: bytes.byteLength,
240
+ data: bytes.byteLength === 0 ? null : bytes,
241
+ });
242
+ }
243
+
244
+ export function createRustCallStatus(
245
+ code = RustCallStatusCodes.SUCCESS,
246
+ error_buf = EMPTY_RUST_BUFFER,
247
+ ) {
248
+ return Object.freeze({
249
+ code,
250
+ error_buf: normalizeRustBuffer(error_buf) ?? EMPTY_RUST_BUFFER,
251
+ });
252
+ }
253
+
254
+ export function rustBufferNeedsFree(buffer) {
255
+ const normalized = normalizeRustBuffer(buffer) ?? EMPTY_RUST_BUFFER;
256
+ if (normalized.data == null) {
257
+ return false;
258
+ }
259
+ if (isByteSource(normalized.data)) {
260
+ return false;
261
+ }
262
+ return true;
263
+ }
264
+
265
+ export function coerceUint8Array(value, label = "bytes") {
266
+ if (value == null) {
267
+ return new Uint8Array();
268
+ }
269
+ if (value instanceof Uint8Array) {
270
+ return value;
271
+ }
272
+ if (ArrayBuffer.isView(value)) {
273
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
274
+ }
275
+ if (value instanceof ArrayBuffer) {
276
+ return new Uint8Array(value);
277
+ }
278
+ if (Array.isArray(value)) {
279
+ return Uint8Array.from(value);
280
+ }
281
+ throw new TypeError(`${label} must be an ArrayBuffer, TypedArray, or array of bytes.`);
282
+ }
283
+
284
+ export function copyUint8Array(value, label = "bytes") {
285
+ return Uint8Array.from(coerceUint8Array(value, label));
286
+ }
287
+
288
+ export function viewPointerBytes(pointer, length, label = "pointer") {
289
+ const byteLength = assertSafeArrayLength(length, `${label} length`);
290
+ if (byteLength === 0) {
291
+ return new Uint8Array();
292
+ }
293
+
294
+ if (isByteSource(pointer)) {
295
+ const available = normalizeByteSourceLength(pointer, label);
296
+ if (available < byteLength) {
297
+ throw new BufferOverflowError(
298
+ `${label} only contains ${available} byte(s), expected ${byteLength}.`,
299
+ );
300
+ }
301
+ if (ArrayBuffer.isView(pointer)) {
302
+ return new Uint8Array(pointer.buffer, pointer.byteOffset, byteLength);
303
+ }
304
+ return new Uint8Array(pointer, 0, byteLength);
305
+ }
306
+
307
+ if (isNullPointer(pointer)) {
308
+ throw new UnexpectedNullPointer(`${label} is null.`);
309
+ }
310
+
311
+ const pointerBytes = koffi.view(pointer, byteLength);
312
+ return Uint8Array.from(
313
+ ArrayBuffer.isView(pointerBytes)
314
+ ? pointerBytes
315
+ : new Uint8Array(pointerBytes),
316
+ );
317
+ }
318
+
319
+ export function readPointerBytes(pointer, length, label = "pointer") {
320
+ const bytes = viewPointerBytes(pointer, length, label);
321
+ return isByteSource(pointer)
322
+ ? Uint8Array.from(bytes)
323
+ : bytes;
324
+ }
325
+
326
+ export function readForeignBytes(bytes, label = "ForeignBytes") {
327
+ const normalized = normalizeForeignBytes(bytes) ?? EMPTY_FOREIGN_BYTES;
328
+ return readPointerBytes(normalized.data, normalized.len, label);
329
+ }
330
+
331
+ export function readRustBufferBytes(buffer, label = "RustBuffer") {
332
+ const normalized = normalizeRustBuffer(buffer) ?? EMPTY_RUST_BUFFER;
333
+ return readPointerBytes(normalized.data, normalized.len, label);
334
+ }
335
+
336
+ export function defineOpaquePointer(name) {
337
+ return getOrCreateNamedType(
338
+ NAMED_POINTER_TYPES,
339
+ name,
340
+ () => koffi.pointer(name, koffi.opaque()),
341
+ );
342
+ }
343
+
344
+ export function defineStructType(name, fields) {
345
+ return getOrCreateNamedType(
346
+ NAMED_STRUCT_TYPES,
347
+ name,
348
+ () => koffi.struct(name, fields),
349
+ );
350
+ }
351
+
352
+ export function defineCallbackVtable(name, fields) {
353
+ return getOrCreateNamedType(
354
+ NAMED_CALLBACK_VTABLE_TYPES,
355
+ name,
356
+ () => koffi.struct(name, fields),
357
+ );
358
+ }
359
+
360
+ export function defineCallbackPrototype(name, returnType, argumentTypes) {
361
+ return getOrCreateNamedType(
362
+ NAMED_CALLBACK_PROTOTYPES,
363
+ name,
364
+ () => koffi.proto(name, returnType, argumentTypes),
365
+ );
366
+ }
367
+
368
+ export class RustBufferValue {
369
+ constructor(buffer = EMPTY_RUST_BUFFER) {
370
+ this._buffer = normalizeRustBuffer(buffer) ?? EMPTY_RUST_BUFFER;
371
+ this._released = false;
372
+ }
373
+
374
+ static empty() {
375
+ return new RustBufferValue(EMPTY_RUST_BUFFER);
376
+ }
377
+
378
+ _requireBuffer() {
379
+ if (this._released) {
380
+ throw new UnexpectedNullPointer("RustBuffer has already been released.");
381
+ }
382
+ return this._buffer;
383
+ }
384
+
385
+ toStruct() {
386
+ return createRustBuffer(this._requireBuffer());
387
+ }
388
+
389
+ isEmpty() {
390
+ return this._requireBuffer().len === 0n;
391
+ }
392
+
393
+ byteLength() {
394
+ return assertSafeArrayLength(this._requireBuffer().len, "RustBuffer length");
395
+ }
396
+
397
+ toUint8Array() {
398
+ return readRustBufferBytes(this._requireBuffer());
399
+ }
400
+
401
+ free(freeRustBuffer) {
402
+ const buffer = this._requireBuffer();
403
+ if (rustBufferNeedsFree(buffer) && typeof freeRustBuffer !== "function") {
404
+ throw new TypeError("freeRustBuffer must be a function when releasing a RustBuffer.");
405
+ }
406
+
407
+ this._released = true;
408
+ this._buffer = EMPTY_RUST_BUFFER;
409
+
410
+ if (rustBufferNeedsFree(buffer)) {
411
+ freeRustBuffer(buffer);
412
+ }
413
+ return true;
414
+ }
415
+
416
+ consumeIntoUint8Array(freeRustBuffer) {
417
+ const bytes = this.toUint8Array();
418
+ this.free(freeRustBuffer);
419
+ return bytes;
420
+ }
421
+ }
422
+
423
+ export class ForeignBytesValue {
424
+ constructor(bytes = EMPTY_FOREIGN_BYTES) {
425
+ this._bytes = normalizeForeignBytes(bytes) ?? EMPTY_FOREIGN_BYTES;
426
+ }
427
+
428
+ static empty() {
429
+ return new ForeignBytesValue(EMPTY_FOREIGN_BYTES);
430
+ }
431
+
432
+ toStruct() {
433
+ return createForeignBytes(this._bytes);
434
+ }
435
+
436
+ isEmpty() {
437
+ return this._bytes.len === 0;
438
+ }
439
+
440
+ byteLength() {
441
+ return this._bytes.len;
442
+ }
443
+
444
+ toUint8Array() {
445
+ return readForeignBytes(this._bytes);
446
+ }
447
+ }
448
+
449
+ function getOrCreateNamedType(cache, name, create) {
450
+ let type = cache.get(name);
451
+ if (type == null) {
452
+ type = create();
453
+ cache.set(name, type);
454
+ }
455
+ return type;
456
+ }
@@ -0,0 +1,35 @@
1
+ export type UniffiHandle = bigint;
2
+
3
+ export declare const INVALID_HANDLE: 0n;
4
+ export declare const defaultUniffiHandle: 0n;
5
+ export declare const FIRST_FOREIGN_HANDLE: 1n;
6
+ export declare const FOREIGN_HANDLE_STEP: 2n;
7
+
8
+ export interface HandleMapOptions {
9
+ firstHandle?: bigint | number;
10
+ handleStep?: bigint | number;
11
+ }
12
+
13
+ export declare class UniffiHandleMap<T>
14
+ implements Iterable<[UniffiHandle, T]>
15
+ {
16
+ constructor(options?: HandleMapOptions);
17
+ insert(value: T): UniffiHandle;
18
+ register(handle: bigint | number, value: T): UniffiHandle;
19
+ get(handle: bigint | number): T;
20
+ peek(handle: bigint | number | null | undefined): T | undefined;
21
+ clone(handle: bigint | number): UniffiHandle;
22
+ remove(handle: bigint | number | null | undefined): T | undefined;
23
+ take(handle: bigint | number): T;
24
+ has(handle: bigint | number | null | undefined): boolean;
25
+ clear(): void;
26
+ keys(): IterableIterator<UniffiHandle>;
27
+ values(): IterableIterator<T>;
28
+ entries(): IterableIterator<[UniffiHandle, T]>;
29
+ [Symbol.iterator](): IterableIterator<[UniffiHandle, T]>;
30
+ readonly size: number;
31
+ }
32
+
33
+ export declare function createHandleMap<T>(
34
+ options?: HandleMapOptions,
35
+ ): UniffiHandleMap<T>;