@effindomv2/fui-as 0.1.1 → 0.1.3

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.
@@ -21,6 +21,11 @@ function relativeImport(fromFile: string, targetFile: string): string {
21
21
  return toPosix(relative);
22
22
  }
23
23
 
24
+ function sourcePathForHeader(sourceModulePath: string): string {
25
+ const relative = path.relative(process.cwd(), sourceModulePath);
26
+ return toPosix(relative.startsWith(".") ? relative : `./${relative}`);
27
+ }
28
+
24
29
  function asTypeName(type: HostServiceTypeName): string {
25
30
  switch (type) {
26
31
  case "string":
@@ -29,28 +34,71 @@ function asTypeName(type: HostServiceTypeName): string {
29
34
  return "bool";
30
35
  case "i32":
31
36
  return "i32";
37
+ case "u32":
38
+ return "u32";
39
+ case "i64":
40
+ return "i64";
41
+ case "u64":
42
+ return "u64";
32
43
  case "f64":
33
44
  return "f64";
45
+ case "bytes":
46
+ return "Uint8Array";
47
+ case "i32_array":
48
+ return "Int32Array";
49
+ case "u32_array":
50
+ return "Uint32Array";
51
+ case "i64_array":
52
+ return "Int64Array";
53
+ case "u64_array":
54
+ return "Uint64Array";
55
+ case "f64_array":
56
+ return "Float64Array";
34
57
  case "void":
35
58
  return "void";
36
59
  }
37
60
  }
38
61
 
39
- function emitExternalSignature(importName: string, args: readonly HostServiceTypeName[], returns: HostServiceTypeName): string {
62
+ function isPointerLengthType(type: HostServiceTypeName): boolean {
63
+ return type === "string" ||
64
+ type === "bytes" ||
65
+ type === "i32_array" ||
66
+ type === "u32_array" ||
67
+ type === "i64_array" ||
68
+ type === "u64_array" ||
69
+ type === "f64_array";
70
+ }
71
+
72
+ function returnsBufferType(type: HostServiceTypeName): boolean {
73
+ return type === "string" ||
74
+ type === "bytes" ||
75
+ type === "i32_array" ||
76
+ type === "u32_array" ||
77
+ type === "i64_array" ||
78
+ type === "u64_array" ||
79
+ type === "f64_array";
80
+ }
81
+
82
+ function emitExternalSignature(
83
+ importName: string,
84
+ args: readonly HostServiceTypeName[],
85
+ returns: HostServiceTypeName,
86
+ moduleName: string,
87
+ ): string {
40
88
  const signatureParts: Array<string> = [];
41
89
  args.forEach((type, index) => {
42
- if (type === "string") {
90
+ if (isPointerLengthType(type)) {
43
91
  signatureParts.push(`arg${String(index)}Ptr: usize`, `arg${String(index)}Len: u32`);
44
92
  return;
45
93
  }
46
94
  signatureParts.push(`arg${String(index)}: ${asTypeName(type)}`);
47
95
  });
48
- if (returns === "string") {
96
+ if (returnsBufferType(returns)) {
49
97
  signatureParts.push("resultPtr: usize", "resultCap: u32");
50
98
  }
51
- const returnType = returns === "string" ? "u32" : asTypeName(returns);
99
+ const returnType = returnsBufferType(returns) ? "u32" : asTypeName(returns);
52
100
  return [
53
- `@external("fui_host_service", "${importName}")`,
101
+ `@external("${moduleName}", "${importName}")`,
54
102
  `declare function __host_${importName}(${signatureParts.join(", ")}): ${returnType};`,
55
103
  ].join("\n");
56
104
  }
@@ -61,6 +109,10 @@ function emitWrapper(importName: string, args: readonly HostServiceTypeName[], r
61
109
  args.forEach((type, index) => {
62
110
  if (type === "string") {
63
111
  lines.push(` const arg${String(index)}Bytes = Uint8Array.wrap(String.UTF8.encode(arg${String(index)}, false));`);
112
+ return;
113
+ }
114
+ if (type === "bytes" || type === "i32_array" || type === "u32_array" || type === "i64_array" || type === "u64_array" || type === "f64_array") {
115
+ lines.push(` const arg${String(index)}Bytes = arg${String(index)};`);
64
116
  }
65
117
  });
66
118
  const callArgs: Array<string> = [];
@@ -70,14 +122,38 @@ function emitWrapper(importName: string, args: readonly HostServiceTypeName[], r
70
122
  callArgs.push(`<u32>arg${String(index)}Bytes.length`);
71
123
  return;
72
124
  }
125
+ if (type === "bytes") {
126
+ callArgs.push(`arg${String(index)}Bytes.length > 0 ? arg${String(index)}Bytes.dataStart : 0`);
127
+ callArgs.push(`<u32>arg${String(index)}Bytes.length`);
128
+ return;
129
+ }
130
+ if (type === "i32_array" || type === "u32_array" || type === "i64_array" || type === "u64_array" || type === "f64_array") {
131
+ callArgs.push(`arg${String(index)}Bytes.length > 0 ? arg${String(index)}Bytes.dataStart : 0`);
132
+ callArgs.push(`<u32>arg${String(index)}Bytes.length`);
133
+ return;
134
+ }
73
135
  callArgs.push(`arg${String(index)}`);
74
136
  });
75
- if (returns === "string") {
137
+ if (returnsBufferType(returns)) {
76
138
  lines.push(" const resultPtr = hostServiceResultBufferPtr();");
77
139
  lines.push(" const resultCap = hostServiceResultBufferSize();");
78
140
  callArgs.push("resultPtr", "resultCap");
79
141
  lines.push(` const resultLen = __host_${importName}(${callArgs.join(", ")});`);
80
- lines.push(` return decodeHostServiceStringResult(resultPtr, resultLen, "${importName}");`);
142
+ if (returns === "string") {
143
+ lines.push(` return decodeHostServiceStringResult(resultPtr, resultLen, "${importName}");`);
144
+ } else if (returns === "bytes") {
145
+ lines.push(` return decodeHostServiceBytesResult(resultPtr, resultLen, "${importName}");`);
146
+ } else if (returns === "i32_array") {
147
+ lines.push(` return decodeHostServiceI32ArrayResult(resultPtr, resultLen, "${importName}");`);
148
+ } else if (returns === "u32_array") {
149
+ lines.push(` return decodeHostServiceU32ArrayResult(resultPtr, resultLen, "${importName}");`);
150
+ } else if (returns === "i64_array") {
151
+ lines.push(` return decodeHostServiceI64ArrayResult(resultPtr, resultLen, "${importName}");`);
152
+ } else if (returns === "u64_array") {
153
+ lines.push(` return decodeHostServiceU64ArrayResult(resultPtr, resultLen, "${importName}");`);
154
+ } else {
155
+ lines.push(` return decodeHostServiceF64ArrayResult(resultPtr, resultLen, "${importName}");`);
156
+ }
81
157
  } else if (returns === "void") {
82
158
  lines.push(` __host_${importName}(${callArgs.join(", ")});`);
83
159
  } else {
@@ -118,19 +194,51 @@ function emitBindingsFile(
118
194
  exportName: string,
119
195
  outputPath: string,
120
196
  methods: ReturnType<typeof listHostServiceMethods>,
197
+ primitivesImportOverride: string | undefined,
198
+ moduleName: string,
121
199
  ): string {
122
- const runtimeImport = relativeImport(outputPath, path.resolve(PACKAGE_DIR, "src/FuiPrimitives.ts"));
200
+ const runtimeImport = primitivesImportOverride ?? relativeImport(outputPath, path.resolve(PACKAGE_DIR, "src/FuiPrimitives.ts"));
123
201
  const blocks: Array<string> = [
124
- `// Generated by scripts/generate-host-services.ts from ${toPosix(sourceModulePath)}#${exportName}.`,
202
+ `// Generated by scripts/generate-host-services.ts from ${sourcePathForHeader(sourceModulePath)}#${exportName}.`,
125
203
  ];
126
- if (methods.some((method) => method.returns === "string")) {
127
- blocks.push(`import { decodeHostServiceStringResult, hostServiceResultBufferPtr, hostServiceResultBufferSize } from "${runtimeImport}";`);
204
+ if (methods.some((method) => returnsBufferType(method.returns))) {
205
+ const helpers = [
206
+ "hostServiceResultBufferPtr",
207
+ "hostServiceResultBufferSize",
208
+ ...new Set(
209
+ methods
210
+ .map((method) => method.returns)
211
+ .filter((type) => returnsBufferType(type))
212
+ .map((type) => {
213
+ if (type === "string") {
214
+ return "decodeHostServiceStringResult";
215
+ }
216
+ if (type === "bytes") {
217
+ return "decodeHostServiceBytesResult";
218
+ }
219
+ if (type === "i32_array") {
220
+ return "decodeHostServiceI32ArrayResult";
221
+ }
222
+ if (type === "u32_array") {
223
+ return "decodeHostServiceU32ArrayResult";
224
+ }
225
+ if (type === "i64_array") {
226
+ return "decodeHostServiceI64ArrayResult";
227
+ }
228
+ if (type === "u64_array") {
229
+ return "decodeHostServiceU64ArrayResult";
230
+ }
231
+ return "decodeHostServiceF64ArrayResult";
232
+ }),
233
+ ),
234
+ ];
235
+ blocks.push(`import { ${helpers.join(", ")} } from "${runtimeImport}";`);
128
236
  blocks.push("");
129
237
  } else {
130
238
  blocks.push("");
131
239
  }
132
240
  methods.forEach((method, index) => {
133
- blocks.push(emitExternalSignature(method.importName, method.args, method.returns));
241
+ blocks.push(emitExternalSignature(method.importName, method.args, method.returns, moduleName));
134
242
  blocks.push("");
135
243
  blocks.push(emitWrapper(method.importName, method.args, method.returns));
136
244
  if (index + 1 < methods.length) {
@@ -141,15 +249,24 @@ function emitBindingsFile(
141
249
  }
142
250
 
143
251
  async function main(): Promise<void> {
144
- const [moduleArg, exportName, outputArg] = process.argv.slice(2);
252
+ const [moduleArg, exportName, outputArg, primitivesImportArg, hostModuleArg] = process.argv.slice(2);
145
253
  if (moduleArg === undefined || exportName === undefined || outputArg === undefined) {
146
- throw new Error("Usage: generate-host-services <module-path> <export-name> <output-path>");
254
+ throw new Error(
255
+ "Usage: generate-host-services <module-path> <export-name> <output-path> [primitives-import] [host-import-module]",
256
+ );
147
257
  }
148
258
  const modulePath = path.resolve(process.cwd(), moduleArg);
149
259
  const outputPath = path.resolve(process.cwd(), outputArg);
150
260
  const registry = await loadHostServices(modulePath, exportName);
151
261
  const methods = listHostServiceMethods(registry as never);
152
- const content = emitBindingsFile(modulePath, exportName, outputPath, methods);
262
+ const content = emitBindingsFile(
263
+ modulePath,
264
+ exportName,
265
+ outputPath,
266
+ methods,
267
+ primitivesImportArg,
268
+ hostModuleArg ?? "fui_host_service",
269
+ );
153
270
  await fs.mkdir(path.dirname(outputPath), { recursive: true });
154
271
  await fs.writeFile(outputPath, content, "utf8");
155
272
  }
@@ -12,4 +12,14 @@ export {
12
12
  } from "./core/BoundCallback";
13
13
  export { bind0, bind1, bind2, bindResult0, bindResult1 } from "./core/bind";
14
14
  export { clearCurrentSelection, tryGetBounds } from "./bindings/ui";
15
- export { decodeHostServiceStringResult, hostServiceResultBufferPtr, hostServiceResultBufferSize } from "./host-services/runtime";
15
+ export {
16
+ decodeHostServiceBytesResult,
17
+ decodeHostServiceF64ArrayResult,
18
+ decodeHostServiceI64ArrayResult,
19
+ decodeHostServiceI32ArrayResult,
20
+ decodeHostServiceStringResult,
21
+ decodeHostServiceU64ArrayResult,
22
+ decodeHostServiceU32ArrayResult,
23
+ hostServiceResultBufferPtr,
24
+ hostServiceResultBufferSize,
25
+ } from "./host-services/runtime";
package/src/core/ffi.ts CHANGED
@@ -1,3 +1,11 @@
1
+ export {
2
+ fui_get_accent_color,
3
+ fui_get_platform_family,
4
+ fui_is_coarse_pointer,
5
+ fui_is_dark_mode,
6
+ fui_now_ms,
7
+ } from "./generated/FrameworkHostServices";
8
+
1
9
  export enum HandleValue {
2
10
  Invalid = 0,
3
11
  }
@@ -569,24 +577,9 @@ export declare function fui_start_timer(timerId: u32, delayMs: i32): void;
569
577
  @external("fui_host", "fui_cancel_timer")
570
578
  export declare function fui_cancel_timer(timerId: u32): void;
571
579
 
572
- @external("fui_host", "fui_now_ms")
573
- export declare function fui_now_ms(): f64;
574
-
575
580
  @external("fui_host", "fui_set_cursor")
576
581
  export declare function fui_set_cursor(style: u32): void;
577
582
 
578
- @external("fui_host", "fui_is_dark_mode")
579
- export declare function fui_is_dark_mode(): bool;
580
-
581
- @external("fui_host", "fui_get_accent_color")
582
- export declare function fui_get_accent_color(): u32;
583
-
584
- @external("fui_host", "fui_get_platform_family")
585
- export declare function fui_get_platform_family(): u32;
586
-
587
- @external("fui_host", "fui_is_coarse_pointer")
588
- export declare function fui_is_coarse_pointer(): bool;
589
-
590
583
  @external("fui_host", "fui_show_url_preview")
591
584
  export declare function fui_show_url_preview(ptr: usize, len: u32): void;
592
585
 
@@ -0,0 +1,36 @@
1
+ // Generated by scripts/generate-host-services.ts from ./scripts/framework-host-services.ts#frameworkHostServices.
2
+
3
+ @external("fui_host", "fui_get_accent_color")
4
+ declare function __host_fui_get_accent_color(): u32;
5
+
6
+ export function fui_get_accent_color(): u32 {
7
+ return __host_fui_get_accent_color();
8
+ }
9
+
10
+ @external("fui_host", "fui_get_platform_family")
11
+ declare function __host_fui_get_platform_family(): u32;
12
+
13
+ export function fui_get_platform_family(): u32 {
14
+ return __host_fui_get_platform_family();
15
+ }
16
+
17
+ @external("fui_host", "fui_is_coarse_pointer")
18
+ declare function __host_fui_is_coarse_pointer(): bool;
19
+
20
+ export function fui_is_coarse_pointer(): bool {
21
+ return __host_fui_is_coarse_pointer();
22
+ }
23
+
24
+ @external("fui_host", "fui_is_dark_mode")
25
+ declare function __host_fui_is_dark_mode(): bool;
26
+
27
+ export function fui_is_dark_mode(): bool {
28
+ return __host_fui_is_dark_mode();
29
+ }
30
+
31
+ @external("fui_host", "fui_now_ms")
32
+ declare function __host_fui_now_ms(): f64;
33
+
34
+ export function fui_now_ms(): f64 {
35
+ return __host_fui_now_ms();
36
+ }
@@ -8,7 +8,7 @@ export function hostServiceResultBufferSize(): u32 {
8
8
  return __fui_text_buffer_size();
9
9
  }
10
10
 
11
- export function decodeHostServiceStringResult(resultPtr: usize, resultLen: u32, importName: string): string {
11
+ function assertResultByteLength(resultLen: u32, importName: string): void {
12
12
  const capacity = __fui_text_buffer_size();
13
13
  if (resultLen > capacity) {
14
14
  throw new Error(
@@ -21,5 +21,78 @@ export function decodeHostServiceStringResult(resultPtr: usize, resultLen: u32,
21
21
  ".",
22
22
  );
23
23
  }
24
+ }
25
+
26
+ export function decodeHostServiceStringResult(resultPtr: usize, resultLen: u32, importName: string): string {
27
+ assertResultByteLength(resultLen, importName);
24
28
  return resultLen == 0 ? "" : String.UTF8.decodeUnsafe(resultPtr, <usize>resultLen, false);
25
29
  }
30
+
31
+ export function decodeHostServiceBytesResult(resultPtr: usize, resultLen: u32, importName: string): Uint8Array {
32
+ assertResultByteLength(resultLen, importName);
33
+ const bytes = new Uint8Array(<i32>resultLen);
34
+ if (resultLen > 0) {
35
+ memory.copy(bytes.dataStart, resultPtr, <usize>resultLen);
36
+ }
37
+ return bytes;
38
+ }
39
+
40
+ export function decodeHostServiceI32ArrayResult(resultPtr: usize, resultLen: u32, importName: string): Int32Array {
41
+ assertResultByteLength(resultLen, importName);
42
+ if ((resultLen & 3) != 0) {
43
+ throw new Error("Host service " + importName + " returned misaligned Int32Array byte length.");
44
+ }
45
+ const values = new Int32Array(<i32>(resultLen >> 2));
46
+ if (resultLen > 0) {
47
+ memory.copy(values.dataStart, resultPtr, <usize>resultLen);
48
+ }
49
+ return values;
50
+ }
51
+
52
+ export function decodeHostServiceU32ArrayResult(resultPtr: usize, resultLen: u32, importName: string): Uint32Array {
53
+ assertResultByteLength(resultLen, importName);
54
+ if ((resultLen & 3) != 0) {
55
+ throw new Error("Host service " + importName + " returned misaligned Uint32Array byte length.");
56
+ }
57
+ const values = new Uint32Array(<i32>(resultLen >> 2));
58
+ if (resultLen > 0) {
59
+ memory.copy(values.dataStart, resultPtr, <usize>resultLen);
60
+ }
61
+ return values;
62
+ }
63
+
64
+ export function decodeHostServiceI64ArrayResult(resultPtr: usize, resultLen: u32, importName: string): Int64Array {
65
+ assertResultByteLength(resultLen, importName);
66
+ if ((resultLen & 7) != 0) {
67
+ throw new Error("Host service " + importName + " returned misaligned Int64Array byte length.");
68
+ }
69
+ const values = new Int64Array(<i32>(resultLen >> 3));
70
+ if (resultLen > 0) {
71
+ memory.copy(values.dataStart, resultPtr, <usize>resultLen);
72
+ }
73
+ return values;
74
+ }
75
+
76
+ export function decodeHostServiceU64ArrayResult(resultPtr: usize, resultLen: u32, importName: string): Uint64Array {
77
+ assertResultByteLength(resultLen, importName);
78
+ if ((resultLen & 7) != 0) {
79
+ throw new Error("Host service " + importName + " returned misaligned Uint64Array byte length.");
80
+ }
81
+ const values = new Uint64Array(<i32>(resultLen >> 3));
82
+ if (resultLen > 0) {
83
+ memory.copy(values.dataStart, resultPtr, <usize>resultLen);
84
+ }
85
+ return values;
86
+ }
87
+
88
+ export function decodeHostServiceF64ArrayResult(resultPtr: usize, resultLen: u32, importName: string): Float64Array {
89
+ assertResultByteLength(resultLen, importName);
90
+ if ((resultLen & 7) != 0) {
91
+ throw new Error("Host service " + importName + " returned misaligned Float64Array byte length.");
92
+ }
93
+ const values = new Float64Array(<i32>(resultLen >> 3));
94
+ if (resultLen > 0) {
95
+ memory.copy(values.dataStart, resultPtr, <usize>resultLen);
96
+ }
97
+ return values;
98
+ }