@gtkx/runtime 1.0.0-rc.3 → 1.0.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 (141) hide show
  1. package/README.md +8 -9
  2. package/dist/application-class.d.ts +32 -0
  3. package/dist/application-class.d.ts.map +1 -0
  4. package/dist/application-class.js +68 -0
  5. package/dist/application-class.js.map +1 -0
  6. package/dist/arg.d.ts +9 -3
  7. package/dist/arg.d.ts.map +1 -1
  8. package/dist/arg.js +4 -3
  9. package/dist/arg.js.map +1 -1
  10. package/dist/bind.d.ts +11 -0
  11. package/dist/bind.d.ts.map +1 -1
  12. package/dist/bind.js +11 -0
  13. package/dist/bind.js.map +1 -1
  14. package/dist/callback.d.ts +2 -1
  15. package/dist/callback.d.ts.map +1 -1
  16. package/dist/callback.js +119 -21
  17. package/dist/callback.js.map +1 -1
  18. package/dist/closure.d.ts +26 -0
  19. package/dist/closure.d.ts.map +1 -0
  20. package/dist/closure.js +99 -0
  21. package/dist/closure.js.map +1 -0
  22. package/dist/descriptors.d.ts +105 -6
  23. package/dist/descriptors.d.ts.map +1 -1
  24. package/dist/descriptors.js +56 -12
  25. package/dist/descriptors.js.map +1 -1
  26. package/dist/error.d.ts +7 -0
  27. package/dist/error.d.ts.map +1 -1
  28. package/dist/error.js +1 -1
  29. package/dist/error.js.map +1 -1
  30. package/dist/fn.d.ts +24 -3
  31. package/dist/fn.d.ts.map +1 -1
  32. package/dist/fn.js +70 -33
  33. package/dist/fn.js.map +1 -1
  34. package/dist/index.d.ts +29 -7
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +26 -4
  37. package/dist/index.js.map +1 -1
  38. package/dist/internal.d.ts +1 -0
  39. package/dist/internal.d.ts.map +1 -1
  40. package/dist/internal.js +1 -0
  41. package/dist/internal.js.map +1 -1
  42. package/dist/library.d.ts +2 -1
  43. package/dist/library.d.ts.map +1 -1
  44. package/dist/library.js +2 -1
  45. package/dist/library.js.map +1 -1
  46. package/dist/lifecycle.d.ts +52 -10
  47. package/dist/lifecycle.d.ts.map +1 -1
  48. package/dist/lifecycle.js +62 -18
  49. package/dist/lifecycle.js.map +1 -1
  50. package/dist/listeners.d.ts +6 -0
  51. package/dist/listeners.d.ts.map +1 -1
  52. package/dist/listeners.js +3 -1
  53. package/dist/listeners.js.map +1 -1
  54. package/dist/mixin.d.ts +16 -2
  55. package/dist/mixin.d.ts.map +1 -1
  56. package/dist/mixin.js +18 -6
  57. package/dist/mixin.js.map +1 -1
  58. package/dist/native-value.d.ts +8 -0
  59. package/dist/native-value.d.ts.map +1 -1
  60. package/dist/native-value.js +12 -3
  61. package/dist/native-value.js.map +1 -1
  62. package/dist/object.d.ts +34 -6
  63. package/dist/object.d.ts.map +1 -1
  64. package/dist/object.js +89 -25
  65. package/dist/object.js.map +1 -1
  66. package/dist/param-spec.d.ts +11 -0
  67. package/dist/param-spec.d.ts.map +1 -0
  68. package/dist/param-spec.js +149 -0
  69. package/dist/param-spec.js.map +1 -0
  70. package/dist/promisify.d.ts +3 -5
  71. package/dist/promisify.d.ts.map +1 -1
  72. package/dist/promisify.js +4 -3
  73. package/dist/promisify.js.map +1 -1
  74. package/dist/properties.d.ts +39 -7
  75. package/dist/properties.d.ts.map +1 -1
  76. package/dist/properties.js +305 -42
  77. package/dist/properties.js.map +1 -1
  78. package/dist/register-class.d.ts +119 -14
  79. package/dist/register-class.d.ts.map +1 -1
  80. package/dist/register-class.js +109 -80
  81. package/dist/register-class.js.map +1 -1
  82. package/dist/registry.d.ts +81 -17
  83. package/dist/registry.d.ts.map +1 -1
  84. package/dist/registry.js +72 -26
  85. package/dist/registry.js.map +1 -1
  86. package/dist/signal.d.ts +22 -3
  87. package/dist/signal.d.ts.map +1 -1
  88. package/dist/signal.js +64 -8
  89. package/dist/signal.js.map +1 -1
  90. package/dist/t.d.ts +44 -0
  91. package/dist/t.d.ts.map +1 -1
  92. package/dist/t.js.map +1 -1
  93. package/dist/type.d.ts +2 -2
  94. package/dist/type.d.ts.map +1 -1
  95. package/dist/type.js +2 -0
  96. package/dist/type.js.map +1 -1
  97. package/dist/value.d.ts +10 -10
  98. package/dist/value.d.ts.map +1 -1
  99. package/dist/value.js +44 -22
  100. package/dist/value.js.map +1 -1
  101. package/dist/vfunc-call.d.ts +37 -0
  102. package/dist/vfunc-call.d.ts.map +1 -0
  103. package/dist/vfunc-call.js +168 -0
  104. package/dist/vfunc-call.js.map +1 -0
  105. package/dist/vfunc-seeds.d.ts +12 -0
  106. package/dist/vfunc-seeds.d.ts.map +1 -0
  107. package/dist/vfunc-seeds.js +19 -0
  108. package/dist/vfunc-seeds.js.map +1 -0
  109. package/dist/vfunc.d.ts +8 -0
  110. package/dist/vfunc.d.ts.map +1 -0
  111. package/dist/vfunc.js +23 -0
  112. package/dist/vfunc.js.map +1 -0
  113. package/package.json +4 -4
  114. package/src/application-class.ts +116 -0
  115. package/src/arg.ts +11 -5
  116. package/src/bind.ts +11 -0
  117. package/src/callback.ts +163 -23
  118. package/src/closure.ts +136 -0
  119. package/src/descriptors.ts +137 -41
  120. package/src/error.ts +8 -1
  121. package/src/fn.ts +104 -39
  122. package/src/index.ts +36 -7
  123. package/src/internal.ts +1 -0
  124. package/src/library.ts +2 -1
  125. package/src/lifecycle.ts +99 -22
  126. package/src/listeners.ts +9 -1
  127. package/src/mixin.ts +27 -8
  128. package/src/native-value.ts +13 -3
  129. package/src/object.ts +128 -34
  130. package/src/param-spec.ts +235 -0
  131. package/src/promisify.ts +8 -8
  132. package/src/properties.ts +459 -45
  133. package/src/register-class.ts +329 -114
  134. package/src/registry.ts +150 -38
  135. package/src/signal.ts +101 -17
  136. package/src/t.ts +44 -0
  137. package/src/type.ts +3 -2
  138. package/src/value.ts +57 -19
  139. package/src/vfunc-call.ts +243 -0
  140. package/src/vfunc-seeds.ts +36 -0
  141. package/src/vfunc.ts +31 -0
