@gtkx/runtime 1.0.0 → 1.1.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.
Files changed (109) hide show
  1. package/README.md +1 -1
  2. package/dist/application-class.d.ts +5 -0
  3. package/dist/application-class.d.ts.map +1 -1
  4. package/dist/application-class.js +11 -1
  5. package/dist/application-class.js.map +1 -1
  6. package/dist/callback.d.ts +2 -2
  7. package/dist/callback.d.ts.map +1 -1
  8. package/dist/callback.js +51 -54
  9. package/dist/callback.js.map +1 -1
  10. package/dist/default-application.d.ts +4 -0
  11. package/dist/default-application.d.ts.map +1 -0
  12. package/dist/default-application.js +17 -0
  13. package/dist/default-application.js.map +1 -0
  14. package/dist/descriptors.d.ts +25 -2
  15. package/dist/descriptors.d.ts.map +1 -1
  16. package/dist/descriptors.js +31 -9
  17. package/dist/descriptors.js.map +1 -1
  18. package/dist/exit-hook.js +13 -0
  19. package/dist/exit-hook.js.map +1 -1
  20. package/dist/fn.d.ts +5 -0
  21. package/dist/fn.d.ts.map +1 -1
  22. package/dist/fn.js +11 -13
  23. package/dist/fn.js.map +1 -1
  24. package/dist/folded-lengths.d.ts +16 -0
  25. package/dist/folded-lengths.d.ts.map +1 -0
  26. package/dist/folded-lengths.js +38 -0
  27. package/dist/folded-lengths.js.map +1 -0
  28. package/dist/internal.d.ts +1 -0
  29. package/dist/internal.d.ts.map +1 -1
  30. package/dist/internal.js +1 -0
  31. package/dist/internal.js.map +1 -1
  32. package/dist/library.d.ts +2 -1
  33. package/dist/library.d.ts.map +1 -1
  34. package/dist/library.js +2 -1
  35. package/dist/library.js.map +1 -1
  36. package/dist/lifecycle.d.ts +16 -1
  37. package/dist/lifecycle.d.ts.map +1 -1
  38. package/dist/lifecycle.js +44 -14
  39. package/dist/lifecycle.js.map +1 -1
  40. package/dist/listeners.d.ts.map +1 -1
  41. package/dist/listeners.js +16 -4
  42. package/dist/listeners.js.map +1 -1
  43. package/dist/native-value.js +2 -2
  44. package/dist/native-value.js.map +1 -1
  45. package/dist/object.d.ts +7 -2
  46. package/dist/object.d.ts.map +1 -1
  47. package/dist/object.js +7 -2
  48. package/dist/object.js.map +1 -1
  49. package/dist/param-spec.d.ts.map +1 -1
  50. package/dist/param-spec.js +18 -20
  51. package/dist/param-spec.js.map +1 -1
  52. package/dist/properties.d.ts +2 -1
  53. package/dist/properties.d.ts.map +1 -1
  54. package/dist/properties.js +13 -9
  55. package/dist/properties.js.map +1 -1
  56. package/dist/register-class.d.ts +30 -0
  57. package/dist/register-class.d.ts.map +1 -1
  58. package/dist/register-class.js +21 -7
  59. package/dist/register-class.js.map +1 -1
  60. package/dist/registry.d.ts +12 -3
  61. package/dist/registry.d.ts.map +1 -1
  62. package/dist/registry.js +24 -15
  63. package/dist/registry.js.map +1 -1
  64. package/dist/signal.d.ts +2 -2
  65. package/dist/signal.d.ts.map +1 -1
  66. package/dist/signal.js +22 -18
  67. package/dist/signal.js.map +1 -1
  68. package/dist/t.d.ts +2 -0
  69. package/dist/t.d.ts.map +1 -1
  70. package/dist/t.js +1 -0
  71. package/dist/t.js.map +1 -1
  72. package/dist/tuple.d.ts +6 -3
  73. package/dist/tuple.d.ts.map +1 -1
  74. package/dist/tuple.js +9 -7
  75. package/dist/tuple.js.map +1 -1
  76. package/dist/value.d.ts +3 -1
  77. package/dist/value.d.ts.map +1 -1
  78. package/dist/value.js +64 -18
  79. package/dist/value.js.map +1 -1
  80. package/dist/vfunc-call.d.ts.map +1 -1
  81. package/dist/vfunc-call.js +5 -1
  82. package/dist/vfunc-call.js.map +1 -1
  83. package/dist/vfunc.d.ts.map +1 -1
  84. package/dist/vfunc.js +9 -3
  85. package/dist/vfunc.js.map +1 -1
  86. package/package.json +14 -4
  87. package/src/application-class.ts +12 -2
  88. package/src/callback.ts +70 -66
  89. package/src/default-application.ts +21 -0
  90. package/src/descriptors.ts +69 -14
  91. package/src/exit-hook.ts +18 -0
  92. package/src/fn.ts +23 -13
  93. package/src/folded-lengths.ts +64 -0
  94. package/src/internal.ts +1 -0
  95. package/src/library.ts +2 -1
  96. package/src/lifecycle.ts +60 -14
  97. package/src/listeners.ts +22 -5
  98. package/src/native-value.ts +2 -2
  99. package/src/object.ts +7 -2
  100. package/src/param-spec.ts +21 -22
  101. package/src/properties.ts +23 -9
  102. package/src/register-class.ts +63 -8
  103. package/src/registry.ts +40 -18
  104. package/src/signal.ts +32 -28
  105. package/src/t.ts +3 -0
  106. package/src/tuple.ts +18 -12
  107. package/src/value.ts +94 -19
  108. package/src/vfunc-call.ts +5 -1
  109. package/src/vfunc.ts +10 -3
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: bind(LIB, "g_value_set_boxed", [VALUE_T, arrayT(stringT("borrowed"))], voidT),
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
- throw new Error(`Unsupported fundamental type '${typeName(type) ?? String(type)}' for value`);
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 resolveValueGetter = (fundamental: bigint): ValueGetter | undefined =>
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 resolveValueSetter = (fundamental: bigint): ValueType["set"] | undefined =>
421
+ const builtInValueSetter = (fundamental: bigint): ValueType["set"] | undefined =>
357
422
  PLAIN_VALUE_SETTERS.get(fundamental) ?? WRAPPED_VALUE_SETTERS.get(fundamental);
358
423
 
359
- function setStrvValue(value: ExternalObject<Handle>, jsValue: unknown): void {
360
- strvValueType.set(value, jsValue ?? null);
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
- if (type === getStrvType()) {
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
- { args, returns: descriptor.returnDescriptor, canThrow },
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 { type: descriptor.innerDescriptor, direction: descriptor.inout === true ? "inout" : "out" };
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
- return descriptor.argDescriptors.map((argDescriptor) => vfuncArg(argDescriptor));
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 };