@gtkx/runtime 1.3.0 → 1.4.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/src/signal.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Descriptor, ExternalObject, Handle } from "@gtkx/native";
2
- import type { TypedClass } from "./type.js";
2
+ import { getOrInsert, toCamelIdentifier, upperFirst } from "@gtkx/utils";
3
3
  import { type Arg, isCallerAllocatedArg, isInoutArg, isOutputArg } from "./arg.js";
4
4
  import { bind, createBindCache } from "./bind.js";
5
5
  import { wrapCallback } from "./callback.js";
@@ -11,6 +11,8 @@ import {
11
11
  boxedT,
12
12
  type CallbackDescriptor,
13
13
  objectT,
14
+ refT,
15
+ sizedArrayT,
14
16
  stringT,
15
17
  uint32T,
16
18
  uint64T,
@@ -19,6 +21,7 @@ import {
19
21
  import { LIB, VALUE_SIZE, VALUE_T } from "./library.js";
20
22
  import { getHandle } from "./registry.js";
21
23
  import { packTupleResult } from "./tuple.js";
24
+ import { TYPE_INVALID, type TypedClass, typeInterfaces, typeParent } from "./type.js";
22
25
  import {
23
26
  fromValue,
24
27
  getBoxedValue,
@@ -70,6 +73,9 @@ const connectCache = createBindCache();
70
73
  const connectionTable: WeakMap<object, Map<string, Set<number>>> = new WeakMap();
71
74
  const gQuarkFromString = bind(LIB, "g_quark_from_string", [stringT("borrowed")], uint32T);
72
75
  const gSignalLookup = bind(LIB, "g_signal_lookup", [stringT("borrowed"), biguint64T], uint32T);
76
+ const gSignalName = bind(LIB, "g_signal_name", [uint32T], stringT("borrowed"));
77
+ const signalNameCache: Map<bigint, string[]> = new Map();
78
+ const gSignalListIds = bind(LIB, "g_signal_list_ids", [biguint64T, refT(uint32T)], sizedArrayT(uint32T, 1, "full"));
73
79
 
74
80
  const gSignalEmitv = bind(
75
81
  LIB,
@@ -197,12 +203,46 @@ function hasSignalListener(instance: object, signals?: string[]): boolean {
197
203
  });
198
204
  }
199
205
 
200
- const getSignalId = (instance: object, signal: string): number => {
201
- const type: bigint = (instance as TypedClass).__type__;
206
+ const signalIdFor = (type: bigint, signal: string): number =>
207
+ gSignalLookup(getSignalBaseName(signal), type) as number;
208
+
209
+ const ownSignalNames = (type: bigint): string[] => {
210
+ const countRef = { value: 0 };
211
+
212
+ return (gSignalListIds(type, countRef) as number[]).map((id) => gSignalName(id) as string);
213
+ };
214
+
215
+ const addSignalNames = (names: Set<string>, type: bigint): void => {
216
+ for (const name of ownSignalNames(type)) {
217
+ names.add(name);
218
+ }
219
+ };
220
+
221
+ const handlerNameFor = (signal: string): string => `on${upperFirst(toCamelIdentifier(signal))}`;
222
+
223
+ /** The signal a generated `on…` handler prop names on the given type, or `undefined` when it carries none. */
224
+ const signalForHandlerName = (type: bigint, handlerName: string): string | undefined =>
225
+ signalNamesFor(type).find((signal) => handlerNameFor(signal) === handlerName);
226
+
227
+ const buildSignalNames = (type: bigint): string[] => {
228
+ const names: Set<string> = new Set();
202
229
 
203
- return gSignalLookup(getSignalBaseName(signal), type) as number;
230
+ for (let current = type; current !== TYPE_INVALID; current = typeParent(current)) {
231
+ addSignalNames(names, current);
232
+
233
+ for (const iface of typeInterfaces(current)) {
234
+ addSignalNames(names, iface);
235
+ }
236
+ }
237
+
238
+ return [...names];
204
239
  };
205
240
 
241
+ const signalNamesFor = (type: bigint): string[] => getOrInsert(signalNameCache, type, buildSignalNames);
242
+
243
+ const getSignalId = (instance: object, signal: string): number =>
244
+ signalIdFor((instance as TypedClass).__type__, signal);
245
+
206
246
  function connectBind(type: bigint, signal: string, callback: CallbackDescriptor): (...values: unknown[]) => unknown {
207
247
  const key = `${String(type)}\0${getSignalBaseName(signal)}`;
208
248
 
@@ -232,13 +272,7 @@ function connectSignal(instance: object, signal: string, spec: SignalConnectSpec
232
272
  return handlerId;
233
273
  }
234
274
 
235
- function overrideSignalClassClosure(type: bigint, signal: string, handler: SignalHandler): void {
236
- const signalId = gSignalLookup(signal, type) as number;
237
-
238
- if (signalId === 0) {
239
- return;
240
- }
241
-
275
+ function overrideSignalClassClosure(type: bigint, signalId: number, handler: SignalHandler): void {
242
276
  gSignalOverrideClassClosure(signalId, type, toClosure(handler));
243
277
  }
244
278
 
@@ -342,7 +376,9 @@ function emitSignal(instance: object, signal: string, args: EmitArg[], returns?:
342
376
  }
343
377
 
344
378
  export {
379
+ signalForHandlerName,
345
380
  getSignalBaseName,
381
+ signalIdFor,
346
382
  connectClosureSignal,
347
383
  connectSignal,
348
384
  type DeclaredSignalTypes,
package/src/t.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { bind } from "./bind.js";
2
2
  import * as helpers from "./descriptors.js";
3
+ import { field, fieldAt } from "./field.js";
3
4
  import { fn } from "./fn.js";
4
5
 
5
6
  /** The descriptor factories and function binders exposed as {@link t}. */
@@ -86,6 +87,16 @@ type T = {
86
87
  * arguments into the result.
87
88
  */
88
89
  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
+ */
94
+ 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
+ */
99
+ fieldAt: typeof fieldAt;
89
100
  };
90
101
 
91
102
  /**
@@ -132,6 +143,8 @@ const t: T = {
132
143
  cursorArray: helpers.cursorArrayT,
133
144
  callback: helpers.callbackT,
134
145
  fn,
146
+ field,
147
+ fieldAt,
135
148
  };
136
149
 
137
150
  export { t };