@@ -1,97 +1,192 @@
1
1
  import type { ArrayKind, Descriptor, Ownership } from "@gtkx/native";
2
2
  import type { AnyClass } from "@gtkx/utils";
3
3
 
4
+ /** Descriptor variant for a `gint8`. */
4
5
  type Int8Descriptor = Extract<Descriptor, { kind: "int8" }>;
6
+ /** Descriptor variant for a `guint8`. */
5
7
  type Uint8Descriptor = Extract<Descriptor, { kind: "uint8" }>;
8
+ /** Descriptor variant for a `gint16`. */
6
9
  type Int16Descriptor = Extract<Descriptor, { kind: "int16" }>;
10
+ /** Descriptor variant for a `guint16`. */
7
11
  type Uint16Descriptor = Extract<Descriptor, { kind: "uint16" }>;
12
+ /** Descriptor variant for a `gint32`. */
8
13
  type Int32Descriptor = Extract<Descriptor, { kind: "int32" }>;
14
+ /** Descriptor variant for a `guint32`. */
9
15
  type Uint32Descriptor = Extract<Descriptor, { kind: "uint32" }>;
16
+ /** Descriptor variant for a `gint64` marshalled as a number. */
10
17
  type Int64Descriptor = Extract<Descriptor, { kind: "int64" }>;
18
+ /** Descriptor variant for a `guint64` marshalled as a number. */
11
19
  type Uint64Descriptor = Extract<Descriptor, { kind: "uint64" }>;
20
+ /** Descriptor variant for a `gint64` marshalled as a bigint. */
12
21
  type BigInt64Descriptor = Extract<Descriptor, { kind: "bigint64" }>;
22
+ /** Descriptor variant for a `guint64` marshalled as a bigint. */
13
23
  type BigUint64Descriptor = Extract<Descriptor, { kind: "biguint64" }>;
24
+ /** Descriptor variant for a `gfloat`. */
14
25
  type Float32Descriptor = Extract<Descriptor, { kind: "float32" }>;
26
+ /** Descriptor variant for a `gdouble`. */
15
27
  type Float64Descriptor = Extract<Descriptor, { kind: "float64" }>;
28
+ /** Descriptor variant for an enumeration, carrying the library and `get_type` symbol its GType comes from. */
16
29
  type EnumDescriptor = Extract<Descriptor, { kind: "enum" }>;
30
+ /** Descriptor variant for a flags type, carrying the library and `get_type` symbol its GType comes from. */
17
31
  type FlagsDescriptor = Extract<Descriptor, { kind: "flags" }>;
32
+ /** Descriptor variant for a `gboolean`. */
18
33
  type BooleanDescriptor = Extract<Descriptor, { kind: "boolean" }>;
34
+ /** Descriptor variant for a C string. */
19
35
  type StringDescriptor = Extract<Descriptor, { kind: "string" }>;
36
+ /** Descriptor variant for a `GObject`. */
20
37
  type ObjectDescriptor = Extract<Descriptor, { kind: "object" }>;
38
+ /** Descriptor variant for a `gunichar`. */
21
39
  type UnicharDescriptor = Extract<Descriptor, { kind: "unichar" }>;
40
+ /** Descriptor variant for the absence of a value. */
22
41
  type VoidDescriptor = Extract<Descriptor, { kind: "void" }>;
42
+ /** Descriptor variant for an opaque `gpointer`. */
23
43
  type BufferDescriptor = Extract<Descriptor, { kind: "buffer" }>;
44
+ /** Descriptor variant for a `GBoxed` value. */
24
45
  type BoxedDescriptor = Extract<Descriptor, { kind: "boxed" }>;
