@gtkx/runtime 1.5.0 → 2.0.0-beta.1
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 +5 -5
- package/dist/application-class.d.ts +1 -1
- package/dist/application-class.d.ts.map +1 -1
- package/dist/application-class.js +1 -2
- package/dist/application-class.js.map +1 -1
- package/dist/arg.d.ts +4 -1
- package/dist/arg.d.ts.map +1 -1
- package/dist/arg.js.map +1 -1
- package/dist/bind.d.ts.map +1 -1
- package/dist/bind.js +1 -9
- package/dist/bind.js.map +1 -1
- package/dist/callback.d.ts +6 -1
- package/dist/callback.d.ts.map +1 -1
- package/dist/callback.js +33 -21
- package/dist/callback.js.map +1 -1
- package/dist/closure.d.ts +3 -1
- package/dist/closure.d.ts.map +1 -1
- package/dist/closure.js +17 -6
- package/dist/closure.js.map +1 -1
- package/dist/descriptors.d.ts +36 -36
- package/dist/descriptors.d.ts.map +1 -1
- package/dist/descriptors.js +65 -26
- package/dist/descriptors.js.map +1 -1
- package/dist/element-metadata.d.ts +9 -0
- package/dist/element-metadata.d.ts.map +1 -0
- package/dist/element-metadata.js +14 -0
- package/dist/element-metadata.js.map +1 -0
- package/dist/fn.d.ts +8 -2
- package/dist/fn.d.ts.map +1 -1
- package/dist/fn.js +43 -13
- package/dist/fn.js.map +1 -1
- package/dist/folded-lengths.d.ts +2 -1
- package/dist/folded-lengths.d.ts.map +1 -1
- package/dist/folded-lengths.js +17 -7
- package/dist/folded-lengths.js.map +1 -1
- package/dist/index.d.ts +4 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -26
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +5 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -2
- package/dist/internal.js.map +1 -1
- package/dist/native-value.d.ts +9 -1
- package/dist/native-value.d.ts.map +1 -1
- package/dist/native-value.js +41 -5
- package/dist/native-value.js.map +1 -1
- package/dist/properties.d.ts +1 -1
- package/dist/properties.d.ts.map +1 -1
- package/dist/properties.js +2 -11
- package/dist/properties.js.map +1 -1
- package/dist/register-class.d.ts +45 -249
- package/dist/register-class.d.ts.map +1 -1
- package/dist/register-class.js +38 -1
- package/dist/register-class.js.map +1 -1
- package/dist/registry.d.ts +26 -3
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +75 -20
- package/dist/registry.js.map +1 -1
- package/dist/signal.d.ts.map +1 -1
- package/dist/signal.js +9 -22
- package/dist/signal.js.map +1 -1
- package/dist/t.d.ts +5 -21
- package/dist/t.d.ts.map +1 -1
- package/dist/t.js +1 -5
- package/dist/t.js.map +1 -1
- package/dist/type.d.ts +10 -1
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js +21 -2
- package/dist/type.js.map +1 -1
- package/dist/value.d.ts.map +1 -1
- package/dist/value.js +26 -4
- package/dist/value.js.map +1 -1
- package/dist/variant.d.ts +2 -6
- package/dist/variant.d.ts.map +1 -1
- package/dist/variant.js.map +1 -1
- package/dist/vfunc-call.d.ts.map +1 -1
- package/dist/vfunc-call.js +2 -11
- package/dist/vfunc-call.js.map +1 -1
- package/package.json +15 -6
- package/src/application-class.ts +2 -2
- package/src/arg.ts +4 -1
- package/src/bind.ts +1 -12
- package/src/callback.ts +53 -29
- package/src/closure.ts +31 -6
- package/src/descriptors.ts +126 -44
- package/src/element-metadata.ts +24 -0
- package/src/fn.ts +64 -15
- package/src/folded-lengths.ts +23 -10
- package/src/index.ts +5 -24
- package/src/internal.ts +9 -2
- package/src/native-value.ts +54 -5
- package/src/properties.ts +3 -16
- package/src/register-class.ts +104 -249
- package/src/registry.ts +110 -19
- package/src/signal.ts +9 -34
- package/src/t.ts +5 -21
- package/src/type.ts +34 -1
- package/src/value.ts +37 -5
- package/src/variant.ts +2 -6
- package/src/vfunc-call.ts +3 -16
package/src/registry.ts
CHANGED
|
@@ -10,11 +10,12 @@ import {
|
|
|
10
10
|
setWrapper,
|
|
11
11
|
} from "@gtkx/native";
|
|
12
12
|
import { type AnyClass, walkClassChain } from "@gtkx/utils";
|
|
13
|
-
import { copyLayerMembers, type Mixin, type MixinReceiver } from "./mixin.js";
|
|
13
|
+
import { copyLayerMembers, installMixins, type Mixin, type MixinReceiver } from "./mixin.js";
|
|
14
14
|
import {
|
|
15
15
|
TYPE_INVALID,
|
|
16
16
|
TYPE_OBJECT,
|
|
17
17
|
type TypedClass,
|
|
18
|
+
typeFundamental,
|
|
18
19
|
typeInterfaces,
|
|
19
20
|
typeIsA,
|
|
20
21
|
typeName,
|
|
@@ -31,6 +32,22 @@ import {
|
|
|
31
32
|
type StaticBase<C, K extends PropertyKey> = Omit<C, K> &
|
|
32
33
|
(C extends abstract new (...args: infer A) => infer R ? abstract new (...args: A) => R : never);
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Static side of class `C` with its construct signature retargeted to produce `I`. A generated
|
|
37
|
+
* wrapper class is declared locally and exported as a registered constant; its instance type is
|
|
38
|
+
* exported as an interface extending the local class so declaration merging and module
|
|
39
|
+
* augmentation keep working, and this type makes constructing the constant produce that interface.
|
|
40
|
+
*/
|
|
41
|
+
type WrapperClass<C, I> = Omit<C, "prototype"> & {
|
|
42
|
+
/** Prototype retyped to the exported instance interface, so `instanceof` narrows to it. */
|
|
43
|
+
prototype: I;
|
|
44
|
+
} &
|
|
45
|
+
(C extends new (...args: infer A) => unknown
|
|
46
|
+
? new (...args: A) => I
|
|
47
|
+
: C extends abstract new (...args: infer A) => unknown
|
|
48
|
+
? abstract new (...args: A) => I
|
|
49
|
+
: never);
|
|
50
|
+
|
|
34
51
|
/** One overridable vtable slot: where it sits in the vtable struct and how it is marshalled. */
|
|
35
52
|
type VfuncDescriptor = {
|
|
36
53
|
/** GIR name of the type struct holding the slot, without its namespace, such as `WidgetClass`. */
|
|
@@ -374,6 +391,31 @@ function registerInterface(cls: AnyClass, type: bigint, mixin: Mixin, layout?: I
|
|
|
374
391
|
}
|
|
375
392
|
}
|
|
376
393
|
|
|
394
|
+
/**
|
|
395
|
+
* Copies the members of registered interfaces onto a wrapper class, resolving each interface's
|
|
396
|
+
* mixin through the registry rather than taking the mixin itself, so a class states which
|
|
397
|
+
* interfaces it implements by referencing their classes. The interfaces must already be
|
|
398
|
+
* registered through `registerInterface`; generated code guarantees that by declaring interfaces
|
|
399
|
+
* ahead of the classes that implement them.
|
|
400
|
+
*
|
|
401
|
+
* @param cls Wrapper class adopting the interfaces.
|
|
402
|
+
* @param interfaces Registered interface classes to adopt, in order.
|
|
403
|
+
* @throws If an entry is not a registered interface.
|
|
404
|
+
*/
|
|
405
|
+
function installInterfaces(cls: AnyClass, interfaces: AnyClass[]): void {
|
|
406
|
+
const mixins = interfaces.map((iface) => {
|
|
407
|
+
const mixin = getInterfaceMixin(getClassType(iface));
|
|
408
|
+
|
|
409
|
+
if (mixin === undefined) {
|
|
410
|
+
throw new Error(`installInterfaces: ${iface.name} is not a registered interface`);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return mixin;
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
installMixins(cls, mixins);
|
|
417
|
+
}
|
|
418
|
+
|
|
377
419
|
/**
|
|
378
420
|
* Wraps a native handle in a JS wrapper instance. With no class, resolves and
|
|
379
421
|
* reuses the wrapper for the handle's runtime GType (composing interface mixins),
|
|
@@ -443,6 +485,23 @@ function getWrapperClass(type: bigint): AnyClass {
|
|
|
443
485
|
return cls;
|
|
444
486
|
}
|
|
445
487
|
|
|
488
|
+
function getExactWrapperClass(type: bigint, label?: string): AnyClass {
|
|
489
|
+
if (type === TYPE_INVALID) {
|
|
490
|
+
throw new Error(`No GType is registered under '${label ?? String(type)}'`);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const cls = classRegistry.get(type);
|
|
494
|
+
|
|
495
|
+
if (cls === undefined) {
|
|
496
|
+
throw new Error(
|
|
497
|
+
`No wrapper class is registered for '${label ?? typeName(type) ?? String(type)}': ` +
|
|
498
|
+
"its module was dropped from the bundle or never imported",
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return cls;
|
|
503
|
+
}
|
|
504
|
+
|
|
446
505
|
function resolveWrapperClass(type: bigint): AnyClass | null {
|
|
447
506
|
let currentType = type;
|
|
448
507
|
|
|
@@ -491,7 +550,35 @@ function createComposedClass(base: AnyClass, runtimeType: bigint): AnyClass {
|
|
|
491
550
|
return applied.size === 0 ? base : cls;
|
|
492
551
|
}
|
|
493
552
|
|
|
494
|
-
function
|
|
553
|
+
function isWrappableBase(fallbackType: bigint): boolean {
|
|
554
|
+
return fallbackType === TYPE_INVALID || typeFundamental(fallbackType) === TYPE_OBJECT;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function isBetweenWalkAndRuntime(fallbackType: bigint, walkedType: bigint, runtimeType: bigint): boolean {
|
|
558
|
+
return fallbackType !== walkedType && typeIsA(fallbackType, walkedType) && typeIsA(runtimeType, fallbackType);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function chooseWrapBase(walked: AnyClass | null, fallback: AnyClass | undefined, runtimeType: bigint): AnyClass | null {
|
|
562
|
+
if (fallback === undefined || !isWrappableBase(getClassType(fallback))) {
|
|
563
|
+
return walked;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (walked === null || isBetweenWalkAndRuntime(getClassType(fallback), getClassType(walked), runtimeType)) {
|
|
567
|
+
return fallback;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return walked;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function stampComposedClass(composed: AnyClass, runtimeType: bigint): AnyClass {
|
|
574
|
+
setClassType(composed, runtimeType);
|
|
575
|
+
wrapperClasses.add(composed);
|
|
576
|
+
composedClassRegistry.set(runtimeType, composed);
|
|
577
|
+
|
|
578
|
+
return composed;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function resolveComposedClass(runtimeType: bigint, fallbackClass?: () => AnyClass): AnyClass | null {
|
|
495
582
|
const exact = classRegistry.get(runtimeType);
|
|
496
583
|
|
|
497
584
|
if (exact) {
|
|
@@ -504,7 +591,8 @@ function resolveComposedClass(runtimeType: bigint): AnyClass | null {
|
|
|
504
591
|
return cached;
|
|
505
592
|
}
|
|
506
593
|
|
|
507
|
-
const
|
|
594
|
+
const walked = resolveWrapperClass(runtimeType);
|
|
595
|
+
const base = chooseWrapBase(walked, fallbackClass?.(), runtimeType);
|
|
508
596
|
|
|
509
597
|
if (base === null) {
|
|
510
598
|
return null;
|
|
@@ -512,37 +600,37 @@ function resolveComposedClass(runtimeType: bigint): AnyClass | null {
|
|
|
512
600
|
|
|
513
601
|
const composed = createComposedClass(base, runtimeType);
|
|
514
602
|
|
|
515
|
-
if (composed
|
|
516
|
-
return
|
|
603
|
+
if (composed !== base) {
|
|
604
|
+
return stampComposedClass(composed, runtimeType);
|
|
517
605
|
}
|
|
518
606
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
607
|
+
if (base === walked) {
|
|
608
|
+
return base;
|
|
609
|
+
}
|
|
522
610
|
|
|
523
|
-
return
|
|
611
|
+
return stampComposedClass(class extends base {}, runtimeType);
|
|
524
612
|
}
|
|
525
613
|
|
|
526
|
-
function wrapObject(value: unknown): object | null {
|
|
527
|
-
return value == null ? null : getOrCreateWrapper(value as ExternalObject<Handle
|
|
614
|
+
function wrapObject(value: unknown, fallbackClass?: () => AnyClass): object | null {
|
|
615
|
+
return value == null ? null : getOrCreateWrapper(value as ExternalObject<Handle>, fallbackClass);
|
|
528
616
|
}
|
|
529
617
|
|
|
530
|
-
function wrapCallScopedObject(value: unknown): object | null {
|
|
531
|
-
return value == null ? null : wrapperFor(value as ExternalObject<Handle>, bindCallScopedWrapper);
|
|
618
|
+
function wrapCallScopedObject(value: unknown, fallbackClass?: () => AnyClass): object | null {
|
|
619
|
+
return value == null ? null : wrapperFor(value as ExternalObject<Handle>, bindCallScopedWrapper, fallbackClass);
|
|
532
620
|
}
|
|
533
621
|
|
|
534
622
|
function existingWrapperFor(handle: ExternalObject<Handle>): object | null {
|
|
535
623
|
return handleMap.has(handle) ? handle : getWrapper(handle);
|
|
536
624
|
}
|
|
537
625
|
|
|
538
|
-
function createWrapper(handle: ExternalObject<Handle
|
|
626
|
+
function createWrapper(handle: ExternalObject<Handle>, fallbackClass?: () => AnyClass): object {
|
|
539
627
|
const runtimeType: bigint = getType(handle);
|
|
540
628
|
|
|
541
629
|
if (runtimeType === TYPE_INVALID) {
|
|
542
630
|
throw new Error("Cannot resolve runtime GLib type from handle");
|
|
543
631
|
}
|
|
544
632
|
|
|
545
|
-
const cls = resolveComposedClass(runtimeType);
|
|
633
|
+
const cls = resolveComposedClass(runtimeType, fallbackClass);
|
|
546
634
|
|
|
547
635
|
if (!cls) {
|
|
548
636
|
throw new Error(`Expected registered GLib type, got type ${String(runtimeType)}`);
|
|
@@ -551,21 +639,21 @@ function createWrapper(handle: ExternalObject<Handle>): object {
|
|
|
551
639
|
return Object.create(cls.prototype) as object;
|
|
552
640
|
}
|
|
553
641
|
|
|
554
|
-
function wrapperFor(handle: ExternalObject<Handle>, bind: WrapperBinding): object {
|
|
642
|
+
function wrapperFor(handle: ExternalObject<Handle>, bind: WrapperBinding, fallbackClass?: () => AnyClass): object {
|
|
555
643
|
const existing = existingWrapperFor(handle);
|
|
556
644
|
|
|
557
645
|
if (existing) {
|
|
558
646
|
return existing;
|
|
559
647
|
}
|
|
560
648
|
|
|
561
|
-
const instance = createWrapper(handle);
|
|
649
|
+
const instance = createWrapper(handle, fallbackClass);
|
|
562
650
|
bind(handle, instance);
|
|
563
651
|
|
|
564
652
|
return instance;
|
|
565
653
|
}
|
|
566
654
|
|
|
567
|
-
function getOrCreateWrapper(handle: ExternalObject<Handle
|
|
568
|
-
return wrapperFor(handle, registerWrapper);
|
|
655
|
+
function getOrCreateWrapper(handle: ExternalObject<Handle>, fallbackClass?: () => AnyClass): object {
|
|
656
|
+
return wrapperFor(handle, registerWrapper, fallbackClass);
|
|
569
657
|
}
|
|
570
658
|
|
|
571
659
|
function instanceClassName(instance: object): string {
|
|
@@ -639,8 +727,10 @@ export {
|
|
|
639
727
|
registerWrapperClass,
|
|
640
728
|
registerWrapperClassResolver,
|
|
641
729
|
registerInterface,
|
|
730
|
+
installInterfaces,
|
|
642
731
|
wrapFundamentalHandle,
|
|
643
732
|
wrapHandle,
|
|
733
|
+
getExactWrapperClass,
|
|
644
734
|
getWrapperClass,
|
|
645
735
|
resolveWrapperClass,
|
|
646
736
|
getHandle,
|
|
@@ -657,5 +747,6 @@ export {
|
|
|
657
747
|
type InterfaceProperty,
|
|
658
748
|
type StaticBase,
|
|
659
749
|
type VfuncDescriptor,
|
|
750
|
+
type WrapperClass,
|
|
660
751
|
type WrapperClassResolver,
|
|
661
752
|
};
|
package/src/signal.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Descriptor, ExternalObject, Handle } from "@gtkx/native";
|
|
2
|
-
import {
|
|
2
|
+
import { toCamelIdentifier, upperFirst } from "@gtkx/utils";
|
|
3
3
|
import { type Arg, isCallerAllocatedArg, isInoutArg, isOutputArg } from "./arg.js";
|
|
4
|
-
import { bind
|
|
4
|
+
import { bind } from "./bind.js";
|
|
5
5
|
import { wrapCallback } from "./callback.js";
|
|
6
|
-
import { toClosure } from "./closure.js";
|
|
6
|
+
import { newCCallbackClosure, toClosure } from "./closure.js";
|
|
7
7
|
import {
|
|
8
8
|
arrayT,
|
|
9
9
|
biguint64T,
|
|
@@ -69,7 +69,6 @@ type EmitArg = Arg & {
|
|
|
69
69
|
value?: unknown;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
const connectCache = createBindCache();
|
|
73
72
|
const connectionTable: WeakMap<object, Map<string, Set<number>>> = new WeakMap();
|
|
74
73
|
const gQuarkFromString = bind(LIB, "g_quark_from_string", [stringT("borrowed")], uint32T);
|
|
75
74
|
const gSignalLookup = bind(LIB, "g_signal_lookup", [stringT("borrowed"), biguint64T], uint32T);
|
|
@@ -129,21 +128,8 @@ const isSignalHandlerConnected = (instance: object, handlerId: number): boolean
|
|
|
129
128
|
gSignalHandlerIsConnected(getHandle(instance), handlerId) as boolean;
|
|
130
129
|
|
|
131
130
|
const trackConnection = (instance: object, signal: string, handlerId: number): void => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (!bySignal) {
|
|
135
|
-
bySignal = new Map();
|
|
136
|
-
connectionTable.set(instance, bySignal);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
let handlerIds = bySignal.get(signal);
|
|
140
|
-
|
|
141
|
-
if (!handlerIds) {
|
|
142
|
-
handlerIds = new Set();
|
|
143
|
-
bySignal.set(signal, handlerIds);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
handlerIds.add(handlerId);
|
|
131
|
+
const bySignal = connectionTable.getOrInsertComputed(instance, () => new Map<string, Set<number>>());
|
|
132
|
+
bySignal.getOrInsertComputed(signal, () => new Set<number>()).add(handlerId);
|
|
147
133
|
};
|
|
148
134
|
|
|
149
135
|
const untrackConnection = (instance: object, handlerId: number): void => {
|
|
@@ -238,23 +224,11 @@ const buildSignalNames = (type: bigint): string[] => {
|
|
|
238
224
|
return [...names];
|
|
239
225
|
};
|
|
240
226
|
|
|
241
|
-
const signalNamesFor = (type: bigint): string[] =>
|
|
227
|
+
const signalNamesFor = (type: bigint): string[] => signalNameCache.getOrInsertComputed(type, buildSignalNames);
|
|
242
228
|
|
|
243
229
|
const getSignalId = (instance: object, signal: string): number =>
|
|
244
230
|
signalIdFor((instance as TypedClass).__type__, signal);
|
|
245
231
|
|
|
246
|
-
function connectBind(type: bigint, signal: string, callback: CallbackDescriptor): (...values: unknown[]) => unknown {
|
|
247
|
-
const key = `${String(type)}\0${getSignalBaseName(signal)}`;
|
|
248
|
-
|
|
249
|
-
return connectCache(
|
|
250
|
-
key,
|
|
251
|
-
LIB,
|
|
252
|
-
"g_signal_connect_data",
|
|
253
|
-
[objectT("borrowed"), stringT("borrowed"), callback, uint32T],
|
|
254
|
-
uint64T,
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
232
|
/**
|
|
259
233
|
* Connects a handler to a GObject signal on an instance and returns the handler id.
|
|
260
234
|
* @param instance Emitter to connect to.
|
|
@@ -265,8 +239,9 @@ function connectSignal(instance: object, signal: string, spec: SignalConnectSpec
|
|
|
265
239
|
const { callback, handler, isAfter } = spec;
|
|
266
240
|
const wrapped = wrapCallback(handler, callback, "signal");
|
|
267
241
|
const type: bigint = (instance as TypedClass).__type__;
|
|
268
|
-
const
|
|
269
|
-
const
|
|
242
|
+
const key = `${String(type)}\0${getSignalBaseName(signal)}`;
|
|
243
|
+
const closure = newCCallbackClosure(key, callback, wrapped);
|
|
244
|
+
const handlerId = gSignalConnectClosure(getHandle(instance), signal, closure, isAfter) as number;
|
|
270
245
|
trackConnection(instance, getSignalBaseName(signal), handlerId);
|
|
271
246
|
|
|
272
247
|
return handlerId;
|
package/src/t.ts
CHANGED
|
@@ -41,10 +41,7 @@ type T = {
|
|
|
41
41
|
unichar: typeof helpers.unicharT;
|
|
42
42
|
/** Descriptor for an opaque `gpointer` argument, taken from a typed array's memory or a numeric address. */
|
|
43
43
|
buffer: typeof helpers.bufferT;
|
|
44
|
-
/**
|
|
45
|
-
* Builds a descriptor for a C string, whose optional length sizes the caller-allocated buffer
|
|
46
|
-
* used when the string is passed by reference.
|
|
47
|
-
*/
|
|
44
|
+
/** Builds a C-string descriptor with optional caller-allocated length. */
|
|
48
45
|
string: typeof helpers.stringT;
|
|
49
46
|
/** Builds a descriptor for a `GObject`, wrapped in the class registered for its runtime GType. */
|
|
50
47
|
object: typeof helpers.objectT;
|
|
@@ -82,28 +79,15 @@ type T = {
|
|
|
82
79
|
cursorArray: typeof helpers.cursorArrayT;
|
|
83
80
|
/** Builds a descriptor for a function pointer, marshalling a JavaScript function into a native closure. */
|
|
84
81
|
callback: typeof helpers.callbackT;
|
|
85
|
-
/**
|
|
86
|
-
* Binds a native function, wiring up argument directions, `GError` checking, and packing output
|
|
87
|
-
* arguments into the result.
|
|
88
|
-
*/
|
|
82
|
+
/** Binds a native function with argument directions, errors, and packed outputs. */
|
|
89
83
|
fn: typeof fn;
|
|
90
|
-
/**
|
|
91
|
-
* Binds a struct field at a fixed offset, compiling its descriptor once into an accessor that
|
|
92
|
-
* reads and writes it.
|
|
93
|
-
*/
|
|
84
|
+
/** Binds a struct field at a fixed offset. */
|
|
94
85
|
field: typeof field;
|
|
95
|
-
/**
|
|
96
|
-
* Binds a struct field whose offset is supplied per access, for walking records stored at a
|
|
97
|
-
* stride in a buffer.
|
|
98
|
-
*/
|
|
86
|
+
/** Binds a struct field whose offset is supplied per access. */
|
|
99
87
|
fieldAt: typeof fieldAt;
|
|
100
88
|
};
|
|
101
89
|
|
|
102
|
-
/**
|
|
103
|
-
* Type descriptor builder: a collection of factory helpers that describe C types for
|
|
104
|
-
* FFI marshalling, plus `bind` to bind a native function and `fn` to describe a
|
|
105
|
-
* function signature.
|
|
106
|
-
*/
|
|
90
|
+
/** FFI descriptor factories and native function binders. */
|
|
107
91
|
const t: T = {
|
|
108
92
|
bind,
|
|
109
93
|
int8: helpers.int8T,
|
package/src/type.ts
CHANGED
|
@@ -29,6 +29,14 @@ const gTypeParent = bind(LIB, "g_type_parent", [biguint64T], biguint64T);
|
|
|
29
29
|
const gTypeFundamental = bind(LIB, "g_type_fundamental", [biguint64T], biguint64T);
|
|
30
30
|
const gTypeName = bind(LIB, "g_type_name", [biguint64T], stringT("borrowed"));
|
|
31
31
|
const gTypeInterfaces = bind(LIB, "g_type_interfaces", [biguint64T, refT(uint32T)], sizedArrayT(biguint64T, 1, "full"));
|
|
32
|
+
|
|
33
|
+
const gTypeInterfacePrerequisites = bind(
|
|
34
|
+
LIB,
|
|
35
|
+
"g_type_interface_prerequisites",
|
|
36
|
+
[biguint64T, refT(uint32T)],
|
|
37
|
+
sizedArrayT(biguint64T, 1, "full"),
|
|
38
|
+
);
|
|
39
|
+
|
|
32
40
|
/** GType tag for an invalid or uninitialized type. */
|
|
33
41
|
const TYPE_INVALID = 0n;
|
|
34
42
|
/** GType tag for the absence of a value (`void`). */
|
|
@@ -137,11 +145,26 @@ function typeInterfaces(type: bigint): bigint[] {
|
|
|
137
145
|
return gTypeInterfaces(type, nInterfacesRef) as bigint[];
|
|
138
146
|
}
|
|
139
147
|
|
|
148
|
+
function typeInterfacePrerequisites(type: bigint): bigint[] {
|
|
149
|
+
const nPrerequisitesRef = { value: 0 };
|
|
150
|
+
|
|
151
|
+
return gTypeInterfacePrerequisites(type, nPrerequisitesRef) as bigint[];
|
|
152
|
+
}
|
|
153
|
+
|
|
140
154
|
/** Returns the GType registered under the given name, or `TYPE_INVALID` if none exists. */
|
|
141
155
|
function typeFromName(name: string): bigint {
|
|
142
156
|
return gTypeFromName(name) as bigint;
|
|
143
157
|
}
|
|
144
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Keeps the given wrapper classes in a tree-shaken bundle: a generated bootstrap names the classes
|
|
161
|
+
* its namespace cannot operate without as arguments here, which is a reference a bundler retains.
|
|
162
|
+
*
|
|
163
|
+
* @param wrappers Wrapper classes to keep.
|
|
164
|
+
* @returns The same classes, untouched.
|
|
165
|
+
*/
|
|
166
|
+
const retainWrapperClasses = (wrappers: readonly unknown[]): readonly unknown[] => wrappers;
|
|
167
|
+
|
|
145
168
|
function typeFundamental(type: bigint): bigint {
|
|
146
169
|
return gTypeFundamental(type) as bigint;
|
|
147
170
|
}
|
|
@@ -221,6 +244,14 @@ function isResolvableDescriptor(descriptor: Descriptor): descriptor is Resolvabl
|
|
|
221
244
|
return RESOLVABLE_DESCRIPTOR_KINDS.has(descriptor.kind);
|
|
222
245
|
}
|
|
223
246
|
|
|
247
|
+
function resolveEnumOrFlagsType(descriptor: Extract<Descriptor, { kind: "enum" | "flags" }>): bigint {
|
|
248
|
+
if (descriptor.getTypeFnName === "") {
|
|
249
|
+
return descriptor.isSigned ? TYPE_INT : TYPE_UINT;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return resolveType(descriptor.sharedLibrary, descriptor.getTypeFnName);
|
|
253
|
+
}
|
|
254
|
+
|
|
224
255
|
function resolveDescriptorType(descriptor: Descriptor): bigint {
|
|
225
256
|
if (descriptor.kind === "biguint64" && "type" in descriptor) {
|
|
226
257
|
return TYPE_GTYPE;
|
|
@@ -239,7 +270,7 @@ function resolveDescriptorType(descriptor: Descriptor): bigint {
|
|
|
239
270
|
switch (descriptor.kind) {
|
|
240
271
|
case "enum":
|
|
241
272
|
case "flags": {
|
|
242
|
-
return
|
|
273
|
+
return resolveEnumOrFlagsType(descriptor);
|
|
243
274
|
}
|
|
244
275
|
case "boxed": {
|
|
245
276
|
return resolveBoxedType(descriptor);
|
|
@@ -283,8 +314,10 @@ export {
|
|
|
283
314
|
getStrvType,
|
|
284
315
|
isResolvableDescriptor,
|
|
285
316
|
isTypedClass,
|
|
317
|
+
retainWrapperClasses,
|
|
286
318
|
typeIsA,
|
|
287
319
|
typeParent,
|
|
320
|
+
typeInterfacePrerequisites,
|
|
288
321
|
typeInterfaces,
|
|
289
322
|
typeFromName,
|
|
290
323
|
typeFundamental,
|
package/src/value.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
fundamentalT,
|
|
16
16
|
int8T,
|
|
17
17
|
int32T,
|
|
18
|
+
type ObjectDescriptor,
|
|
18
19
|
objectT,
|
|
19
20
|
stringT,
|
|
20
21
|
uint8T,
|
|
@@ -128,6 +129,7 @@ const stringValueType = bindValueType("string", stringT("borrowed"));
|
|
|
128
129
|
const enumValueType = bindValueType("enum", int32T);
|
|
129
130
|
const flagsValueType = bindValueType("flags", uint32T);
|
|
130
131
|
const objectValueType = bindValueType("object", objectT("borrowed"));
|
|
132
|
+
const objectValueFundamentals: Set<bigint> = new Set([TYPE_OBJECT, TYPE_INTERFACE]);
|
|
131
133
|
const paramValueType = bindValueType("param", PARAM_T);
|
|
132
134
|
const variantValueType = bindValueType("variant", VARIANT_T);
|
|
133
135
|
const pointerValueType = bindValueType("pointer", uint64T);
|
|
@@ -420,6 +422,14 @@ const arrayValueType = (descriptor: ArrayDescriptor): ValueType => {
|
|
|
420
422
|
throw new Error(`Unsupported array type ${descriptor.arrayKind} of ${descriptor.itemDescriptor.kind}`);
|
|
421
423
|
};
|
|
422
424
|
|
|
425
|
+
const resolveEnumOrFlagsValueType = (descriptor: Extract<Descriptor, { kind: "enum" | "flags" }>): ValueType => {
|
|
426
|
+
if (descriptor.getTypeFnName === "") {
|
|
427
|
+
return descriptor.kind === "flags" ? flagsValueType : enumValueType;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return enumOrFlagsValueType(resolveType(descriptor.sharedLibrary, descriptor.getTypeFnName));
|
|
431
|
+
};
|
|
432
|
+
|
|
423
433
|
const resolveValueType = (descriptor: Descriptor): ValueType => {
|
|
424
434
|
if (descriptor.kind === "biguint64" && "type" in descriptor) {
|
|
425
435
|
return typeValueType;
|
|
@@ -438,7 +448,7 @@ const resolveValueType = (descriptor: Descriptor): ValueType => {
|
|
|
438
448
|
switch (descriptor.kind) {
|
|
439
449
|
case "enum":
|
|
440
450
|
case "flags": {
|
|
441
|
-
return
|
|
451
|
+
return resolveEnumOrFlagsValueType(descriptor);
|
|
442
452
|
}
|
|
443
453
|
case "boxed": {
|
|
444
454
|
return boxedValueType(resolveBoxedType(descriptor));
|
|
@@ -718,10 +728,32 @@ function fromValue(value: ExternalObject<Handle>): unknown {
|
|
|
718
728
|
return get(value);
|
|
719
729
|
}
|
|
720
730
|
|
|
721
|
-
const
|
|
722
|
-
descriptor
|
|
723
|
-
|
|
724
|
-
|
|
731
|
+
const objectValueWithFallback = (
|
|
732
|
+
descriptor: ObjectDescriptor,
|
|
733
|
+
value: ExternalObject<Handle>,
|
|
734
|
+
): { wrapped: unknown } | null => {
|
|
735
|
+
if (descriptor.fallbackClass === undefined || !objectValueFundamentals.has(typeFundamental(getValueType(value)))) {
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return { wrapped: wrapObject(objectValueType.get(value), descriptor.fallbackClass) };
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
const fromValueForDescriptor = (descriptor: Descriptor, value: ExternalObject<Handle>): unknown => {
|
|
743
|
+
if (descriptor.kind === "array" && descriptor.arrayKind === "gbytearray") {
|
|
744
|
+
return byteArrayValueGetterFor(descriptor.isBytes === true)(value);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
if (descriptor.kind === "object") {
|
|
748
|
+
const withFallback = objectValueWithFallback(descriptor, value);
|
|
749
|
+
|
|
750
|
+
if (withFallback !== null) {
|
|
751
|
+
return withFallback.wrapped;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
return fromValue(value);
|
|
756
|
+
};
|
|
725
757
|
|
|
726
758
|
const inferredValueGuard: ValueGuard = (jsValue) => inferValueGType(jsValue, wrapperGType(jsValue)) !== TYPE_INVALID;
|
|
727
759
|
|
package/src/variant.ts
CHANGED
|
@@ -34,10 +34,7 @@ type BasicValueMap<Nested> = {
|
|
|
34
34
|
|
|
35
35
|
/** Single-character code of one of the GVariant basic types in {@link BasicValueMap}. */
|
|
36
36
|
type BasicCode = keyof BasicValueMap<unknown>;
|
|
37
|
-
/**
|
|
38
|
-
* JavaScript type a byte array (`ay`) unpacks to: the same one the generated bindings use for byte sequences, so a
|
|
39
|
-
* `Uint8Array` under the `v2ByteArrays` future flag and a `number[]` otherwise.
|
|
40
|
-
*/
|
|
37
|
+
/** JavaScript type a byte array (`ay`) unpacks to. */
|
|
41
38
|
type ByteArray = ReturnType<GLib.Bytes["unrefToArray"]>;
|
|
42
39
|
/** Values a byte array (`ay`) packs from. */
|
|
43
40
|
type ByteArrayInput = Uint8Array | number[];
|
|
@@ -503,8 +500,7 @@ const toVariant = <S extends string>(typeString: S, value: VariantInput<S>): GLi
|
|
|
503
500
|
/**
|
|
504
501
|
* Unpacks a `GLib.Variant` into the JavaScript value its GVariant type describes, the inverse of
|
|
505
502
|
* {@link toVariant}. A dictionary keyed by strings unpacks to a record and one keyed by anything
|
|
506
|
-
* else to a `Map`, an array to an array, a byte array (`ay`) to
|
|
507
|
-
* bindings use (`Uint8Array` under the `v2ByteArrays` future flag, `number[]` otherwise), a tuple
|
|
503
|
+
* else to a `Map`, an array to an array, a byte array (`ay`) to a `Uint8Array`, a tuple
|
|
508
504
|
* to an array of its members, a maybe to its value or `null`, and a nested variant to the
|
|
509
505
|
* `GLib.Variant` itself unless `recursive` is set, in which case it is unwrapped all the way down.
|
|
510
506
|
*
|
package/src/vfunc-call.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { BindVfuncOptions } from "@gtkx/native";
|
|
2
1
|
import type { AnyClass } from "@gtkx/utils";
|
|
3
|
-
import { bindVfunc } from "@gtkx/native";
|
|
2
|
+
import { bindVfunc, type BindVfuncOptions } from "@gtkx/native";
|
|
4
3
|
import { type Arg, isCallerAllocatedArg, requiresInputArg } from "./arg.js";
|
|
5
4
|
import { buildNativeArgTypes, fromNativeCallable } from "./fn.js";
|
|
6
5
|
import { toNative } from "./native-value.js";
|
|
@@ -106,21 +105,9 @@ function buildInvoker(slot: ResolvedSlot, instanceType: bigint | undefined, call
|
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
function cachedInvoker(cache: InvokerCache, owner: AnyClass, key: string, build: () => Invoker): Invoker {
|
|
109
|
-
|
|
108
|
+
const byKey = cache.getOrInsertComputed(owner, () => new Map<string, Invoker>());
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
byKey = new Map();
|
|
113
|
-
cache.set(owner, byKey);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
let invoker = byKey.get(key);
|
|
117
|
-
|
|
118
|
-
if (invoker === undefined) {
|
|
119
|
-
invoker = build();
|
|
120
|
-
byKey.set(key, invoker);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return invoker;
|
|
110
|
+
return byKey.getOrInsertComputed(key, build);
|
|
124
111
|
}
|
|
125
112
|
|
|
126
113
|
function resolveParentSlot(klass: AnyClass, parentType: bigint, methodName: string): ResolvedSlot | undefined {
|