@gtkx/runtime 1.0.0-rc.1 → 1.0.0-rc.2
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/arg.d.ts +6 -5
- package/dist/arg.d.ts.map +1 -1
- package/dist/arg.js +5 -4
- package/dist/arg.js.map +1 -1
- package/dist/bind.d.ts +3 -2
- package/dist/bind.d.ts.map +1 -1
- package/dist/bind.js +5 -3
- package/dist/bind.js.map +1 -1
- package/dist/callback.d.ts +3 -3
- package/dist/callback.d.ts.map +1 -1
- package/dist/callback.js +51 -33
- package/dist/callback.js.map +1 -1
- package/dist/descriptors.d.ts +67 -64
- package/dist/descriptors.d.ts.map +1 -1
- package/dist/descriptors.js +92 -60
- package/dist/descriptors.js.map +1 -1
- package/dist/error.d.ts +5 -6
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +10 -6
- package/dist/error.js.map +1 -1
- package/dist/exit-hook.d.ts +2 -0
- package/dist/exit-hook.d.ts.map +1 -0
- package/dist/exit-hook.js +3 -0
- package/dist/exit-hook.js.map +1 -0
- package/dist/fn.d.ts +2 -2
- package/dist/fn.d.ts.map +1 -1
- package/dist/fn.js +26 -15
- package/dist/fn.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/library.d.ts +6 -5
- package/dist/library.d.ts.map +1 -1
- package/dist/library.js +6 -5
- package/dist/library.js.map +1 -1
- package/dist/lifecycle.d.ts +10 -9
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +38 -23
- package/dist/lifecycle.js.map +1 -1
- package/dist/listeners.d.ts +8 -8
- package/dist/listeners.d.ts.map +1 -1
- package/dist/listeners.js +28 -15
- package/dist/listeners.js.map +1 -1
- package/dist/mixin.d.ts +5 -11
- package/dist/mixin.d.ts.map +1 -1
- package/dist/mixin.js +24 -14
- package/dist/mixin.js.map +1 -1
- package/dist/native-value.d.ts +3 -2
- package/dist/native-value.d.ts.map +1 -1
- package/dist/native-value.js +75 -42
- package/dist/native-value.js.map +1 -1
- package/dist/object.d.ts +4 -3
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +8 -5
- package/dist/object.js.map +1 -1
- package/dist/promisify.d.ts +9 -1
- package/dist/promisify.d.ts.map +1 -1
- package/dist/promisify.js +18 -15
- package/dist/promisify.js.map +1 -1
- package/dist/properties.d.ts +14 -0
- package/dist/properties.d.ts.map +1 -0
- package/dist/properties.js +79 -0
- package/dist/properties.js.map +1 -0
- package/dist/register-class.d.ts +10 -2
- package/dist/register-class.d.ts.map +1 -1
- package/dist/register-class.js +83 -29
- package/dist/register-class.js.map +1 -1
- package/dist/registry.d.ts +23 -21
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +54 -35
- package/dist/registry.js.map +1 -1
- package/dist/signal.d.ts +7 -6
- package/dist/signal.d.ts.map +1 -1
- package/dist/signal.js +19 -12
- package/dist/signal.js.map +1 -1
- package/dist/t.d.ts +2 -2
- package/dist/t.d.ts.map +1 -1
- package/dist/t.js +2 -1
- package/dist/t.js.map +1 -1
- package/dist/tuple.d.ts +3 -2
- package/dist/tuple.d.ts.map +1 -1
- package/dist/tuple.js +7 -4
- package/dist/tuple.js.map +1 -1
- package/dist/type.d.ts +48 -41
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js +107 -87
- package/dist/type.js.map +1 -1
- package/dist/value.d.ts +19 -10
- package/dist/value.d.ts.map +1 -1
- package/dist/value.js +164 -99
- package/dist/value.js.map +1 -1
- package/package.json +4 -6
- package/src/arg.ts +7 -5
- package/src/bind.ts +13 -4
- package/src/callback.ts +97 -35
- package/src/descriptors.ts +227 -85
- package/src/error.ts +18 -9
- package/src/exit-hook.ts +3 -0
- package/src/fn.ts +53 -22
- package/src/index.ts +4 -2
- package/src/library.ts +7 -5
- package/src/lifecycle.ts +54 -26
- package/src/listeners.ts +46 -18
- package/src/mixin.ts +39 -14
- package/src/native-value.ts +103 -46
- package/src/object.ts +19 -7
- package/src/promisify.ts +42 -15
- package/src/properties.ts +115 -0
- package/src/register-class.ts +157 -30
- package/src/registry.ts +144 -54
- package/src/signal.ts +53 -13
- package/src/t.ts +3 -1
- package/src/tuple.ts +16 -4
- package/src/type.ts +183 -93
- package/src/value.ts +231 -108
package/src/registry.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AnyClass } from "@gtkx/utils";
|
|
1
2
|
import {
|
|
2
3
|
type ExternalObject,
|
|
3
4
|
getType,
|
|
@@ -6,7 +7,6 @@ import {
|
|
|
6
7
|
type RegisterClassVfunc as NativeRegisterClassVfunc,
|
|
7
8
|
setWrapper,
|
|
8
9
|
} from "@gtkx/native";
|
|
9
|
-
import type { AnyClass } from "@gtkx/utils";
|
|
10
10
|
import type { Mixin, MixinReceiver } from "./mixin.js";
|
|
11
11
|
import { TYPE_INVALID, type TypedClass, typeInterfaces, typeIsA, typeName, typeParent } from "./type.js";
|
|
12
12
|
|
|
@@ -14,46 +14,50 @@ import { TYPE_INVALID, type TypedClass, typeInterfaces, typeIsA, typeName, typeP
|
|
|
14
14
|
* Static side of class `C` with its construct signature preserved but the member
|
|
15
15
|
* named `K` (default `"new"`) removed.
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
type StaticBase<C, K extends PropertyKey = "new"> = Omit<C, K> &
|
|
18
18
|
(C extends new (...args: infer A) => infer R ? new (...args: A) => R : never);
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
type VfuncDescriptor<K extends "class" | "interface"> = {
|
|
21
21
|
kind: K;
|
|
22
22
|
className: string;
|
|
23
23
|
vfuncName: string;
|
|
24
24
|
byteOffset: number;
|
|
25
|
+
vtableSize: number;
|
|
25
26
|
argDescriptors: NativeRegisterClassVfunc["argDescriptors"];
|
|
26
27
|
returnDescriptor: NativeRegisterClassVfunc["returnDescriptor"];
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
type VfuncRegistry = Record<string, VfuncDescriptor<"class"> | VfuncDescriptor<"interface">>;
|
|
30
31
|
|
|
31
|
-
const classRegistry
|
|
32
|
-
const interfaceMixinRegistry
|
|
33
|
-
const composedClassRegistry
|
|
34
|
-
const handleMap
|
|
35
|
-
const vfuncRegistry
|
|
36
|
-
const interfaceVfuncRegistry
|
|
32
|
+
const classRegistry: Map<bigint, AnyClass> = new Map();
|
|
33
|
+
const interfaceMixinRegistry: Map<bigint, Mixin> = new Map();
|
|
34
|
+
const composedClassRegistry: Map<bigint, AnyClass> = new Map();
|
|
35
|
+
const handleMap: WeakMap<object, ExternalObject<Handle>> = new WeakMap();
|
|
36
|
+
const vfuncRegistry: WeakMap<object, VfuncRegistry> = new WeakMap();
|
|
37
|
+
const interfaceVfuncRegistry: Map<bigint, VfuncRegistry> = new Map();
|
|
37
38
|
|
|
38
39
|
function setClassType(cls: AnyClass, type: bigint): void {
|
|
39
40
|
(cls.prototype as { [K in keyof TypedClass]: TypedClass[K] }).__type__ = type;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
function getClassType(cls: AnyClass): bigint {
|
|
43
44
|
const proto: object = cls.prototype;
|
|
45
|
+
|
|
44
46
|
return Object.hasOwn(proto, "__type__") ? (proto as TypedClass).__type__ : TYPE_INVALID;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
/** Returns the GType tag of the given wrapper instance. */
|
|
48
|
-
|
|
50
|
+
function getInstanceType(instance: object): bigint {
|
|
49
51
|
return getClassType(instance.constructor as AnyClass);
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
if (type
|
|
54
|
-
|
|
55
|
-
setClassType(cls, type);
|
|
54
|
+
function registerClassType(cls: AnyClass, type: bigint): void {
|
|
55
|
+
if (type === TYPE_INVALID) {
|
|
56
|
+
return;
|
|
56
57
|
}
|
|
58
|
+
|
|
59
|
+
classRegistry.set(type, cls);
|
|
60
|
+
setClassType(cls, type);
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
/**
|
|
@@ -63,9 +67,12 @@ export function registerClassType(cls: AnyClass, type: bigint): void {
|
|
|
63
67
|
* @param type GType the class wraps.
|
|
64
68
|
* @param vfuncs Virtual functions the class overrides.
|
|
65
69
|
*/
|
|
66
|
-
|
|
70
|
+
function registerWrapperClass(cls: AnyClass, type: bigint, vfuncs?: VfuncRegistry): void {
|
|
67
71
|
registerClassType(cls, type);
|
|
68
|
-
|
|
72
|
+
|
|
73
|
+
if (vfuncs) {
|
|
74
|
+
registerVfuncRegistry(cls, vfuncs);
|
|
75
|
+
}
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
/**
|
|
@@ -76,11 +83,17 @@ export function registerWrapperClass(cls: AnyClass, type: bigint, vfuncs?: Vfunc
|
|
|
76
83
|
* @param mixin Mixin that applies the interface to a wrapper class.
|
|
77
84
|
* @param vfuncs Virtual functions the interface exposes.
|
|
78
85
|
*/
|
|
79
|
-
|
|
80
|
-
if (type === TYPE_INVALID)
|
|
86
|
+
function registerInterface(cls: AnyClass, type: bigint, mixin: Mixin, vfuncs?: VfuncRegistry): void {
|
|
87
|
+
if (type === TYPE_INVALID) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
81
91
|
setClassType(cls, type);
|
|
82
92
|
interfaceMixinRegistry.set(type, mixin);
|
|
83
|
-
|
|
93
|
+
|
|
94
|
+
if (vfuncs) {
|
|
95
|
+
registerInterfaceVfuncRegistry(type, vfuncs);
|
|
96
|
+
}
|
|
84
97
|
}
|
|
85
98
|
|
|
86
99
|
/**
|
|
@@ -91,24 +104,29 @@ export function registerInterface(cls: AnyClass, type: bigint, mixin: Mixin, vfu
|
|
|
91
104
|
* @param handle Native handle to wrap.
|
|
92
105
|
* @param cls Wrapper class to instantiate, or omitted to resolve it from the runtime type.
|
|
93
106
|
*/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
107
|
+
function wrapHandle(handle: null | undefined, cls?: AnyClass): null;
|
|
108
|
+
function wrapHandle<T extends object>(handle: ExternalObject<Handle>, cls: AnyClass<T>): T;
|
|
109
|
+
|
|
110
|
+
function wrapHandle<T extends object>(
|
|
97
111
|
handle: ExternalObject<Handle> | null | undefined,
|
|
98
112
|
cls: AnyClass<T>,
|
|
99
113
|
): T | null;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
):
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
|
|
115
|
+
function wrapHandle(handle: ExternalObject<Handle>, cls?: AnyClass): TypedClass;
|
|
116
|
+
function wrapHandle(handle: ExternalObject<Handle> | null | undefined, cls?: AnyClass): TypedClass | null;
|
|
117
|
+
|
|
118
|
+
function wrapHandle(handle: ExternalObject<Handle> | null | undefined, cls?: AnyClass): object | null {
|
|
119
|
+
if (handle === null || handle === undefined) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
107
123
|
if (cls === undefined) {
|
|
108
124
|
return getOrCreateWrapper(handle);
|
|
109
125
|
}
|
|
110
|
-
|
|
126
|
+
|
|
127
|
+
const instance: object = Object.create(cls.prototype) as object;
|
|
111
128
|
setHandle(instance, handle);
|
|
129
|
+
|
|
112
130
|
return instance;
|
|
113
131
|
}
|
|
114
132
|
|
|
@@ -116,85 +134,135 @@ export function wrapHandle(handle: ExternalObject<Handle> | null | undefined, cl
|
|
|
116
134
|
* Returns the wrapper class registered for a GType, walking up to ancestor types,
|
|
117
135
|
* and throws if none is registered.
|
|
118
136
|
*/
|
|
119
|
-
|
|
137
|
+
function getWrapperClass(type: bigint): AnyClass {
|
|
120
138
|
const cls = resolveWrapperClass(type);
|
|
139
|
+
|
|
121
140
|
if (!cls) {
|
|
122
141
|
throw new Error(`No registered wrapper class for type '${typeName(type) ?? String(type)}'`);
|
|
123
142
|
}
|
|
143
|
+
|
|
124
144
|
return cls;
|
|
125
145
|
}
|
|
126
146
|
|
|
127
|
-
|
|
147
|
+
function resolveWrapperClass(type: bigint): AnyClass | null {
|
|
128
148
|
let currentType = type;
|
|
149
|
+
|
|
129
150
|
while (currentType !== TYPE_INVALID) {
|
|
130
151
|
const cls = classRegistry.get(currentType);
|
|
131
|
-
|
|
152
|
+
|
|
153
|
+
if (cls) {
|
|
154
|
+
return cls;
|
|
155
|
+
}
|
|
156
|
+
|
|
132
157
|
currentType = typeParent(currentType);
|
|
133
158
|
}
|
|
159
|
+
|
|
134
160
|
return null;
|
|
135
161
|
}
|
|
136
162
|
|
|
163
|
+
function applyInterfaceMixin(cls: AnyClass, type: bigint, baseType: bigint, applied: Set<bigint>): AnyClass {
|
|
164
|
+
if (applied.has(type) || typeIsA(baseType, type)) {
|
|
165
|
+
return cls;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const mixin = interfaceMixinRegistry.get(type);
|
|
169
|
+
|
|
170
|
+
if (mixin === undefined) {
|
|
171
|
+
return cls;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
applied.add(type);
|
|
175
|
+
|
|
176
|
+
return mixin(cls as AnyClass<MixinReceiver>);
|
|
177
|
+
}
|
|
178
|
+
|
|
137
179
|
function createComposedClass(base: AnyClass, runtimeType: bigint): AnyClass {
|
|
138
180
|
const baseType = getClassType(base);
|
|
139
|
-
const applied = new Set
|
|
181
|
+
const applied: Set<bigint> = new Set();
|
|
140
182
|
let cls: AnyClass = base;
|
|
183
|
+
|
|
141
184
|
for (const type of typeInterfaces(runtimeType)) {
|
|
142
|
-
|
|
143
|
-
const mixin = interfaceMixinRegistry.get(type);
|
|
144
|
-
if (mixin === undefined) continue;
|
|
145
|
-
applied.add(type);
|
|
146
|
-
cls = mixin(cls as AnyClass<MixinReceiver>);
|
|
185
|
+
cls = applyInterfaceMixin(cls, type, baseType, applied);
|
|
147
186
|
}
|
|
187
|
+
|
|
148
188
|
return applied.size === 0 ? base : cls;
|
|
149
189
|
}
|
|
150
190
|
|
|
151
191
|
function resolveComposedClass(runtimeType: bigint): AnyClass | null {
|
|
152
192
|
const exact = classRegistry.get(runtimeType);
|
|
153
|
-
|
|
193
|
+
|
|
194
|
+
if (exact) {
|
|
195
|
+
return exact;
|
|
196
|
+
}
|
|
197
|
+
|
|
154
198
|
const cached = composedClassRegistry.get(runtimeType);
|
|
155
|
-
|
|
199
|
+
|
|
200
|
+
if (cached) {
|
|
201
|
+
return cached;
|
|
202
|
+
}
|
|
203
|
+
|
|
156
204
|
const base = resolveWrapperClass(runtimeType);
|
|
157
|
-
|
|
205
|
+
|
|
206
|
+
if (base === null) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
|
|
158
210
|
const composed = createComposedClass(base, runtimeType);
|
|
159
|
-
|
|
211
|
+
|
|
212
|
+
if (composed === base) {
|
|
213
|
+
return base;
|
|
214
|
+
}
|
|
215
|
+
|
|
160
216
|
setClassType(composed, runtimeType);
|
|
161
217
|
composedClassRegistry.set(runtimeType, composed);
|
|
218
|
+
|
|
162
219
|
return composed;
|
|
163
220
|
}
|
|
164
221
|
|
|
165
222
|
function getOrCreateWrapper(handle: ExternalObject<Handle>): object {
|
|
166
223
|
const existing = getWrapper(handle);
|
|
167
|
-
|
|
224
|
+
|
|
225
|
+
if (existing) {
|
|
226
|
+
return existing;
|
|
227
|
+
}
|
|
168
228
|
|
|
169
229
|
const runtimeType: bigint = getType(handle);
|
|
230
|
+
|
|
170
231
|
if (runtimeType === TYPE_INVALID) {
|
|
171
232
|
throw new Error("Cannot resolve runtime GLib type from handle");
|
|
172
233
|
}
|
|
173
234
|
|
|
174
235
|
const cls = resolveComposedClass(runtimeType);
|
|
175
|
-
|
|
176
|
-
|
|
236
|
+
|
|
237
|
+
if (!cls) {
|
|
238
|
+
throw new Error(`Expected registered GLib type, got type ${String(runtimeType)}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const instance: object = Object.create(cls.prototype) as object;
|
|
177
242
|
registerWrapper(handle, instance);
|
|
243
|
+
|
|
178
244
|
return instance;
|
|
179
245
|
}
|
|
180
246
|
|
|
181
247
|
/** Returns the native handle bound to a wrapper instance, throwing if none is set. */
|
|
182
|
-
|
|
248
|
+
function getHandle(instance: object): ExternalObject<Handle> {
|
|
183
249
|
const handle = handleMap.get(instance);
|
|
250
|
+
|
|
184
251
|
if (handle === undefined) {
|
|
185
252
|
const name = (instance as { constructor?: { name?: string } }).constructor?.name ?? "object";
|
|
186
253
|
throw new Error(`No native handle associated with ${name}`);
|
|
187
254
|
}
|
|
255
|
+
|
|
188
256
|
return handle;
|
|
189
257
|
}
|
|
190
258
|
|
|
191
259
|
/** Returns the native handle bound to an instance, or undefined when there is none or the instance is null. */
|
|
192
|
-
|
|
260
|
+
function tryGetHandle(instance: object | null | undefined): ExternalObject<Handle> | undefined {
|
|
193
261
|
return instance == null ? undefined : handleMap.get(instance);
|
|
194
262
|
}
|
|
195
263
|
|
|
196
264
|
/** Associates a native handle with a wrapper instance. */
|
|
197
|
-
|
|
265
|
+
function setHandle(instance: object, handle: ExternalObject<Handle>): void {
|
|
198
266
|
handleMap.set(instance, handle);
|
|
199
267
|
}
|
|
200
268
|
|
|
@@ -207,15 +275,37 @@ function registerVfuncRegistry(cls: object, registry: VfuncRegistry): void {
|
|
|
207
275
|
vfuncRegistry.set(cls, registry);
|
|
208
276
|
}
|
|
209
277
|
|
|
210
|
-
|
|
278
|
+
function getVfuncRegistry(cls: object): VfuncRegistry | undefined {
|
|
211
279
|
return vfuncRegistry.get(cls);
|
|
212
280
|
}
|
|
213
281
|
|
|
214
282
|
function registerInterfaceVfuncRegistry(type: bigint, registry: VfuncRegistry): void {
|
|
215
|
-
if (type === TYPE_INVALID)
|
|
283
|
+
if (type === TYPE_INVALID) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
216
287
|
interfaceVfuncRegistry.set(type, registry);
|
|
217
288
|
}
|
|
218
289
|
|
|
219
|
-
|
|
290
|
+
function getInterfaceVfuncRegistry(type: bigint): VfuncRegistry | undefined {
|
|
220
291
|
return interfaceVfuncRegistry.get(type);
|
|
221
292
|
}
|
|
293
|
+
|
|
294
|
+
export {
|
|
295
|
+
getClassType,
|
|
296
|
+
getInstanceType,
|
|
297
|
+
registerClassType,
|
|
298
|
+
registerWrapperClass,
|
|
299
|
+
registerInterface,
|
|
300
|
+
wrapHandle,
|
|
301
|
+
getWrapperClass,
|
|
302
|
+
resolveWrapperClass,
|
|
303
|
+
getHandle,
|
|
304
|
+
tryGetHandle,
|
|
305
|
+
setHandle,
|
|
306
|
+
getVfuncRegistry,
|
|
307
|
+
getInterfaceVfuncRegistry,
|
|
308
|
+
type StaticBase,
|
|
309
|
+
type VfuncDescriptor,
|
|
310
|
+
type VfuncRegistry,
|
|
311
|
+
};
|
package/src/signal.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { Descriptor, ExternalObject, Handle } from "@gtkx/native";
|
|
2
|
+
import type { TypedClass } from "./type.js";
|
|
2
3
|
import { type Arg, isCallerAllocatedArg, isInoutArg, isOutputArg } from "./arg.js";
|
|
3
4
|
import { bind, createBindCache } from "./bind.js";
|
|
4
5
|
import { wrapCallback } from "./callback.js";
|
|
5
6
|
import {
|
|
6
7
|
arrayT,
|
|
7
8
|
biguint64T,
|
|
9
|
+
booleanT,
|
|
8
10
|
type CallbackDescriptor,
|
|
9
11
|
objectT,
|
|
10
12
|
stringT,
|
|
@@ -15,7 +17,6 @@ import {
|
|
|
15
17
|
import { LIB, VALUE_SIZE, VALUE_T } from "./library.js";
|
|
16
18
|
import { getHandle } from "./registry.js";
|
|
17
19
|
import { packTupleResult } from "./tuple.js";
|
|
18
|
-
import type { TypedClass } from "./type.js";
|
|
19
20
|
import {
|
|
20
21
|
fromValue,
|
|
21
22
|
getBoxedValue,
|
|
@@ -27,7 +28,7 @@ import {
|
|
|
27
28
|
} from "./value.js";
|
|
28
29
|
|
|
29
30
|
/** Function invoked when a connected GObject signal is emitted. */
|
|
30
|
-
|
|
31
|
+
type SignalHandler = (...args: unknown[]) => unknown;
|
|
31
32
|
|
|
32
33
|
type SignalConnectSpec = {
|
|
33
34
|
callback: CallbackDescriptor;
|
|
@@ -55,25 +56,42 @@ const gSignalHandlersBlockMatched = bind(
|
|
|
55
56
|
uint32T,
|
|
56
57
|
);
|
|
57
58
|
|
|
59
|
+
const gSignalHandlerIsConnected = bind(
|
|
60
|
+
LIB,
|
|
61
|
+
"g_signal_handler_is_connected",
|
|
62
|
+
[objectT("borrowed"), uint64T],
|
|
63
|
+
booleanT,
|
|
64
|
+
);
|
|
65
|
+
|
|
58
66
|
/** Returns the signal name without its detail suffix (the part after `::`). */
|
|
59
|
-
|
|
67
|
+
const getSignalBaseName = (signal: string): string => {
|
|
60
68
|
const detailIndex = signal.indexOf("::");
|
|
69
|
+
|
|
61
70
|
return detailIndex === -1 ? signal : signal.slice(0, detailIndex);
|
|
62
71
|
};
|
|
63
72
|
|
|
64
|
-
function
|
|
73
|
+
function getSignalDetailQuark(signal: string): number {
|
|
65
74
|
const detailIndex = signal.indexOf("::");
|
|
66
|
-
|
|
75
|
+
|
|
76
|
+
if (detailIndex === -1) {
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
67
80
|
return gQuarkFromString(signal.slice(detailIndex + 2)) as number;
|
|
68
81
|
}
|
|
69
82
|
|
|
83
|
+
const isSignalHandlerConnected = (instance: object, handlerId: number): boolean =>
|
|
84
|
+
gSignalHandlerIsConnected(getHandle(instance), handlerId) as boolean;
|
|
85
|
+
|
|
70
86
|
const getSignalId = (instance: object, signal: string): number => {
|
|
71
87
|
const type: bigint = (instance as TypedClass).__type__;
|
|
88
|
+
|
|
72
89
|
return gSignalLookup(getSignalBaseName(signal), type) as number;
|
|
73
90
|
};
|
|
74
91
|
|
|
75
92
|
function connectBind(type: bigint, signal: string, callback: CallbackDescriptor): (...values: unknown[]) => unknown {
|
|
76
|
-
const key = `${type}\0${getSignalBaseName(signal)}`;
|
|
93
|
+
const key = `${String(type)}\0${getSignalBaseName(signal)}`;
|
|
94
|
+
|
|
77
95
|
return connectCache(
|
|
78
96
|
key,
|
|
79
97
|
LIB,
|
|
@@ -89,26 +107,35 @@ function connectBind(type: bigint, signal: string, callback: CallbackDescriptor)
|
|
|
89
107
|
* @param signal Signal name, optionally including a `::detail` suffix.
|
|
90
108
|
* @param spec Callback descriptor, handler function, and whether to run after the default handler.
|
|
91
109
|
*/
|
|
92
|
-
|
|
110
|
+
function connectSignal(instance: object, signal: string, spec: SignalConnectSpec): number {
|
|
93
111
|
const { callback, handler, after } = spec;
|
|
94
112
|
const wrapped = wrapCallback(handler, callback, "emitter");
|
|
95
113
|
const type: bigint = (instance as TypedClass).__type__;
|
|
96
114
|
const connect = connectBind(type, signal, callback);
|
|
115
|
+
|
|
97
116
|
return connect(getHandle(instance), signal, wrapped, after ? 1 : 0) as number;
|
|
98
117
|
}
|
|
99
118
|
|
|
100
|
-
|
|
119
|
+
function blockMatchedSignalHandlers(instance: object, signal: string): void {
|
|
101
120
|
const signalId = getSignalId(instance, signal);
|
|
102
121
|
gSignalHandlersBlockMatched(getHandle(instance), 1, signalId, 0, undefined, undefined, undefined);
|
|
103
122
|
}
|
|
104
123
|
|
|
105
124
|
const createEmitValue = (arg: EmitArg): { value: ExternalObject<Handle>; read?: () => unknown } => {
|
|
106
|
-
if (!isOutputArg(arg))
|
|
125
|
+
if (!isOutputArg(arg)) {
|
|
126
|
+
return { value: toValue(arg.type, arg.value) };
|
|
127
|
+
}
|
|
128
|
+
|
|
107
129
|
if (isCallerAllocatedArg(arg)) {
|
|
108
|
-
if (isInoutArg(arg))
|
|
130
|
+
if (isInoutArg(arg)) {
|
|
131
|
+
return { value: inoutValueForBoxedDescriptor(arg.type, arg.value as object) };
|
|
132
|
+
}
|
|
133
|
+
|
|
109
134
|
const value = outValueForBoxedDescriptor(arg.type, arg.value as object);
|
|
135
|
+
|
|
110
136
|
return { value, read: () => getBoxedValue(value) };
|
|
111
137
|
}
|
|
138
|
+
|
|
112
139
|
return isInoutArg(arg) ? outValueForDescriptor(arg.type, arg.value) : outValueForDescriptor(arg.type);
|
|
113
140
|
};
|
|
114
141
|
|
|
@@ -120,21 +147,25 @@ const createEmitValue = (arg: EmitArg): { value: ExternalObject<Handle>; read?:
|
|
|
120
147
|
* @param args Arguments to pass, including output and inout arguments.
|
|
121
148
|
* @param returnDescriptor Descriptor for the signal's return value, omitted when it returns void.
|
|
122
149
|
*/
|
|
123
|
-
|
|
150
|
+
function emitSignal(instance: object, signal: string, args: EmitArg[], returnDescriptor?: Descriptor): unknown {
|
|
124
151
|
const signalId = getSignalId(instance, signal);
|
|
125
|
-
const detail =
|
|
152
|
+
const detail = getSignalDetailQuark(signal);
|
|
126
153
|
const values: ExternalObject<Handle>[] = [toValue(objectT("full"), instance)];
|
|
127
154
|
const reads: (() => unknown)[] = [];
|
|
128
155
|
|
|
129
156
|
for (const arg of args) {
|
|
130
157
|
const { value, read } = createEmitValue(arg);
|
|
131
158
|
values.push(value);
|
|
132
|
-
|
|
159
|
+
|
|
160
|
+
if (read) {
|
|
161
|
+
reads.push(read);
|
|
162
|
+
}
|
|
133
163
|
}
|
|
134
164
|
|
|
135
165
|
if (returnDescriptor !== undefined) {
|
|
136
166
|
const returnValue = newValueForDescriptor(returnDescriptor);
|
|
137
167
|
gSignalEmitv(values, signalId, detail, returnValue);
|
|
168
|
+
|
|
138
169
|
return packTupleResult(
|
|
139
170
|
reads.map((read) => read()),
|
|
140
171
|
fromValue(returnValue),
|
|
@@ -150,3 +181,12 @@ export function emitSignal(instance: object, signal: string, args: EmitArg[], re
|
|
|
150
181
|
false,
|
|
151
182
|
);
|
|
152
183
|
}
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
getSignalBaseName,
|
|
187
|
+
connectSignal,
|
|
188
|
+
blockMatchedSignalHandlers,
|
|
189
|
+
emitSignal,
|
|
190
|
+
isSignalHandlerConnected,
|
|
191
|
+
type SignalHandler,
|
|
192
|
+
};
|
package/src/t.ts
CHANGED
|
@@ -47,7 +47,7 @@ type T = {
|
|
|
47
47
|
* FFI marshalling, plus `bind` to bind a native function and `fn` to describe a
|
|
48
48
|
* function signature.
|
|
49
49
|
*/
|
|
50
|
-
|
|
50
|
+
const t: T = {
|
|
51
51
|
bind,
|
|
52
52
|
int8: helpers.int8T,
|
|
53
53
|
uint8: helpers.uint8T,
|
|
@@ -86,3 +86,5 @@ export const t: T = {
|
|
|
86
86
|
callback: helpers.callbackT,
|
|
87
87
|
fn,
|
|
88
88
|
};
|
|
89
|
+
|
|
90
|
+
export { t };
|
package/src/tuple.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
const packTupleResult = (outs: unknown[], primary: unknown, hasPrimary: boolean): unknown => {
|
|
2
2
|
if (hasPrimary) {
|
|
3
3
|
return outs.length === 0 ? primary : [primary, ...outs];
|
|
4
4
|
}
|
|
5
|
-
|
|
6
|
-
if (outs.length ===
|
|
5
|
+
|
|
6
|
+
if (outs.length === 0) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (outs.length === 1) {
|
|
11
|
+
return outs[0];
|
|
12
|
+
}
|
|
13
|
+
|
|
7
14
|
return outs;
|
|
8
15
|
};
|
|
9
16
|
|
|
10
|
-
|
|
17
|
+
const splitTupleResult = (
|
|
11
18
|
result: unknown,
|
|
12
19
|
hasPrimary: boolean,
|
|
13
20
|
outCount: number,
|
|
@@ -16,10 +23,15 @@ export const splitTupleResult = (
|
|
|
16
23
|
if (Array.isArray(result)) {
|
|
17
24
|
return { primary: result[0], outValues: result.slice(1) };
|
|
18
25
|
}
|
|
26
|
+
|
|
19
27
|
return { primary: result, outValues: [] };
|
|
20
28
|
}
|
|
29
|
+
|
|
21
30
|
if (outCount === 1) {
|
|
22
31
|
return { primary: undefined, outValues: [result] };
|
|
23
32
|
}
|
|
33
|
+
|
|
24
34
|
return { primary: undefined, outValues: Array.isArray(result) ? result : [] };
|
|
25
35
|
};
|
|
36
|
+
|
|
37
|
+
export { packTupleResult, splitTupleResult };
|