25
- type StructDescriptor = Extract<Descriptor, { kind: "struct" }> & { wrapperClass?: AnyClass };
26
- type FundamentalDescriptor = Extract<Descriptor, { kind: "fundamental" }> & { wrapperClass?: AnyClass };
46
+
47
+ /** Descriptor variant for a plain C struct, extended with the class its decoded value is wrapped in. */
48
+ type StructDescriptor = Extract<Descriptor, { kind: "struct" }> & {
49
+ /** Class a decoded value is wrapped in; without it the wrapper comes from the value's own GType. */
50
+ wrapperClass?: AnyClass;
51
+ };
52
+
53
+ /** Descriptor variant for a ref-counted fundamental type, extended with the class its decoded value is wrapped in. */
54
+ type FundamentalDescriptor = Extract<Descriptor, { kind: "fundamental" }> & {
55
+ /** Class a decoded value is wrapped in; without it the wrapper comes from the type named by `typeName`. */
56
+ wrapperClass?: AnyClass;
57
+ };
58
+
59
+ /** Descriptor variant for an array of items in one of the supported container layouts. */
27
60
  type ArrayDescriptor = Extract<Descriptor, { kind: "array" }>;
61
+ /** Descriptor variant for a `GHashTable`, marshalled as an array of key/value pairs. */
28
62
  type HashTableDescriptor = Extract<Descriptor, { kind: "hashtable" }>;
63
+ /** Descriptor variant for a function pointer a JavaScript function is marshalled into. */
29
64
  type CallbackDescriptor = Extract<Descriptor, { kind: "callback" }>;
65
+ /** Descriptor variant for a pointer to another descriptor's value, for an output or inout argument. */
30
66
  type RefDescriptor = Extract<Descriptor, { kind: "ref" }>;
31
- type TypeDescriptor = BigUint64Descriptor & { type: true };
32
67
 
68
+ /** Descriptor for a `GType`: a `guint64` marked so it resolves to `G_TYPE_GTYPE` rather than an integer. */
69
+ type TypeDescriptor = BigUint64Descriptor & {
70
+ /** Distinguishes a GType from a plain `guint64` when the GLib type and the GValue type are resolved. */
71
+ type: true;
72
+ };
73
+
74
+ /** How a boxed value is stored, and where its GType and free function are resolved from. */
33
75
  type BoxedOptions = {
34
- callerAllocated?: boolean;
35
- inline?: boolean;
76
+ /** The caller owns the storage the callee fills, so a decoded value is borrowed instead of copied. */
77
+ isCallerAllocated?: boolean;
78
+ /** The value is embedded in the containing struct rather than reached through a pointer. */
79
+ isInline?: boolean;
80
+ /** Whether a decoded value is owned by the caller; defaults to `"borrowed"`. */
36
81
  ownership?: Ownership;
82
+ /** Library `getTypeFnName` and `freeFnName` are resolved in. */
37
83
  sharedLibrary?: string;
84
+ /** Symbol returning the boxed GType, used when the type is not already registered under its name. */
38
85
  getTypeFnName?: string;
86
+ /** Symbol that frees the value, for a boxed type with no GType of its own. */
39
87
  freeFnName?: string;
88
+ /** Byte size of the value, needed to copy it into an inline field. */
40
89
  size?: number;
41
90
  };
42
91
 
92
+ /** How the callee takes a callback's closure, and how long that closure has to stay alive. */
43
93
  type CallbackOptions = {
94
+ /** The callee also takes a destroy notify, which frees the closure once it is done with it. */
44
95
  hasDestroy?: boolean;
96
+ /** Signature of that destroy notify; defaults to `destroyNotify`, a one-argument `GDestroyNotify`. */
97
+ destroyKind?: CallbackDescriptor["destroyKind"];
98
+ /** The callee also takes a `user_data` pointer; without one the closure can never be freed. */
99
+ hasUserData?: boolean;
100
+ /** Position of `user_data` among the callback's own arguments, dropped before the closure is called. */
45
101
  userDataIndex?: number;
102
+ /** Lifetime of the closure; defaults to `notified` when `hasDestroy` is set and `call` otherwise. */
46
103
  scope?: CallbackDescriptor["scope"];
47
104
  };
48
105
 
106
+ /** The lengths and strides a C array layout needs beyond its element type. */
49
107
  type ArrayOptions = {
108
+ /** Stride in bytes between elements stored inline in the array. */
50
109
  elementSize?: number | undefined;
110
+ /** Position of the argument carrying the element count, for a length-bounded array. */
51
111
  sizeParamIndex?: number | undefined;
112
+ /** Element count of a fixed-length array. */
52
113
  fixedSize?: number | undefined;
53
114
  };
54
115
 
116
+ /** How a ref-counted fundamental value is named, wrapped and stored. */
55
117
  type FundamentalOptions = {
118
+ /** Whether a decoded value is owned by the caller; defaults to `"borrowed"`. */
56
119
  ownership?: Ownership;
120
+ /** GLib type name the wrapper class is looked up by. */
57
121
  typeName?: string;
122
+ /** Class a decoded value is wrapped in, instead of the one registered for `typeName`. */
58
123
  wrapperClass?: AnyClass;
59
- inline?: boolean;
124
+ /** The value is embedded in the containing struct rather than reached through a pointer. */
125
+ isInline?: boolean;
60
126
  };
61
127
 
