@gtkx/runtime 1.0.0 → 1.2.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.
- package/README.md +1 -1
- package/dist/application-class.d.ts +5 -0
- package/dist/application-class.d.ts.map +1 -1
- package/dist/application-class.js +11 -1
- package/dist/application-class.js.map +1 -1
- package/dist/callback.d.ts +2 -2
- package/dist/callback.d.ts.map +1 -1
- package/dist/callback.js +51 -54
- package/dist/callback.js.map +1 -1
- package/dist/closure.js +1 -1
- package/dist/closure.js.map +1 -1
- package/dist/default-application.d.ts +4 -0
- package/dist/default-application.d.ts.map +1 -0
- package/dist/default-application.js +17 -0
- package/dist/default-application.js.map +1 -0
- package/dist/descriptors.d.ts +34 -9
- package/dist/descriptors.d.ts.map +1 -1
- package/dist/descriptors.js +42 -17
- package/dist/descriptors.js.map +1 -1
- package/dist/exit-hook.js +13 -0
- package/dist/exit-hook.js.map +1 -1
- package/dist/fn.d.ts +5 -0
- package/dist/fn.d.ts.map +1 -1
- package/dist/fn.js +11 -13
- package/dist/fn.js.map +1 -1
- package/dist/folded-lengths.d.ts +16 -0
- package/dist/folded-lengths.d.ts.map +1 -0
- package/dist/folded-lengths.js +38 -0
- package/dist/folded-lengths.js.map +1 -0
- package/dist/internal.d.ts +1 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -0
- package/dist/internal.js.map +1 -1
- package/dist/library.d.ts +2 -1
- package/dist/library.d.ts.map +1 -1
- package/dist/library.js +2 -1
- package/dist/library.js.map +1 -1
- package/dist/lifecycle.d.ts +16 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +44 -14
- package/dist/lifecycle.js.map +1 -1
- package/dist/listeners.d.ts.map +1 -1
- package/dist/listeners.js +16 -4
- package/dist/listeners.js.map +1 -1
- package/dist/native-value.js +2 -2
- package/dist/native-value.js.map +1 -1
- package/dist/object.d.ts +7 -2
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +7 -2
- package/dist/object.js.map +1 -1
- package/dist/param-spec.d.ts.map +1 -1
- package/dist/param-spec.js +18 -20
- package/dist/param-spec.js.map +1 -1
- package/dist/properties.d.ts +2 -1
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +13 -9
- package/dist/properties.js.map +1 -1
- package/dist/register-class.d.ts +33 -3
- package/dist/register-class.d.ts.map +1 -1
- package/dist/register-class.js +21 -7
- package/dist/register-class.js.map +1 -1
- package/dist/registry.d.ts +14 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +24 -15
- package/dist/registry.js.map +1 -1
- package/dist/signal.d.ts +2 -2
- package/dist/signal.d.ts.map +1 -1
- package/dist/signal.js +22 -18
- package/dist/signal.js.map +1 -1
- package/dist/t.d.ts +3 -1
- package/dist/t.d.ts.map +1 -1
- package/dist/t.js +1 -0
- package/dist/t.js.map +1 -1
- package/dist/tuple.d.ts +6 -3
- package/dist/tuple.d.ts.map +1 -1
- package/dist/tuple.js +9 -7
- package/dist/tuple.js.map +1 -1
- package/dist/value.d.ts +3 -1
- package/dist/value.d.ts.map +1 -1
- package/dist/value.js +64 -18
- package/dist/value.js.map +1 -1
- package/dist/vfunc-call.d.ts.map +1 -1
- package/dist/vfunc-call.js +5 -1
- package/dist/vfunc-call.js.map +1 -1
- package/dist/vfunc.d.ts.map +1 -1
- package/dist/vfunc.js +9 -3
- package/dist/vfunc.js.map +1 -1
- package/package.json +14 -4
- package/src/application-class.ts +12 -2
- package/src/callback.ts +70 -66
- package/src/closure.ts +1 -1
- package/src/default-application.ts +21 -0
- package/src/descriptors.ts +98 -29
- package/src/exit-hook.ts +18 -0
- package/src/fn.ts +23 -13
- package/src/folded-lengths.ts +64 -0
- package/src/internal.ts +1 -0
- package/src/library.ts +2 -1
- package/src/lifecycle.ts +60 -14
- package/src/listeners.ts +22 -5
- package/src/native-value.ts +2 -2
- package/src/object.ts +7 -2
- package/src/param-spec.ts +21 -22
- package/src/properties.ts +23 -9
- package/src/register-class.ts +66 -11
- package/src/registry.ts +43 -20
- package/src/signal.ts +32 -28
- package/src/t.ts +4 -1
- package/src/tuple.ts +18 -12
- package/src/value.ts +94 -19
- package/src/vfunc-call.ts +5 -1
- package/src/vfunc.ts +10 -3
package/src/registry.ts
CHANGED
|
@@ -11,11 +11,14 @@ import type { Mixin, MixinReceiver } from "./mixin.js";
|
|
|
11
11
|
import { TYPE_INVALID, type TypedClass, typeInterfaces, typeIsA, typeName, typeParent } from "./type.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Static side of class `C` with its construct signature preserved but the
|
|
15
|
-
*
|
|
14
|
+
* Static side of class `C` with its construct signature preserved but the members named `K`
|
|
15
|
+
* removed. A generated class lists every static it declares itself, so a static it narrows never
|
|
16
|
+
* has to stay assignable to the one it shadows. The signature is kept abstract so an abstract `C`
|
|
17
|
+
* survives it: a subclass extends the result, and only the subclass's own declarations decide
|
|
18
|
+
* which statics reach it.
|
|
16
19
|
*/
|
|
17
|
-
type StaticBase<C, K extends PropertyKey
|
|
18
|
-
(C extends new (...args: infer A) => infer R ? new (...args: A) => R : never);
|
|
20
|
+
type StaticBase<C, K extends PropertyKey> = Omit<C, K> &
|
|
21
|
+
(C extends abstract new (...args: infer A) => infer R ? abstract new (...args: A) => R : never);
|
|
19
22
|
|
|
20
23
|
/** One overridable vtable slot: where it sits in the vtable struct and how it is marshalled. */
|
|
21
24
|
type VfuncDescriptor = {
|
|
@@ -35,6 +38,12 @@ type VfuncDescriptor = {
|
|
|
35
38
|
argDescriptors: NativeRegisterClassVfunc["argDescriptors"];
|
|
36
39
|
/** Descriptor for the value the slot returns. */
|
|
37
40
|
returnDescriptor: NativeRegisterClassVfunc["returnDescriptor"];
|
|
41
|
+
/**
|
|
42
|
+
* GIR marks the slot's return value as one the bindings do not surface, so a call through the
|
|
43
|
+
* slot drops it and an implementation of the slot reports success in its place, while
|
|
44
|
+
* `VfuncDescriptor.returnDescriptor` keeps the C type the slot is called against either way.
|
|
45
|
+
*/
|
|
46
|
+
isReturnSkipped?: boolean;
|
|
38
47
|
/**
|
|
39
48
|
* The slot takes a trailing `GError**` that `VfuncDescriptor.argDescriptors` leaves out, the
|
|
40
49
|
* way GIR leaves it out of a callable's parameters. A call through the slot has to append it
|
|
@@ -48,6 +57,7 @@ type VfuncDescriptor = {
|
|
|
48
57
|
* overrides each one.
|
|
49
58
|
*/
|
|
50
59
|
type VfuncRegistry = Record<string, VfuncDescriptor>;
|
|
60
|
+
type WrapperBinding = (handle: ExternalObject<Handle>, instance: object) => void;
|
|
51
61
|
|
|
52
62
|
/**
|
|
53
63
|
* How one property an interface declares reaches the vtable, given as the interface's own accessor
|
|
@@ -320,24 +330,18 @@ function resolveComposedClass(runtimeType: bigint): AnyClass | null {
|
|
|
320
330
|
}
|
|
321
331
|
|
|
322
332
|
function wrapObject(value: unknown): object | null {
|
|
323
|
-
|
|
324
|
-
return null;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return getOrCreateWrapper(value as ExternalObject<Handle>);
|
|
333
|
+
return value == null ? null : getOrCreateWrapper(value as ExternalObject<Handle>);
|
|
328
334
|
}
|
|
329
335
|
|
|
330
|
-
function
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
const existing = getWrapper(handle);
|
|
336
|
+
function wrapCallScopedObject(value: unknown): object | null {
|
|
337
|
+
return value == null ? null : wrapperFor(value as ExternalObject<Handle>, bindCallScopedWrapper);
|
|
338
|
+
}
|
|
336
339
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
+
function existingWrapperFor(handle: ExternalObject<Handle>): object | null {
|
|
341
|
+
return handleMap.has(handle) ? handle : getWrapper(handle);
|
|
342
|
+
}
|
|
340
343
|
|
|
344
|
+
function createWrapper(handle: ExternalObject<Handle>): object {
|
|
341
345
|
const runtimeType: bigint = getType(handle);
|
|
342
346
|
|
|
343
347
|
if (runtimeType === TYPE_INVALID) {
|
|
@@ -350,12 +354,26 @@ function getOrCreateWrapper(handle: ExternalObject<Handle>): object {
|
|
|
350
354
|
throw new Error(`Expected registered GLib type, got type ${String(runtimeType)}`);
|
|
351
355
|
}
|
|
352
356
|
|
|
353
|
-
|
|
354
|
-
|
|
357
|
+
return Object.create(cls.prototype) as object;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function wrapperFor(handle: ExternalObject<Handle>, bind: WrapperBinding): object {
|
|
361
|
+
const existing = existingWrapperFor(handle);
|
|
362
|
+
|
|
363
|
+
if (existing) {
|
|
364
|
+
return existing;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const instance = createWrapper(handle);
|
|
368
|
+
bind(handle, instance);
|
|
355
369
|
|
|
356
370
|
return instance;
|
|
357
371
|
}
|
|
358
372
|
|
|
373
|
+
function getOrCreateWrapper(handle: ExternalObject<Handle>): object {
|
|
374
|
+
return wrapperFor(handle, registerWrapper);
|
|
375
|
+
}
|
|
376
|
+
|
|
359
377
|
function instanceClassName(instance: object): string {
|
|
360
378
|
return (instance as { constructor?: { name?: string } }).constructor?.name ?? "object";
|
|
361
379
|
}
|
|
@@ -376,6 +394,10 @@ function setHandle(instance: object, handle: ExternalObject<Handle>): void {
|
|
|
376
394
|
handleMap.set(instance, handle);
|
|
377
395
|
}
|
|
378
396
|
|
|
397
|
+
function bindCallScopedWrapper(handle: ExternalObject<Handle>, instance: object): void {
|
|
398
|
+
setHandle(instance, handle);
|
|
399
|
+
}
|
|
400
|
+
|
|
379
401
|
function registerWrapper(handle: ExternalObject<Handle>, instance: object): void {
|
|
380
402
|
setHandle(instance, handle);
|
|
381
403
|
setWrapper(handle, instance);
|
|
@@ -416,6 +438,7 @@ export {
|
|
|
416
438
|
instanceClassName,
|
|
417
439
|
registerWrapper,
|
|
418
440
|
resolveWrapperType,
|
|
441
|
+
wrapCallScopedObject,
|
|
419
442
|
wrapObject,
|
|
420
443
|
type InterfaceProperty,
|
|
421
444
|
type StaticBase,
|
package/src/signal.ts
CHANGED
|
@@ -43,6 +43,11 @@ type SignalConnectSpec = {
|
|
|
43
43
|
isAfter: boolean;
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
+
type EmitValues = {
|
|
47
|
+
values: ExternalObject<Handle>[];
|
|
48
|
+
reads: (() => unknown)[];
|
|
49
|
+
};
|
|
50
|
+
|
|
46
51
|
/** One argument of a signal emission: how to marshal it, plus the value to marshal. */
|
|
47
52
|
type EmitArg = Arg & {
|
|
48
53
|
/**
|
|
@@ -194,7 +199,7 @@ function connectBind(type: bigint, signal: string, callback: CallbackDescriptor)
|
|
|
194
199
|
*/
|
|
195
200
|
function connectSignal(instance: object, signal: string, spec: SignalConnectSpec): number {
|
|
196
201
|
const { callback, handler, isAfter } = spec;
|
|
197
|
-
const wrapped = wrapCallback(handler, callback, "
|
|
202
|
+
const wrapped = wrapCallback(handler, callback, "signal");
|
|
198
203
|
const type: bigint = (instance as TypedClass).__type__;
|
|
199
204
|
const connect = connectBind(type, signal, callback);
|
|
200
205
|
const handlerId = connect(getHandle(instance), signal, wrapped, isAfter ? 1 : 0) as number;
|
|
@@ -221,47 +226,46 @@ const createEmitValue = (arg: EmitArg): { value: ExternalObject<Handle>; read?:
|
|
|
221
226
|
return isInoutArg(arg) ? outValueForDescriptor(arg.type, arg.value) : outValueForDescriptor(arg.type);
|
|
222
227
|
};
|
|
223
228
|
|
|
229
|
+
const collectEmitValues = (instance: object, args: EmitArg[]): EmitValues => {
|
|
230
|
+
const collected: EmitValues = { values: [toValue(objectT("full"), instance)], reads: [] };
|
|
231
|
+
|
|
232
|
+
for (const arg of args) {
|
|
233
|
+
const { value, read } = createEmitValue(arg);
|
|
234
|
+
collected.values.push(value);
|
|
235
|
+
|
|
236
|
+
if (read) {
|
|
237
|
+
collected.reads.push(read);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return collected;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const readEmitOutputs = (reads: (() => unknown)[]): unknown[] => reads.map((read) => read());
|
|
245
|
+
|
|
224
246
|
/**
|
|
225
247
|
* Emits a signal on an instance with the given arguments and returns its result
|
|
226
248
|
* combined with any output-argument values.
|
|
227
249
|
* @param instance Emitter to emit the signal on.
|
|
228
250
|
* @param signal Signal name, optionally including a `::detail` suffix.
|
|
229
251
|
* @param args Arguments to pass, including output and inout arguments.
|
|
230
|
-
* @param
|
|
252
|
+
* @param returns Descriptor for the signal's return value, omitted when it returns void.
|
|
231
253
|
*/
|
|
232
|
-
function emitSignal(instance: object, signal: string, args: EmitArg[],
|
|
254
|
+
function emitSignal(instance: object, signal: string, args: EmitArg[], returns?: Descriptor): unknown {
|
|
233
255
|
const signalId = getSignalId(instance, signal);
|
|
234
256
|
const detail = getSignalDetailQuark(signal);
|
|
235
|
-
const values
|
|
236
|
-
const reads: (() => unknown)[] = [];
|
|
237
|
-
|
|
238
|
-
for (const arg of args) {
|
|
239
|
-
const { value, read } = createEmitValue(arg);
|
|
240
|
-
values.push(value);
|
|
257
|
+
const { values, reads } = collectEmitValues(instance, args);
|
|
241
258
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
}
|
|
259
|
+
if (returns === undefined) {
|
|
260
|
+
gSignalEmitv(values, signalId, detail, undefined);
|
|
246
261
|
|
|
247
|
-
|
|
248
|
-
const returnValue = newValueForDescriptor(returnDescriptor);
|
|
249
|
-
gSignalEmitv(values, signalId, detail, returnValue);
|
|
250
|
-
|
|
251
|
-
return packTupleResult(
|
|
252
|
-
reads.map((read) => read()),
|
|
253
|
-
fromValue(returnValue),
|
|
254
|
-
true,
|
|
255
|
-
);
|
|
262
|
+
return packTupleResult(readEmitOutputs(reads), undefined, false);
|
|
256
263
|
}
|
|
257
264
|
|
|
258
|
-
|
|
265
|
+
const returnValue = newValueForDescriptor(returns);
|
|
266
|
+
gSignalEmitv(values, signalId, detail, returnValue);
|
|
259
267
|
|
|
260
|
-
return packTupleResult(
|
|
261
|
-
reads.map((read) => read()),
|
|
262
|
-
undefined,
|
|
263
|
-
false,
|
|
264
|
-
);
|
|
268
|
+
return packTupleResult(readEmitOutputs(reads), fromValue(returnValue), true);
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
export {
|
package/src/t.ts
CHANGED
|
@@ -69,7 +69,7 @@ type T = {
|
|
|
69
69
|
slist: typeof helpers.slistT;
|
|
70
70
|
/** Builds a descriptor for a `GPtrArray` of items. */
|
|
71
71
|
ptrArray: typeof helpers.ptrArrayT;
|
|
72
|
-
/** Builds a descriptor for a `GArray` of items
|
|
72
|
+
/** Builds a descriptor for a `GArray` of items. */
|
|
73
73
|
gArray: typeof helpers.gArrayT;
|
|
74
74
|
/** Builds a descriptor for a `GByteArray`. */
|
|
75
75
|
byteArray: typeof helpers.byteArrayT;
|
|
@@ -77,6 +77,8 @@ type T = {
|
|
|
77
77
|
sizedArray: typeof helpers.sizedArrayT;
|
|
78
78
|
/** Builds a descriptor for a C array of a fixed length. */
|
|
79
79
|
fixedArray: typeof helpers.fixedArrayT;
|
|
80
|
+
/** Builds a descriptor for an out pointer into the buffer another argument supplied. */
|
|
81
|
+
cursorArray: typeof helpers.cursorArrayT;
|
|
80
82
|
/** Builds a descriptor for a function pointer, marshalling a JavaScript function into a native closure. */
|
|
81
83
|
callback: typeof helpers.callbackT;
|
|
82
84
|
/**
|
|
@@ -127,6 +129,7 @@ const t: T = {
|
|
|
127
129
|
byteArray: helpers.byteArrayT,
|
|
128
130
|
sizedArray: helpers.sizedArrayT,
|
|
129
131
|
fixedArray: helpers.fixedArrayT,
|
|
132
|
+
cursorArray: helpers.cursorArrayT,
|
|
130
133
|
callback: helpers.callbackT,
|
|
131
134
|
fn,
|
|
132
135
|
};
|
package/src/tuple.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import type { Descriptor } from "@gtkx/native";
|
|
2
|
+
|
|
3
|
+
type SplitResult = { primary: unknown; outValues: unknown[] };
|
|
4
|
+
|
|
5
|
+
const hasSurfacedPrimary = (returnDescriptor: Descriptor, isReturnSkipped: boolean | undefined): boolean =>
|
|
6
|
+
returnDescriptor.kind !== "void" && isReturnSkipped !== true;
|
|
7
|
+
|
|
1
8
|
const packTupleResult = (outs: unknown[], primary: unknown, hasPrimary: boolean): unknown => {
|
|
2
9
|
if (hasPrimary) {
|
|
3
10
|
return outs.length === 0 ? primary : [primary, ...outs];
|
|
@@ -14,19 +21,15 @@ const packTupleResult = (outs: unknown[], primary: unknown, hasPrimary: boolean)
|
|
|
14
21
|
return outs;
|
|
15
22
|
};
|
|
16
23
|
|
|
17
|
-
const
|
|
18
|
-
result
|
|
19
|
-
|
|
20
|
-
outCount: number,
|
|
21
|
-
): { primary: unknown; outValues: unknown[] } => {
|
|
22
|
-
if (hasPrimary) {
|
|
23
|
-
if (Array.isArray(result)) {
|
|
24
|
-
return { primary: result[0], outValues: result.slice(1) };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return { primary: result, outValues: [] };
|
|
24
|
+
const splitPrimaryResult = (result: unknown, outCount: number): SplitResult => {
|
|
25
|
+
if (outCount > 0 && Array.isArray(result)) {
|
|
26
|
+
return { primary: result[0], outValues: result.slice(1) };
|
|
28
27
|
}
|
|
29
28
|
|
|
29
|
+
return { primary: result, outValues: [] };
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const splitOutResult = (result: unknown, outCount: number): SplitResult => {
|
|
30
33
|
if (outCount === 1) {
|
|
31
34
|
return { primary: undefined, outValues: [result] };
|
|
32
35
|
}
|
|
@@ -34,4 +37,7 @@ const splitTupleResult = (
|
|
|
34
37
|
return { primary: undefined, outValues: Array.isArray(result) ? result : [] };
|
|
35
38
|
};
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
const splitTupleResult = (result: unknown, hasPrimary: boolean, outCount: number): SplitResult =>
|
|
41
|
+
hasPrimary ? splitPrimaryResult(result, outCount) : splitOutResult(result, outCount);
|
|
42
|
+
|
|
43
|
+
export { hasSurfacedPrimary, packTupleResult, splitTupleResult };
|
package/src/value.ts
CHANGED
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
boxedT,
|
|
10
10
|
float32T,
|
|
11
11
|
float64T,
|
|
12
|
+
type FundamentalDescriptor,
|
|
13
|
+
fundamentalLifecycleFor,
|
|
14
|
+
fundamentalT,
|
|
12
15
|
int8T,
|
|
13
16
|
int32T,
|
|
14
17
|
objectT,
|
|
@@ -61,10 +64,13 @@ type ValueType = {
|
|
|
61
64
|
|
|
62
65
|
type ValueGetter = (value: ExternalObject<Handle>) => unknown;
|
|
63
66
|
type ValueWriter = ValueType["set"];
|
|
67
|
+
type ValueNarrower = (jsValue: unknown) => unknown;
|
|
64
68
|
|
|
65
69
|
const setBoxedCache = createBindCache();
|
|
66
70
|
const setStaticBoxedCache = createBindCache();
|
|
67
71
|
const dupBoxedCache = createBindCache();
|
|
72
|
+
const setInstanceCache = createBindCache();
|
|
73
|
+
const peekPointerCache = createBindCache();
|
|
68
74
|
const gValueInit = bind(LIB, "g_value_init", [VALUE_T, biguint64T], voidT);
|
|
69
75
|
const gValueCopy = bind(LIB, "g_value_copy", [VALUE_T, VALUE_T], voidT);
|
|
70
76
|
const booleanValueType = bindValueType("boolean", booleanT);
|
|
@@ -86,9 +92,10 @@ const objectValueType = bindValueType("object", objectT("borrowed"));
|
|
|
86
92
|
const paramValueType = bindValueType("param", PARAM_T);
|
|
87
93
|
const variantValueType = bindValueType("variant", VARIANT_T);
|
|
88
94
|
const pointerValueType = bindValueType("pointer", uint64T);
|
|
95
|
+
const setStrvBoxed = bind(LIB, "g_value_set_boxed", [VALUE_T, arrayT(stringT("borrowed"))], voidT);
|
|
89
96
|
|
|
90
97
|
const strvValueType: ValueType = {
|
|
91
|
-
set:
|
|
98
|
+
set: setStrvValue,
|
|
92
99
|
get: bind(LIB, "g_value_get_boxed", [VALUE_T], arrayT(stringT("borrowed"))),
|
|
93
100
|
};
|
|
94
101
|
|
|
@@ -112,7 +119,6 @@ const PLAIN_VALUE_TYPES: Partial<Record<Descriptor["kind"], ValueType>> = {
|
|
|
112
119
|
|
|
113
120
|
const PLAIN_VALUE_GETTERS: Map<bigint, ValueGetter> = new Map([
|
|
114
121
|
[TYPE_BOOLEAN, booleanValueType.get],
|
|
115
|
-
[TYPE_GTYPE, typeValueType.get],
|
|
116
122
|
[TYPE_CHAR, scharValueType.get],
|
|
117
123
|
[TYPE_UCHAR, ucharValueType.get],
|
|
118
124
|
[TYPE_INT, intValueType.get],
|
|
@@ -129,7 +135,6 @@ const PLAIN_VALUE_GETTERS: Map<bigint, ValueGetter> = new Map([
|
|
|
129
135
|
|
|
130
136
|
const PLAIN_VALUE_SETTERS: Map<bigint, ValueType["set"]> = new Map([
|
|
131
137
|
[TYPE_BOOLEAN, booleanValueType.set],
|
|
132
|
-
[TYPE_GTYPE, typeValueType.set],
|
|
133
138
|
[TYPE_CHAR, scharValueType.set],
|
|
134
139
|
[TYPE_UCHAR, ucharValueType.set],
|
|
135
140
|
[TYPE_INT, intValueType.set],
|
|
@@ -182,6 +187,46 @@ const boxedValueType = (type: bigint): ValueType => {
|
|
|
182
187
|
const enumOrFlagsValueType = (type: bigint): ValueType =>
|
|
183
188
|
typeFundamental(type) === TYPE_FLAGS ? flagsValueType : enumValueType;
|
|
184
189
|
|
|
190
|
+
function unsupportedFundamental(type: bigint): never {
|
|
191
|
+
throw new Error(`Unsupported fundamental type '${typeName(type) ?? String(type)}' for value`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const setInstanceBind = (fundamental: bigint, descriptor: FundamentalDescriptor) =>
|
|
195
|
+
setInstanceCache(String(fundamental), LIB, "g_value_set_instance", [VALUE_T, descriptor], voidT);
|
|
196
|
+
|
|
197
|
+
const peekPointerBind = (fundamental: bigint, descriptor: FundamentalDescriptor) =>
|
|
198
|
+
peekPointerCache(String(fundamental), LIB, "g_value_peek_pointer", [VALUE_T], descriptor);
|
|
199
|
+
|
|
200
|
+
const customFundamentalDescriptor = (fundamental: bigint): FundamentalDescriptor | undefined => {
|
|
201
|
+
const name = typeName(fundamental);
|
|
202
|
+
|
|
203
|
+
if (name === null) {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const lifecycle = fundamentalLifecycleFor(name);
|
|
208
|
+
|
|
209
|
+
if (lifecycle === undefined) {
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return fundamentalT(lifecycle.sharedLibrary, lifecycle.refFnName, lifecycle.unrefFnName, {
|
|
214
|
+
ownership: "borrowed",
|
|
215
|
+
typeName: name,
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const customFundamentalValueType = (type: bigint): ValueType | undefined => {
|
|
220
|
+
const fundamental = typeFundamental(type);
|
|
221
|
+
const descriptor = customFundamentalDescriptor(fundamental);
|
|
222
|
+
|
|
223
|
+
if (descriptor === undefined) {
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return { set: setInstanceBind(fundamental, descriptor), get: peekPointerBind(fundamental, descriptor) };
|
|
228
|
+
};
|
|
229
|
+
|
|
185
230
|
const fundamentalValueType = (type: bigint): ValueType => {
|
|
186
231
|
switch (typeFundamental(type)) {
|
|
187
232
|
case TYPE_PARAM: {
|
|
@@ -194,7 +239,7 @@ const fundamentalValueType = (type: bigint): ValueType => {
|
|
|
194
239
|
return boxedValueType(type);
|
|
195
240
|
}
|
|
196
241
|
default: {
|
|
197
|
-
|
|
242
|
+
return customFundamentalValueType(type) ?? unsupportedFundamental(type);
|
|
198
243
|
}
|
|
199
244
|
}
|
|
200
245
|
};
|
|
@@ -332,6 +377,10 @@ function setStringValue(value: ExternalObject<Handle>, nativeValue: unknown): vo
|
|
|
332
377
|
stringValueType.set(value, nativeValue ?? null);
|
|
333
378
|
}
|
|
334
379
|
|
|
380
|
+
function setStrvValue(value: ExternalObject<Handle>, nativeValue: unknown): void {
|
|
381
|
+
setStrvBoxed(value, nativeValue ?? null);
|
|
382
|
+
}
|
|
383
|
+
|
|
335
384
|
function setPointerValue(value: ExternalObject<Handle>, nativeValue: unknown): void {
|
|
336
385
|
if (nativeValue != null) {
|
|
337
386
|
throw new Error("G_TYPE_POINTER non-null values cannot be marshalled from JS");
|
|
@@ -350,22 +399,51 @@ function setBoxedFromValue(value: ExternalObject<Handle>, nativeValue: unknown):
|
|
|
350
399
|
setBoxedValue(value, nativeValue ?? null);
|
|
351
400
|
}
|
|
352
401
|
|
|
353
|
-
const
|
|
402
|
+
const customFundamentalGetter = (type: bigint): ValueGetter | undefined => {
|
|
403
|
+
const valueType = customFundamentalValueType(type);
|
|
404
|
+
|
|
405
|
+
if (valueType === undefined) {
|
|
406
|
+
return undefined;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return (value) => wrapHandle(valueType.get(value) as ExternalObject<Handle> | null, getWrapperClass(type));
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
const customFundamentalSetter = (type: bigint): ValueType["set"] | undefined => {
|
|
413
|
+
const valueType = customFundamentalValueType(type);
|
|
414
|
+
|
|
415
|
+
return valueType === undefined ? undefined : handleSetter(valueType);
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
const builtInValueGetter = (fundamental: bigint): ValueGetter | undefined =>
|
|
354
419
|
PLAIN_VALUE_GETTERS.get(fundamental) ?? wrappedValueGetter(fundamental);
|
|
355
420
|
|
|
356
|
-
const
|
|
421
|
+
const builtInValueSetter = (fundamental: bigint): ValueType["set"] | undefined =>
|
|
357
422
|
PLAIN_VALUE_SETTERS.get(fundamental) ?? WRAPPED_VALUE_SETTERS.get(fundamental);
|
|
358
423
|
|
|
359
|
-
|
|
360
|
-
|
|
424
|
+
const exactValueType = (type: bigint): ValueType | undefined => {
|
|
425
|
+
if (type === TYPE_GTYPE) {
|
|
426
|
+
return typeValueType;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return type === getStrvType() ? strvValueType : undefined;
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const resolveValueGetter = (type: bigint): ValueGetter | undefined =>
|
|
433
|
+
exactValueType(type)?.get ?? builtInValueGetter(typeFundamental(type)) ?? customFundamentalGetter(type);
|
|
434
|
+
|
|
435
|
+
const resolveValueSetter = (type: bigint): ValueType["set"] | undefined =>
|
|
436
|
+
exactValueType(type)?.set ?? builtInValueSetter(typeFundamental(type)) ?? customFundamentalSetter(type);
|
|
437
|
+
|
|
438
|
+
const holdsUnchanged: ValueNarrower = (jsValue) => jsValue;
|
|
439
|
+
const holdsAsFloat: ValueNarrower = (jsValue) => Math.fround(jsValue as number);
|
|
440
|
+
|
|
441
|
+
function valueNarrowerFor(type: bigint): ValueNarrower {
|
|
442
|
+
return typeFundamental(type) === TYPE_FLOAT ? holdsAsFloat : holdsUnchanged;
|
|
361
443
|
}
|
|
362
444
|
|
|
363
445
|
function valueWriterFor(type: bigint): ValueWriter {
|
|
364
|
-
|
|
365
|
-
return setStrvValue;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
const set = resolveValueSetter(typeFundamental(type));
|
|
446
|
+
const set = resolveValueSetter(type);
|
|
369
447
|
|
|
370
448
|
if (set === undefined) {
|
|
371
449
|
throw new Error(`Unsupported type for intoValue: ${typeName(type) ?? String(type)}`);
|
|
@@ -407,12 +485,7 @@ function toValue(descriptor: Descriptor, value: unknown): ExternalObject<Handle>
|
|
|
407
485
|
|
|
408
486
|
function fromValue(value: ExternalObject<Handle>): unknown {
|
|
409
487
|
const type = getValueType(value);
|
|
410
|
-
|
|
411
|
-
if (type === getStrvType()) {
|
|
412
|
-
return strvValueType.get(value);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const get = resolveValueGetter(typeFundamental(type));
|
|
488
|
+
const get = resolveValueGetter(type);
|
|
416
489
|
|
|
417
490
|
if (get === undefined) {
|
|
418
491
|
throw new Error(`Unsupported type for fromValue: ${typeName(type) ?? String(type)}`);
|
|
@@ -463,6 +536,8 @@ export {
|
|
|
463
536
|
outValueForDescriptor,
|
|
464
537
|
outValueForBoxedDescriptor,
|
|
465
538
|
inoutValueForBoxedDescriptor,
|
|
539
|
+
type ValueNarrower,
|
|
540
|
+
valueNarrowerFor,
|
|
466
541
|
type ValueWriter,
|
|
467
542
|
valueWriterFor,
|
|
468
543
|
};
|
package/src/vfunc-call.ts
CHANGED
|
@@ -82,7 +82,11 @@ function buildInvoker(slot: ResolvedSlot, instanceType: bigint | undefined, call
|
|
|
82
82
|
|
|
83
83
|
const shaped = fromNativeCallable(
|
|
84
84
|
bindVfunc(bindOptionsFor(slot, instanceType, args, label)),
|
|
85
|
-
{
|
|
85
|
+
{
|
|
86
|
+
args,
|
|
87
|
+
returns: descriptor.returnDescriptor,
|
|
88
|
+
canThrow,
|
|
89
|
+
},
|
|
86
90
|
takeRefSeeds,
|
|
87
91
|
);
|
|
88
92
|
|
package/src/vfunc.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Descriptor } from "@gtkx/native";
|
|
|
2
2
|
import { type AnyClass, getParentClass, walkClassChain } from "@gtkx/utils";
|
|
3
3
|
import type { Arg } from "./arg.js";
|
|
4
4
|
import { isCallerAllocatedOut } from "./callback.js";
|
|
5
|
+
import { foldedLengthSources } from "./folded-lengths.js";
|
|
5
6
|
import { getInterfaceVfuncRegistry, getVfuncRegistry, type VfuncDescriptor } from "./registry.js";
|
|
6
7
|
|
|
7
8
|
function findClassVfuncDescriptor(klass: AnyClass, methodName: string): VfuncDescriptor | null {
|
|
@@ -12,9 +13,13 @@ function findInterfaceVfuncDescriptor(interfaceGtype: bigint, methodName: string
|
|
|
12
13
|
return getInterfaceVfuncRegistry(interfaceGtype)?.[methodName];
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
function vfuncArg(descriptor: Descriptor): Arg {
|
|
16
|
+
function vfuncArg(descriptor: Descriptor, isFoldedLength: boolean): Arg {
|
|
16
17
|
if (descriptor.kind === "ref") {
|
|
17
|
-
return {
|
|
18
|
+
return {
|
|
19
|
+
type: descriptor.innerDescriptor,
|
|
20
|
+
direction: descriptor.inout === true ? "inout" : "out",
|
|
21
|
+
isConsumed: isFoldedLength,
|
|
22
|
+
};
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
if (isCallerAllocatedOut(descriptor)) {
|
|
@@ -25,7 +30,9 @@ function vfuncArg(descriptor: Descriptor): Arg {
|
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
function vfuncArgs(descriptor: VfuncDescriptor): Arg[] {
|
|
28
|
-
|
|
33
|
+
const lengths = foldedLengthSources(descriptor);
|
|
34
|
+
|
|
35
|
+
return descriptor.argDescriptors.map((argDescriptor, index) => vfuncArg(argDescriptor, lengths.has(index)));
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
export { findClassVfuncDescriptor, findInterfaceVfuncDescriptor, vfuncArgs };
|