@gtkx/runtime 1.5.0 → 1.6.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/dist/descriptors.d.ts +36 -7
- package/dist/descriptors.d.ts.map +1 -1
- package/dist/descriptors.js +18 -5
- 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 +20 -4
- package/dist/fn.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +4 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +4 -1
- package/dist/internal.js.map +1 -1
- package/dist/native-value.d.ts.map +1 -1
- package/dist/native-value.js +21 -2
- package/dist/native-value.js.map +1 -1
- package/dist/register-class.d.ts +2 -2
- 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/type.d.ts +10 -1
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js +14 -1
- package/dist/type.js.map +1 -1
- package/dist/value.d.ts.map +1 -1
- package/dist/value.js +19 -3
- package/dist/value.js.map +1 -1
- package/package.json +10 -5
- package/src/descriptors.ts +55 -9
- package/src/element-metadata.ts +24 -0
- package/src/fn.ts +33 -5
- package/src/index.ts +3 -0
- package/src/internal.ts +8 -1
- package/src/native-value.ts +30 -2
- package/src/register-class.ts +61 -2
- package/src/registry.ts +110 -19
- package/src/type.ts +25 -0
- package/src/value.ts +28 -4
package/src/register-class.ts
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
TYPE_NONE,
|
|
46
46
|
type TypedClass,
|
|
47
47
|
typeFundamental,
|
|
48
|
+
typeInterfacePrerequisites,
|
|
48
49
|
typeInterfaces,
|
|
49
50
|
typeIsA,
|
|
50
51
|
typeName,
|
|
@@ -195,7 +196,7 @@ type SignalSpec = {
|
|
|
195
196
|
/** GType of the value an emission returns, defaulting to none. */
|
|
196
197
|
returnType?: SignalGType;
|
|
197
198
|
/**
|
|
198
|
-
* How the emission combines what its handlers return, limited to the
|
|
199
|
+
* How the emission combines what its handlers return, limited to the accumulators GObject
|
|
199
200
|
* ships: `"first-wins"` stops the emission at the first handler and keeps its result, and
|
|
200
201
|
* `"true-handled"` runs handlers until one returns `true`, which requires a boolean
|
|
201
202
|
* `returnType`. Without one, every handler runs and the last result stands.
|
|
@@ -316,7 +317,7 @@ type RegisterClassOptions<
|
|
|
316
317
|
* in lowercase letters, digits, `-` and `_`, and be new to the type: one an ancestor type or a
|
|
317
318
|
* listed interface already carries throws, and so does one carrying an uppercase letter, which
|
|
318
319
|
* GObject would carry under that exact spelling, out of reach of both its dashed spelling and
|
|
319
|
-
* its `on<SignalName>` default handler.
|
|
320
|
+
* its `on<SignalName>` default handler. Either word separator spells the same signal, so a
|
|
320
321
|
* signal declared as `data_changed` is connected to and emitted as `data-changed` too.
|
|
321
322
|
*
|
|
322
323
|
* Instances connect and emit by name through the same `connect`, `on`, `once`, `off` and
|
|
@@ -381,6 +382,7 @@ const PROPERTY_VFUNC_SPECS: PropertyVfuncSpec[] = [
|
|
|
381
382
|
];
|
|
382
383
|
|
|
383
384
|
const PROPERTY_VFUNC_NAMES: Set<string> = new Set(PROPERTY_VFUNC_SPECS.map((spec) => spec.methodName));
|
|
385
|
+
const VFUNC_METHOD_PATTERN = /^vfunc[A-Z0-9]/;
|
|
384
386
|
const TYPE_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9\-_+]{2,}$/;
|
|
385
387
|
const UPPER_CASE_PATTERN = /[A-Z]/;
|
|
386
388
|
const SIGNAL_OVERRIDE_PATTERN = /^on[A-Z]/;
|
|
@@ -456,6 +458,7 @@ function registerClass(klass: AnyClass, options: AnyRegisterClassOptions = {}):
|
|
|
456
458
|
|
|
457
459
|
const name = resolveTypeName(klass, options);
|
|
458
460
|
const declaredTypes = resolveInterfaceTypes(klass, options.implements ?? []);
|
|
461
|
+
assertInterfacePrerequisites(klass, parentType, declaredTypes);
|
|
459
462
|
const adoptedTypes = declaredTypes.filter((gtype) => !typeIsA(parentType, gtype));
|
|
460
463
|
const properties = options.properties ?? {};
|
|
461
464
|
const signals = resolveDeclaredSignals(klass, options.signals ?? {});
|
|
@@ -471,6 +474,7 @@ function registerClass(klass: AnyClass, options: AnyRegisterClassOptions = {}):
|
|
|
471
474
|
|
|
472
475
|
const claimedMethodNames = new Set(classVfuncs.map((vfunc) => vfunc.methodName));
|
|
473
476
|
const interfaceBindings = discoverInterfaceBindings(methods, parentType, declaredTypes, claimedMethodNames);
|
|
477
|
+
assertClaimedVfuncs(klass, methods, claimedMethodNames, interfaceBindings);
|
|
474
478
|
|
|
475
479
|
const nativeOptions = withNativeSignals(
|
|
476
480
|
toNativeOptions(classVfuncs, interfaceBindings, properties, options),
|
|
@@ -677,6 +681,61 @@ function wrapVfunc(
|
|
|
677
681
|
);
|
|
678
682
|
}
|
|
679
683
|
|
|
684
|
+
const claimedVfuncNames = (
|
|
685
|
+
claimedMethodNames: Set<string>,
|
|
686
|
+
interfaceBindings: InterfaceVfuncBinding[],
|
|
687
|
+
): Set<string> => {
|
|
688
|
+
const claimed = new Set(claimedMethodNames);
|
|
689
|
+
|
|
690
|
+
for (const binding of interfaceBindings) {
|
|
691
|
+
for (const vfunc of binding.vfuncs) {
|
|
692
|
+
claimed.add(vfunc.methodName);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return claimed;
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
const isPrerequisiteMet = (parentType: bigint, declaredTypes: bigint[], prerequisite: bigint): boolean =>
|
|
700
|
+
typeIsA(parentType, prerequisite) || declaredTypes.includes(prerequisite);
|
|
701
|
+
|
|
702
|
+
function assertPrerequisitesFor(klass: AnyClass, parentType: bigint, declaredTypes: bigint[], iface: bigint): void {
|
|
703
|
+
for (const prerequisite of typeInterfacePrerequisites(iface)) {
|
|
704
|
+
if (!isPrerequisiteMet(parentType, declaredTypes, prerequisite)) {
|
|
705
|
+
throw new TypeError(
|
|
706
|
+
`registerClass: ${klass.name} does not meet prerequisite ` +
|
|
707
|
+
`'${typeName(prerequisite) ?? String(prerequisite)}' of interface ` +
|
|
708
|
+
`'${typeName(iface) ?? String(iface)}'`,
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function assertInterfacePrerequisites(klass: AnyClass, parentType: bigint, declaredTypes: bigint[]): void {
|
|
715
|
+
for (const iface of declaredTypes) {
|
|
716
|
+
assertPrerequisitesFor(klass, parentType, declaredTypes, iface);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function assertClaimedVfuncs(
|
|
721
|
+
klass: AnyClass,
|
|
722
|
+
methods: MethodTable,
|
|
723
|
+
claimedMethodNames: Set<string>,
|
|
724
|
+
interfaceBindings: InterfaceVfuncBinding[],
|
|
725
|
+
): void {
|
|
726
|
+
const claimed = claimedVfuncNames(claimedMethodNames, interfaceBindings);
|
|
727
|
+
|
|
728
|
+
for (const methodName of methods.keys()) {
|
|
729
|
+
if (VFUNC_METHOD_PATTERN.test(methodName) && !claimed.has(methodName)) {
|
|
730
|
+
throw new Error(
|
|
731
|
+
`registerClass: ${klass.name}.${methodName} matches no vtable slot on any ancestor ` +
|
|
732
|
+
"or implemented interface, so the override would never be called; check the name against " +
|
|
733
|
+
"the parent class's virtual methods",
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
680
739
|
function discoverInterfaceBindings(
|
|
681
740
|
methods: MethodTable,
|
|
682
741
|
parentGtype: bigint,
|
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/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
|
}
|
|
@@ -283,8 +306,10 @@ export {
|
|
|
283
306
|
getStrvType,
|
|
284
307
|
isResolvableDescriptor,
|
|
285
308
|
isTypedClass,
|
|
309
|
+
retainWrapperClasses,
|
|
286
310
|
typeIsA,
|
|
287
311
|
typeParent,
|
|
312
|
+
typeInterfacePrerequisites,
|
|
288
313
|
typeInterfaces,
|
|
289
314
|
typeFromName,
|
|
290
315
|
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);
|
|
@@ -718,10 +720,32 @@ function fromValue(value: ExternalObject<Handle>): unknown {
|
|
|
718
720
|
return get(value);
|
|
719
721
|
}
|
|
720
722
|
|
|
721
|
-
const
|
|
722
|
-
descriptor
|
|
723
|
-
|
|
724
|
-
|
|
723
|
+
const objectValueWithFallback = (
|
|
724
|
+
descriptor: ObjectDescriptor,
|
|
725
|
+
value: ExternalObject<Handle>,
|
|
726
|
+
): { wrapped: unknown } | null => {
|
|
727
|
+
if (descriptor.fallbackClass === undefined || !objectValueFundamentals.has(typeFundamental(getValueType(value)))) {
|
|
728
|
+
return null;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
return { wrapped: wrapObject(objectValueType.get(value), descriptor.fallbackClass) };
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
const fromValueForDescriptor = (descriptor: Descriptor, value: ExternalObject<Handle>): unknown => {
|
|
735
|
+
if (descriptor.kind === "array" && descriptor.arrayKind === "gbytearray") {
|
|
736
|
+
return byteArrayValueGetterFor(descriptor.isBytes === true)(value);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
if (descriptor.kind === "object") {
|
|
740
|
+
const withFallback = objectValueWithFallback(descriptor, value);
|
|
741
|
+
|
|
742
|
+
if (withFallback !== null) {
|
|
743
|
+
return withFallback.wrapped;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return fromValue(value);
|
|
748
|
+
};
|
|
725
749
|
|
|
726
750
|
const inferredValueGuard: ValueGuard = (jsValue) => inferValueGType(jsValue, wrapperGType(jsValue)) !== TYPE_INVALID;
|
|
727
751
|
|