128
+ /** How a plain C struct is stored and wrapped. */
62
129
  type StructOptions = {
63
- callerAllocated?: boolean;
64
- inline?: boolean;
130
+ /** The caller owns the storage the callee fills, so a decoded value is borrowed instead of copied. */
131
+ isCallerAllocated?: boolean;
132
+ /** The value is embedded in the containing struct rather than reached through a pointer. */
133
+ isInline?: boolean;
134
+ /** Byte size of the struct, needed to copy it rather than borrow the pointer. */
65
135
  size?: number;
136
+ /** Class a decoded value is wrapped in, instead of the one registered for its GType. */
66
137
  wrapperClass?: AnyClass;
67
138
  };
68
139
 
140
+ /** Descriptor for a `gint8`, marshalled as a number. */
69
141
  const int8T: Int8Descriptor = { kind: "int8" };
142
+ /** Descriptor for a `guint8`, marshalled as a number. */
70
143
  const uint8T: Uint8Descriptor = { kind: "uint8" };
144
+ /** Descriptor for a `gint16`, marshalled as a number. */
71
145
  const int16T: Int16Descriptor = { kind: "int16" };
146
+ /** Descriptor for a `guint16`, marshalled as a number. */
72
147
  const uint16T: Uint16Descriptor = { kind: "uint16" };
148
+ /** Descriptor for a `gint32`, marshalled as a number. */
73
149
  const int32T: Int32Descriptor = { kind: "int32" };
150
+ /** Descriptor for a `guint32`, marshalled as a number. */
74
151
  const uint32T: Uint32Descriptor = { kind: "uint32" };
152
+ /** Descriptor for a `gint64`, marshalled as a number and rejected outside the 2^53 safe range. */
75
153
  const int64T: Int64Descriptor = { kind: "int64" };
154
+ /** Descriptor for a `guint64`, marshalled as a number and rejected outside the 2^53 safe range. */
76
155
  const uint64T: Uint64Descriptor = { kind: "uint64" };
156
+ /** Descriptor for a `gint64`, marshalled as a bigint so the full 64-bit range survives. */
77
157
  const bigint64T: BigInt64Descriptor = { kind: "bigint64" };
158
+ /** Descriptor for a `guint64`, marshalled as a bigint so the full 64-bit range survives. */
78
159
  const biguint64T: BigUint64Descriptor = { kind: "biguint64" };
160
+ /** Descriptor for a `GType`, marshalled as a bigint and recognized as a GType by GValue conversion. */
79
161
  const gtypeT: TypeDescriptor = { kind: "biguint64", type: true };
162
+ /** Descriptor for a `gfloat`. */
80
163
  const float32T: Float32Descriptor = { kind: "float32" };
164
+ /** Descriptor for a `gdouble`. */
81
165
  const float64T: Float64Descriptor = { kind: "float64" };
166
+ /** Descriptor for a `gboolean`, marshalled as a JavaScript boolean. */
82
167
  const booleanT: BooleanDescriptor = { kind: "boolean" };
168
+ /** Descriptor for the absence of a value, used as the return descriptor of a `void` function. */
83
169
  const voidT: VoidDescriptor = { kind: "void" };
170
+ /** Descriptor for a `gunichar`, marshalled as a single-character string or a codepoint number. */
84
171
  const unicharT: UnicharDescriptor = { kind: "unichar" };
172
+ /** Descriptor for an opaque `gpointer`, taken from a typed array's memory or a numeric address. */
85
173
  const bufferT: BufferDescriptor = { kind: "buffer" };
86
174
 
175
+ /**
176
+ * Builds a descriptor for a C string, whose optional length sizes the caller-allocated buffer
177
+ * used when the string is passed by reference.
178
+ */
87
179
  const stringT = (ownership: Ownership = "borrowed", length?: number): StringDescriptor =>
88
180
  length === undefined ? { kind: "string", ownership } : { kind: "string", ownership, length };
89
181
 
182
+ /** Builds a descriptor for a `GObject`, wrapped in the class registered for its runtime GType. */
90
183
  const objectT = (ownership: Ownership = "borrowed"): ObjectDescriptor => ({ kind: "object", ownership });
91
184
 
185
+ /** Wraps a descriptor in a pointer to it, for an output or inout argument. */
92
186
  const refT = (innerDescriptor: Descriptor, isInout = false): RefDescriptor =>
93
187
  isInout ? { kind: "ref", innerDescriptor, inout: true } : { kind: "ref", innerDescriptor };
94
188
 
189
+ /** Builds a descriptor for a `GHashTable`, marshalled as an array of key/value pairs. */
95
190
  const hashTableT = (
96
191
  keyDescriptor: Descriptor,
97
192
  valueDescriptor: Descriptor,
@@ -103,18 +198,20 @@ const hashTableT = (
103
198
  ownership,
104
199
  });
105
200
 
201
+ /** Builds a descriptor for an enumeration, resolving its GType from the named `get_type` function. */
106
202
  const enumT = (sharedLibrary: string, typeFnName: string, isSigned: boolean): EnumDescriptor => ({
107
203
  kind: "enum",
108
204
  sharedLibrary,
109
205
  getTypeFnName: typeFnName,
110
- signed: isSigned,
206
+ isSigned,
111
207
  });
112
208
 
209
+ /** Builds a descriptor for a flags type, resolving its GType from the named `get_type` function. */
113
210
  const flagsT = (sharedLibrary: string, typeFnName: string, isSigned: boolean): FlagsDescriptor => ({
114
211
  kind: "flags",
115
212
  sharedLibrary,
116
213
  getTypeFnName: typeFnName,
117
- signed: isSigned,
214
+ isSigned,
118
215
  });
119
216
 
120
217
  const applyBoxedNames = (result: BoxedDescriptor, options: BoxedOptions): void => {
@@ -134,12 +231,12 @@ const applyBoxedNames = (result: BoxedDescriptor, options: BoxedOptions): void =
134
231
  const applyBoxedOptions = (result: BoxedDescriptor, options: BoxedOptions): void => {
135
232
  applyBoxedNames(result, options);
136
233
 
137
- if (options.callerAllocated) {
138
- result.callerAllocated = true;
234
+ if (options.isCallerAllocated) {
235
+ result.isCallerAllocated = true;
139
236
  }
140
237
 
141
- if (options.inline) {
142
- result.inline = true;
238
+ if (options.isInline) {
239
+ result.isInline = true;
143
240
  }
144
241
 
145
242
  if (options.size !== undefined) {
@@ -147,6 +244,7 @@ const applyBoxedOptions = (result: BoxedDescriptor, options: BoxedOptions): void
147
244
  }
148
245
  };
149
246
 
247
+ /** Builds a descriptor for a `GBoxed` value of the named type. */
150
248
  const boxedT = (typeName: string, options: BoxedOptions = {}): BoxedDescriptor => {
151
249
  const result: BoxedDescriptor = {
152
250
  kind: "boxed",
@@ -159,6 +257,7 @@ const boxedT = (typeName: string, options: BoxedOptions = {}): BoxedDescriptor =
159
257
  return result;
160
258
  };
161
259
 
260
+ /** Builds a descriptor for a plain C struct. */
162
261
  const structT = (ownership: Ownership = "borrowed", options: StructOptions = {}): StructDescriptor => {
163
262
  const result: StructDescriptor = { kind: "struct", ownership };
164
263
 
@@ -170,17 +269,18 @@ const structT = (ownership: Ownership = "borrowed", options: StructOptions = {})
170
269
  result.wrapperClass = options.wrapperClass;
171
270
  }
172
271
 
173
- if (options.callerAllocated) {
174
- result.callerAllocated = true;
272
+ if (options.isCallerAllocated) {
273
+ result.isCallerAllocated = true;
175
274
  }
176
275
 
177
- if (options.inline) {
178
- result.inline = true;
276
+ if (options.isInline) {
277
+ result.isInline = true;
179
278
  }
180
279
 
181
280
  return result;
182
281
  };
183
282
 
283
+ /** Builds a descriptor for a fundamental type whose lifetime is managed by named ref and unref functions. */
184
284
  const fundamentalT = (
185
285
  sharedLibrary: string,
186
286
  refFnName: string,
@@ -198,13 +298,14 @@ const fundamentalT = (
198
298
  result.wrapperClass = options.wrapperClass;
199
299
  }
200
300
 
201
- if (options.inline) {
202
- result.inline = true;
301
+ if (options.isInline) {
302
+ result.isInline = true;
203
303
  }
204
304
 
205
305
  return result;
206
306
  };
207
307
 
308
+ /** Builds a descriptor for an array of items in one of the supported container layouts. */
208
309
  const arrayT = (
209
310
  itemDescriptor: Descriptor,
210
311
  arrayKind: ArrayKind = "array",
@@ -228,15 +329,19 @@ const arrayT = (
228
329
  return result;
229
330
  };
230
331
 
332
+ /** Builds a descriptor for a `GList` of items. */
231
333
  const listT = (itemDescriptor: Descriptor, ownership: Ownership = "borrowed"): ArrayDescriptor =>
232
334
  arrayT(itemDescriptor, "glist", ownership);
233
335
 
336
+ /** Builds a descriptor for a `GSList` of items. */
234
337
  const slistT = (itemDescriptor: Descriptor, ownership: Ownership = "borrowed"): ArrayDescriptor =>
235
338
  arrayT(itemDescriptor, "gslist", ownership);
236
339
 
340
+ /** Builds a descriptor for a `GPtrArray` of items. */
237
341
  const ptrArrayT = (itemDescriptor: Descriptor, ownership: Ownership = "borrowed"): ArrayDescriptor =>
238
342
  arrayT(itemDescriptor, "gptrarray", ownership);
239
343
 
344
+ /** Builds a descriptor for a `GArray` of items, optionally with an explicit element size. */
240
345
  const gArrayT = (
241
346
  itemDescriptor: Descriptor,
242
347
  ownership: Ownership = "borrowed",
@@ -244,9 +349,11 @@ const gArrayT = (
244
349
  ): ArrayDescriptor =>
245
350
  arrayT(itemDescriptor, "garray", ownership, elementSize === undefined ? undefined : { elementSize });
246
351
 
352
+ /** Builds a descriptor for a `GByteArray`. */
247
353
  const byteArrayT = (ownership: Ownership = "borrowed"): ArrayDescriptor =>
248
354
  arrayT(uint8T, "gbytearray", ownership);
249
355
 
356
+ /** Builds a descriptor for a C array whose length is carried by another argument. */
250
357
  const sizedArrayT = (
251
358
  itemDescriptor: Descriptor,
252
359
  sizeParamIndex: number,
@@ -254,6 +361,7 @@ const sizedArrayT = (
254
361
  elementSize?: number,
255
362
  ): ArrayDescriptor => arrayT(itemDescriptor, "sized", ownership, { sizeParamIndex, elementSize });
256
363
 
364
+ /** Builds a descriptor for a C array of a fixed length. */
257
365
  const fixedArrayT = (
258
366
  itemDescriptor: Descriptor,
259
367
  fixedSize: number,
@@ -261,6 +369,7 @@ const fixedArrayT = (
261
369
  elementSize?: number,
262
370
  ): ArrayDescriptor => arrayT(itemDescriptor, "fixed", ownership, { fixedSize, elementSize });
263
371
 
372
+ /** Builds a descriptor for a function pointer, marshalling a JavaScript function into a native closure. */
264
373
  const callbackT = (
265
374
  argDescriptors: Descriptor[],
266
375
  returnDescriptor: Descriptor,
@@ -272,6 +381,14 @@ const callbackT = (
272
381
  result.hasDestroy = options.hasDestroy;
273
382
  }
274
383
 
384
+ if (options?.destroyKind !== undefined) {
385
+ result.destroyKind = options.destroyKind;
386
+ }
387
+
388
+ if (options?.hasUserData !== undefined) {
389
+ result.hasUserData = options.hasUserData;
390
+ }
391
+
275
392
  if (options?.userDataIndex !== undefined) {
276
393
  result.userDataIndex = options.userDataIndex;
277
394
  }
@@ -319,26 +436,6 @@ export {
319
436
  sizedArrayT,
320
437
  fixedArrayT,
321
438
  callbackT,
322
- type Int8Descriptor,
323
- type Uint8Descriptor,
324
- type Int16Descriptor,
325
- type Uint16Descriptor,
326
- type Int32Descriptor,
327
- type Uint32Descriptor,
328
- type Int64Descriptor,
329
- type Uint64Descriptor,
330
- type BigInt64Descriptor,
331
- type BigUint64Descriptor,
332
- type Float32Descriptor,
333
- type Float64Descriptor,
334
- type EnumDescriptor,
335
- type FlagsDescriptor,
336
- type BooleanDescriptor,
337
- type StringDescriptor,
338
- type ObjectDescriptor,
339
- type UnicharDescriptor,
340
- type VoidDescriptor,
341
- type BufferDescriptor,
342
439
  type BoxedDescriptor,
343
440
  type StructDescriptor,
344
441
  type FundamentalDescriptor,
@@ -346,5 +443,4 @@ export {
346
443
  type HashTableDescriptor,
347
444
  type CallbackDescriptor,
348
445
  type RefDescriptor,
349
- type TypeDescriptor,
350
446
  };
package/src/error.ts CHANGED
@@ -2,8 +2,14 @@ import type { ExternalObject, Handle, Ref } from "@gtkx/native";
2
2
  import { getWrapperClass, wrapHandle } from "./registry.js";
3
3
  import { getErrorType, isTypedClass } from "./type.js";
4
4
 
5
+ /**
6
+ * A wrapped `GError` thrown across the FFI boundary: a JavaScript `Error` that also identifies its
7
+ * GLib domain and code.
8
+ */
5
9
  type ErrorLike = Error & {
10
+ /** Quark of the error domain the code belongs to. */
6
11
  domain: number;
12
+ /** Error code, meaningful only within `ErrorLike.domain`. */
7
13
  code: number;
8
14
  };
9
15
 
@@ -12,6 +18,7 @@ type ErrorLike = Error & {
12
18
  * matches wrapped GLib errors belonging to a specific error domain.
13
19
  */
14
20
  type ErrorDomain<T extends Record<string, number>> = T & {
21
+ /** Backs `instanceof`, matching a wrapped GLib error whose domain is this one. */
15
22
  [Symbol.hasInstance]: (value: unknown) => value is ErrorLike;
16
23
  };
17
24
 
@@ -21,7 +28,7 @@ function checkError(error: Ref): void {
21
28
  }
22
29
 
23
30
  const gerror = wrapHandle(error.value as ExternalObject<Handle>, getWrapperClass(getErrorType())) as ErrorLike;
24
- const callSite = new Error("gtkx call site");
31
+ const callSite = new Error("GTKX call site");
25
32
  const callerFrames = (callSite.stack ?? "").split("\n").slice(2);
26
33
  gerror.stack = [`${gerror.name}: ${gerror.message}`, ...callerFrames].join("\n");
27
34
  throw gerror;
package/src/fn.ts CHANGED
@@ -1,6 +1,7 @@
1
- import type { Descriptor, Ref } from "@gtkx/native";
2
- import { type Arg, isCallerAllocatedArg, isInoutArg, isOutputArg, isRefArg } from "./arg.js";
3
- import { bind } from "./bind.js";
1
+ import type { CallDescriptor, Descriptor, ExternalObject, Ref } from "@gtkx/native";
2
+ import { call, bind as nativeBind } from "@gtkx/native";
3
+ import type { RefSeeds } from "./vfunc-seeds.js";
4
+ import { type Arg, isCallerAllocatedArg, isOutputArg, isRefArg, requiresInputArg } from "./arg.js";
4
5
  import { wrapCallbackValue } from "./callback.js";
5
6
  import { boxedT, refT } from "./descriptors.js";
6
7
  import { checkError } from "./error.js";
@@ -9,24 +10,37 @@ import { fromNative } from "./native-value.js";
9
10
  import { getHandle } from "./registry.js";
10
11
  import { packTupleResult } from "./tuple.js";
11
12
 
13
+ /** The signature a native function is bound against. */
12
14
  type FnSpec = {
15
+ /** The C arguments in declaration order, including the ones the callee writes into. */
13
16
  args: Arg[];
17
+ /** Descriptor for the C return value, packed first when output arguments are also returned. */
14
18
  returns: Descriptor;
15
- throws?: boolean;
19
+ /** The function takes a trailing `GError**`, whose contents are thrown as an error on return. */
20
+ canThrow?: boolean;
21
+ /**
22
+ * How many of `args` precede the callee's ellipsis, marking it variadic. Omitting it binds a
23
+ * fixed-arity call, which passes the wrong argument classes to a variadic callee on some
24
+ * architectures.
25
+ */
26
+ fixedArgCount?: number;
16
27
  };
17
28
 
18
29
  type ArgSpec = {
19
30
  arg: Arg;
31
+ index: number;
20
32
  isRef: boolean;
21
33
  isCallerAllocated: boolean;
22
- consumesInput: boolean;
34
+ requiresInput: boolean;
23
35
  inputIndex: number;
24
36
  isOutParam: boolean;
25
37
  };
26
38
 
39
+ const NO_OUT_PARAMS: unknown[] = [];
40
+
27
41
  const buildNativeArgTypes = (args: Arg[], canThrow: boolean): Descriptor[] => {
28
42
  const nativeArgTypes = args.map((argSpec) =>
29
- argSpec.direction !== undefined && argSpec.callerAllocated !== true ? refT(argSpec.type) : argSpec.type,
43
+ argSpec.direction !== undefined && argSpec.isCallerAllocated !== true ? refT(argSpec.type) : argSpec.type,
30
44
  );
31
45
 
32
46
  if (canThrow) {
@@ -41,17 +55,18 @@ const buildNativeArgTypes = (args: Arg[], canThrow: boolean): Descriptor[] => {
41
55
  const buildArgSpecs = (args: Arg[]): ArgSpec[] => {
42
56
  let inputCursor = 0;
43
57
 
44
- return args.map((arg) => {
58
+ return args.map((arg, index) => {
45
59
  const isRef = isRefArg(arg);
46
- const isConsumesInput = !isRef || isInoutArg(arg);
47
- const isOutParam = isOutputArg(arg) && arg.consumed !== true;
60
+ const requiresInput = requiresInputArg(arg);
61
+ const isOutParam = isOutputArg(arg) && arg.isConsumed !== true;
48
62
 
49
63
  return {
50
64
  arg,
65
+ index,
51
66
  isRef,
52
67
  isCallerAllocated: isCallerAllocatedArg(arg),
53
- consumesInput: isConsumesInput,
54
- inputIndex: isConsumesInput ? inputCursor++ : -1,
68
+ requiresInput,
69
+ inputIndex: requiresInput ? inputCursor++ : -1,
55
70
  isOutParam,
56
71
  };
57
72
  });
@@ -63,19 +78,19 @@ const resolveCallerAllocated = (inputs: unknown[], inputIndex: number): unknown
63
78
  return wrapper == null ? wrapper : getHandle(wrapper);
64
79
  };
65
80
 
66
- const buildRefValue = (isInputConsumed: boolean, inputs: unknown[], inputIndex: number): Ref => ({
67
- value: isInputConsumed ? inputs[inputIndex] : null,
81
+ const buildRefValue = (spec: ArgSpec, inputs: unknown[], seeds: RefSeeds | undefined): Ref => ({
82
+ value: spec.requiresInput ? inputs[spec.inputIndex] : (seeds?.get(spec.index) ?? null),
68
83
  });
69
84
 
70
- const buildNativeValue = (spec: ArgSpec, inputs: unknown[]): unknown => {
71
- const { arg, isRef, isCallerAllocated, consumesInput, inputIndex } = spec;
85
+ const buildNativeValue = (spec: ArgSpec, inputs: unknown[], seeds: RefSeeds | undefined): unknown => {
86
+ const { arg, isRef, isCallerAllocated, inputIndex } = spec;
72
87
 
73
88
  if (isCallerAllocated) {
74
89
  return resolveCallerAllocated(inputs, inputIndex);
75
90
  }
76
91
 
77
92
  if (isRef) {
78
- return buildRefValue(consumesInput, inputs, inputIndex);
93
+ return buildRefValue(spec, inputs, seeds);
79
94
  }
80
95
 
81
96
  if (arg.type.kind === "callback") {
@@ -85,44 +100,79 @@ const buildNativeValue = (spec: ArgSpec, inputs: unknown[]): unknown => {
85
100
  return inputs[inputIndex];
86
101
  };
87
102
 
88
- const buildNativeValues = (plans: ArgSpec[], inputs: unknown[]): unknown[] =>
89
- plans.map((plan) => buildNativeValue(plan, inputs));
103
+ const buildNativeValues = (plans: ArgSpec[], inputs: unknown[], seeds: RefSeeds | undefined): unknown[] =>
104
+ plans.map((plan) => buildNativeValue(plan, inputs, seeds));
105
+
106
+ const readOutParams = (outPlans: ArgSpec[], inputs: unknown[], nativeValues: unknown[]): unknown[] => {
107
+ if (outPlans.length === 0) {
108
+ return NO_OUT_PARAMS;
109
+ }
90
110
 
91
- const readOutParams = (plans: ArgSpec[], inputs: unknown[], nativeValues: unknown[]): unknown[] => {
92
- const outParams: unknown[] = [];
111
+ return Array.from(outPlans, (plan) =>
112
+ plan.isCallerAllocated
113
+ ? inputs[plan.inputIndex]
114
+ : fromNative(plan.arg.type, (nativeValues[plan.index] as Ref).value));
115
+ };
93
116
 
94
- for (const [index, { arg, isCallerAllocated, inputIndex, isOutParam }] of plans.entries()) {
95
- if (!isOutParam) {
96
- continue;
97
- }
117
+ const isPassThroughPlan = (plan: ArgSpec, index: number): boolean =>
118
+ plan.inputIndex === index &&
119
+ !plan.isRef &&
120
+ !plan.isCallerAllocated &&
121
+ plan.arg.type.kind !== "callback";
98
122
 
99
- outParams.push(
100
- isCallerAllocated ? inputs[inputIndex] : fromNative(arg.type, (nativeValues[index] as Ref).value),
101
- );
123
+ const resizeInputs = (inputs: unknown[], argCount: number): unknown[] => {
124
+ while (inputs.length < argCount) {
125
+ inputs.push(undefined);
102
126
  }
103
127
 
104
- return outParams;
128
+ if (inputs.length > argCount) {
129
+ inputs.length = argCount;
130
+ }
131
+
132
+ return inputs;
105
133
  };
106
134
 
107
- function fn(sharedLibrary: string, symbol: string, spec: FnSpec): (...inputs: unknown[]) => unknown {
108
- const { args, returns: returnDescriptor, throws = false } = spec;
109
- const nativeArgTypes = buildNativeArgTypes(args, throws);
110
- const nativeFn = bind(sharedLibrary, symbol, nativeArgTypes, returnDescriptor);
135
+ const directCallable = (
136
+ descriptor: ExternalObject<CallDescriptor>,
137
+ returnDescriptor: Descriptor,
138
+ argCount: number,
139
+ ): ((...inputs: unknown[]) => unknown) => {
140
+ if (returnDescriptor.kind === "void") {
141
+ return (...inputs) => {
142
+ call(descriptor, resizeInputs(inputs, argCount));
143
+ };
144
+ }
145
+
146
+ return (...inputs) => fromNative(returnDescriptor, call(descriptor, resizeInputs(inputs, argCount)));
147
+ };
148
+
149
+ function fromNativeCallable(
150
+ descriptor: ExternalObject<CallDescriptor>,
151
+ spec: FnSpec,
152
+ getRefSeeds?: () => RefSeeds | undefined,
153
+ ): (...inputs: unknown[]) => unknown {
154
+ const { args, returns: returnDescriptor, canThrow = false } = spec;
111
155
  const hasPrimary = returnDescriptor.kind !== "void";
112
156
  const plans = buildArgSpecs(args);
157
+ const outPlans = plans.filter((plan) => plan.isOutParam);
158
+ const arePassThrough = plans.every((plan, index) => isPassThroughPlan(plan, index));
159
+
160
+ if (!canThrow && arePassThrough) {
161
+ return directCallable(descriptor, returnDescriptor, plans.length);
162
+ }
113
163
 
114
164
  const shape = (inputs: unknown[], nativeValues: unknown[], nativeResult: unknown): unknown => {
115
165
  const primary = hasPrimary ? fromNative(returnDescriptor, nativeResult) : undefined;
116
166
 
117
- return packTupleResult(readOutParams(plans, inputs, nativeValues), primary, hasPrimary);
167
+ return packTupleResult(readOutParams(outPlans, inputs, nativeValues), primary, hasPrimary);
118
168
  };
119
169
 
120
- if (throws) {
170
+ if (canThrow) {
121
171
  return (...inputs) => {
122
- const nativeValues = buildNativeValues(plans, inputs);
172
+ const nativeValues = buildNativeValues(plans, inputs, getRefSeeds?.());
123
173
  const errorRef: Ref = { value: null };
124
174
  nativeValues.push(errorRef);
125
- const nativeResult = nativeFn(...nativeValues);
175
+ const nativeResult = call(descriptor, nativeValues);
126
176
  checkError(errorRef);
127
177
 
128
178
  return shape(inputs, nativeValues, nativeResult);
@@ -130,10 +180,25 @@ function fn(sharedLibrary: string, symbol: string, spec: FnSpec): (...inputs: un
130
180
  }
131
181
 
132
182
  return (...inputs) => {
133
- const nativeValues = buildNativeValues(plans, inputs);
183
+ const nativeValues = buildNativeValues(plans, inputs, getRefSeeds?.());
134
184
 
135
- return shape(inputs, nativeValues, nativeFn(...nativeValues));
185
+ return shape(inputs, nativeValues, call(descriptor, nativeValues));
136
186
  };
137
187
  }
138
188
 
139
- export { fn };
189
+ /**
190
+ * Binds a symbol in a shared library to a callable that marshals its inputs and packs output
191
+ * arguments into the result. When the spec sets `canThrow`, the reported `GError` is thrown.
192
+ *
193
+ * @param sharedLibrary Shared library the symbol is looked up in.
194
+ * @param symbol Name of the C symbol to bind.
195
+ * @param spec Argument and return descriptors the call is marshalled through.
196
+ */
197
+ function fn(sharedLibrary: string, symbol: string, spec: FnSpec): (...inputs: unknown[]) => unknown {
198
+ const nativeArgTypes = buildNativeArgTypes(spec.args, spec.canThrow ?? false);
199
+ const descriptor = nativeBind(sharedLibrary, symbol, nativeArgTypes, spec.returns, spec.fixedArgCount);
200
+
201
+ return fromNativeCallable(descriptor, spec);
202
+ }
203
+
204
+ export { buildNativeArgTypes, fn, fromNativeCallable };