@mks2508/hyperdiff-ffi-bun 0.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.
- package/dist/ffi.d.ts +8 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +307 -0
- package/dist/index.js.map +1 -0
- package/dist/libhyperdiff.dylib +0 -0
- package/dist/types/ffi.types.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/platform.d.ts +18 -0
- package/package.json +33 -0
package/dist/ffi.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type IFFIAdapter } from '@mks2508/hyperdiff-utils';
|
|
2
|
+
/**
|
|
3
|
+
* Create a Bun FFI adapter for the Hyperdiff engine.
|
|
4
|
+
*
|
|
5
|
+
* @param libraryPath - Optional explicit path to libhyperdiff.dylib
|
|
6
|
+
* @returns IFFIAdapter implementation using bun:ffi
|
|
7
|
+
*/
|
|
8
|
+
export declare function createBunAdapter(libraryPath?: string): IFFIAdapter;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { FFIType, dlopen, ptr, read } from "bun:ffi";
|
|
2
|
+
import { createLogger } from "@mks2508/hyperdiff-utils";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
//#region src/utils/platform.ts
|
|
6
|
+
/**
|
|
7
|
+
* Get the shared library file extension for the current platform.
|
|
8
|
+
* @returns 'dylib' on macOS, 'so' on Linux, 'dll' on Windows
|
|
9
|
+
*/
|
|
10
|
+
function getDylibExtension() {
|
|
11
|
+
switch (process.platform) {
|
|
12
|
+
case "darwin": return "dylib";
|
|
13
|
+
case "win32": return "dll";
|
|
14
|
+
default: return "so";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the path to libhyperdiff shared library.
|
|
19
|
+
*
|
|
20
|
+
* Search order:
|
|
21
|
+
* 1. HYPERDIFF_LIB_PATH env var (exact path)
|
|
22
|
+
* 2. Relative to this package: ../../zig/zig-out/lib/ (monorepo dev)
|
|
23
|
+
* 3. /usr/local/lib/ (system install)
|
|
24
|
+
*
|
|
25
|
+
* @param customPath - Optional explicit path override
|
|
26
|
+
* @returns Resolved absolute path to the shared library
|
|
27
|
+
* @throws Error if library not found in any search path
|
|
28
|
+
*/
|
|
29
|
+
function resolveDylibPath(customPath) {
|
|
30
|
+
const libName = `libhyperdiff.${getDylibExtension()}`;
|
|
31
|
+
if (customPath) {
|
|
32
|
+
const resolved = resolve(customPath);
|
|
33
|
+
if (existsSync(resolved)) return resolved;
|
|
34
|
+
throw new Error(`Hyperdiff library not found at explicit path: ${resolved}`);
|
|
35
|
+
}
|
|
36
|
+
const envPath = process.env["HYPERDIFF_LIB_PATH"];
|
|
37
|
+
if (envPath) {
|
|
38
|
+
const resolved = resolve(envPath);
|
|
39
|
+
if (existsSync(resolved)) return resolved;
|
|
40
|
+
}
|
|
41
|
+
const monorepoPath = join(import.meta.dir, "..", "..", "..", "zig", "zig-out", "lib", libName);
|
|
42
|
+
if (existsSync(monorepoPath)) return monorepoPath;
|
|
43
|
+
const systemPath = join("/usr/local/lib", libName);
|
|
44
|
+
if (existsSync(systemPath)) return systemPath;
|
|
45
|
+
throw new Error(`Hyperdiff library (${libName}) not found. Searched:\n - HYPERDIFF_LIB_PATH env var\n - ${monorepoPath} (monorepo)\n - ${systemPath} (system)\nRun 'zig build -Doptimize=ReleaseFast' in core/zig/ first.`);
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/ffi.ts
|
|
49
|
+
/**
|
|
50
|
+
* Bun FFI bindings for the Hyperdiff Zig engine.
|
|
51
|
+
*
|
|
52
|
+
* Uses bun:ffi dlopen to load libhyperdiff and expose typed wrappers.
|
|
53
|
+
* Handles DiffResult/CEdit struct reading from raw pointers.
|
|
54
|
+
*/
|
|
55
|
+
const log = createLogger("BunFFI");
|
|
56
|
+
/** CEdit struct size: u8 + pad[3] + u32×4 = 20 bytes. */
|
|
57
|
+
const CEDIT_BYTE_SIZE = 20;
|
|
58
|
+
/** CHunk struct size: 15×u32 + 2×u8 + 2×pad = 64 bytes. */
|
|
59
|
+
const CHUNK_BYTE_SIZE = 64;
|
|
60
|
+
/** CContent struct size: u8 + pad[3] + u32×4 = 20 bytes. */
|
|
61
|
+
const CCONTENT_BYTE_SIZE = 20;
|
|
62
|
+
/** FFI symbol definitions matching exports.zig C-ABI functions. */
|
|
63
|
+
const SYMBOLS = {
|
|
64
|
+
hyperdiff_compute: {
|
|
65
|
+
args: [
|
|
66
|
+
FFIType.ptr,
|
|
67
|
+
FFIType.u64,
|
|
68
|
+
FFIType.ptr,
|
|
69
|
+
FFIType.u64,
|
|
70
|
+
FFIType.u8
|
|
71
|
+
],
|
|
72
|
+
returns: FFIType.ptr
|
|
73
|
+
},
|
|
74
|
+
hyperdiff_free: {
|
|
75
|
+
args: [FFIType.ptr],
|
|
76
|
+
returns: FFIType.void
|
|
77
|
+
},
|
|
78
|
+
hyperdiff_ping: {
|
|
79
|
+
args: [],
|
|
80
|
+
returns: FFIType.u32
|
|
81
|
+
},
|
|
82
|
+
hyperdiff_cedit_size: {
|
|
83
|
+
args: [],
|
|
84
|
+
returns: FFIType.u64
|
|
85
|
+
},
|
|
86
|
+
hyperdiff_abi_version: {
|
|
87
|
+
args: [],
|
|
88
|
+
returns: FFIType.u32
|
|
89
|
+
},
|
|
90
|
+
hyperdiff_metadata: {
|
|
91
|
+
args: [
|
|
92
|
+
FFIType.ptr,
|
|
93
|
+
FFIType.u64,
|
|
94
|
+
FFIType.ptr,
|
|
95
|
+
FFIType.u64,
|
|
96
|
+
FFIType.u8,
|
|
97
|
+
FFIType.u32,
|
|
98
|
+
FFIType.u8,
|
|
99
|
+
FFIType.ptr
|
|
100
|
+
],
|
|
101
|
+
returns: FFIType.void
|
|
102
|
+
},
|
|
103
|
+
hyperdiff_metadata_free_raw: {
|
|
104
|
+
args: [
|
|
105
|
+
FFIType.ptr,
|
|
106
|
+
FFIType.u32,
|
|
107
|
+
FFIType.ptr,
|
|
108
|
+
FFIType.u32
|
|
109
|
+
],
|
|
110
|
+
returns: FFIType.void
|
|
111
|
+
},
|
|
112
|
+
hyperdiff_patch: {
|
|
113
|
+
args: [
|
|
114
|
+
FFIType.ptr,
|
|
115
|
+
FFIType.u64,
|
|
116
|
+
FFIType.ptr,
|
|
117
|
+
FFIType.u64,
|
|
118
|
+
FFIType.u8,
|
|
119
|
+
FFIType.u32,
|
|
120
|
+
FFIType.ptr,
|
|
121
|
+
FFIType.u64
|
|
122
|
+
],
|
|
123
|
+
returns: FFIType.u64
|
|
124
|
+
},
|
|
125
|
+
hyperdiff_inline_diff: {
|
|
126
|
+
args: [
|
|
127
|
+
FFIType.ptr,
|
|
128
|
+
FFIType.u64,
|
|
129
|
+
FFIType.ptr,
|
|
130
|
+
FFIType.u64,
|
|
131
|
+
FFIType.u8
|
|
132
|
+
],
|
|
133
|
+
returns: FFIType.ptr
|
|
134
|
+
},
|
|
135
|
+
hyperdiff_inline_free: {
|
|
136
|
+
args: [FFIType.ptr],
|
|
137
|
+
returns: FFIType.void
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
function assertNonNull(value) {
|
|
141
|
+
if (value === null) throw new Error("Unexpected null pointer from FFI");
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Create a Bun FFI adapter for the Hyperdiff engine.
|
|
146
|
+
*
|
|
147
|
+
* @param libraryPath - Optional explicit path to libhyperdiff.dylib
|
|
148
|
+
* @returns IFFIAdapter implementation using bun:ffi
|
|
149
|
+
*/
|
|
150
|
+
function createBunAdapter(libraryPath) {
|
|
151
|
+
const dylibPath = resolveDylibPath(libraryPath);
|
|
152
|
+
log.info(`Loading library from ${dylibPath}`);
|
|
153
|
+
const { symbols } = dlopen(dylibPath, SYMBOLS);
|
|
154
|
+
return {
|
|
155
|
+
runtime: "ffi-bun",
|
|
156
|
+
compute(oldText, newText, algorithm) {
|
|
157
|
+
const oldBuf = Buffer.from(oldText);
|
|
158
|
+
const newBuf = Buffer.from(newText);
|
|
159
|
+
const resultPtr = assertNonNull(symbols.hyperdiff_compute(assertNonNull(ptr(oldBuf)), oldBuf.length, assertNonNull(ptr(newBuf)), newBuf.length, algorithm));
|
|
160
|
+
return {
|
|
161
|
+
editsPtr: Number(assertNonNull(read.ptr(resultPtr, 0))),
|
|
162
|
+
editCount: read.u32(resultPtr, 8),
|
|
163
|
+
errorCode: read.u32(resultPtr, 12)
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
free(resultPtr) {
|
|
167
|
+
symbols.hyperdiff_free(resultPtr);
|
|
168
|
+
},
|
|
169
|
+
ping() {
|
|
170
|
+
return symbols.hyperdiff_ping();
|
|
171
|
+
},
|
|
172
|
+
ceditSize() {
|
|
173
|
+
return Number(symbols.hyperdiff_cedit_size());
|
|
174
|
+
},
|
|
175
|
+
abiVersion() {
|
|
176
|
+
return symbols.hyperdiff_abi_version();
|
|
177
|
+
},
|
|
178
|
+
readEdits(editsPtr, editCount) {
|
|
179
|
+
if (editCount === 0) return [];
|
|
180
|
+
const edits = new Array(editCount);
|
|
181
|
+
for (let i = 0; i < editCount; i++) {
|
|
182
|
+
const offset = editsPtr + i * CEDIT_BYTE_SIZE;
|
|
183
|
+
edits[i] = {
|
|
184
|
+
tag: read.u8(offset, 0),
|
|
185
|
+
oldStart: read.u32(offset, 4),
|
|
186
|
+
oldEnd: read.u32(offset, 8),
|
|
187
|
+
newStart: read.u32(offset, 12),
|
|
188
|
+
newEnd: read.u32(offset, 16)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return edits;
|
|
192
|
+
},
|
|
193
|
+
metadata(oldText, newText, algorithm, contextLines, flags = 0) {
|
|
194
|
+
const oldBuf = oldText.length > 0 ? Buffer.from(oldText) : Buffer.alloc(1);
|
|
195
|
+
const newBuf = newText.length > 0 ? Buffer.from(newText) : Buffer.alloc(1);
|
|
196
|
+
const oldLen = Buffer.byteLength(oldText);
|
|
197
|
+
const newLen = Buffer.byteLength(newText);
|
|
198
|
+
const outBuf = Buffer.alloc(48);
|
|
199
|
+
symbols.hyperdiff_metadata(assertNonNull(ptr(oldBuf)), oldLen, assertNonNull(ptr(newBuf)), newLen, algorithm, contextLines, flags, assertNonNull(ptr(outBuf)));
|
|
200
|
+
const resultPtr = assertNonNull(ptr(outBuf));
|
|
201
|
+
return {
|
|
202
|
+
hunksPtr: Number(assertNonNull(read.ptr(resultPtr, 0))),
|
|
203
|
+
hunkCount: read.u32(resultPtr, 8),
|
|
204
|
+
contentsPtr: Number(assertNonNull(read.ptr(resultPtr, 16))),
|
|
205
|
+
contentCount: read.u32(resultPtr, 24),
|
|
206
|
+
splitLineCount: read.u32(resultPtr, 28),
|
|
207
|
+
unifiedLineCount: read.u32(resultPtr, 32),
|
|
208
|
+
oldLineCount: read.u32(resultPtr, 36),
|
|
209
|
+
newLineCount: read.u32(resultPtr, 40),
|
|
210
|
+
errorCode: read.u32(resultPtr, 44)
|
|
211
|
+
};
|
|
212
|
+
},
|
|
213
|
+
readHunks(hunksPtr, hunkCount) {
|
|
214
|
+
if (hunkCount === 0) return [];
|
|
215
|
+
const hunks = new Array(hunkCount);
|
|
216
|
+
for (let i = 0; i < hunkCount; i++) {
|
|
217
|
+
const offset = hunksPtr + i * CHUNK_BYTE_SIZE;
|
|
218
|
+
hunks[i] = {
|
|
219
|
+
collapsedBefore: read.u32(offset, 0),
|
|
220
|
+
additionStart: read.u32(offset, 4),
|
|
221
|
+
additionCount: read.u32(offset, 8),
|
|
222
|
+
additionLines: read.u32(offset, 12),
|
|
223
|
+
additionLineIndex: read.u32(offset, 16),
|
|
224
|
+
deletionStart: read.u32(offset, 20),
|
|
225
|
+
deletionCount: read.u32(offset, 24),
|
|
226
|
+
deletionLines: read.u32(offset, 28),
|
|
227
|
+
deletionLineIndex: read.u32(offset, 32),
|
|
228
|
+
splitLineStart: read.u32(offset, 36),
|
|
229
|
+
splitLineCount: read.u32(offset, 40),
|
|
230
|
+
unifiedLineStart: read.u32(offset, 44),
|
|
231
|
+
unifiedLineCount: read.u32(offset, 48),
|
|
232
|
+
contentOffset: read.u32(offset, 52),
|
|
233
|
+
contentCount: read.u32(offset, 56),
|
|
234
|
+
noEofcrAdditions: read.u8(offset, 60),
|
|
235
|
+
noEofcrDeletions: read.u8(offset, 61)
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
return hunks;
|
|
239
|
+
},
|
|
240
|
+
readContents(contentsPtr, contentCount) {
|
|
241
|
+
if (contentCount === 0) return [];
|
|
242
|
+
const contents = new Array(contentCount);
|
|
243
|
+
for (let i = 0; i < contentCount; i++) {
|
|
244
|
+
const offset = contentsPtr + i * CCONTENT_BYTE_SIZE;
|
|
245
|
+
contents[i] = {
|
|
246
|
+
tag: read.u8(offset, 0),
|
|
247
|
+
param1: read.u32(offset, 4),
|
|
248
|
+
param2: read.u32(offset, 8),
|
|
249
|
+
additionLineIndex: read.u32(offset, 12),
|
|
250
|
+
deletionLineIndex: read.u32(offset, 16)
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
return contents;
|
|
254
|
+
},
|
|
255
|
+
metadataFree(hunksPtr, hunkCount, contentsPtr, contentCount) {
|
|
256
|
+
symbols.hyperdiff_metadata_free_raw(hunksPtr, hunkCount, contentsPtr, contentCount);
|
|
257
|
+
},
|
|
258
|
+
patch(oldText, newText, algorithm, contextLines) {
|
|
259
|
+
const oldBuf = Buffer.from(oldText);
|
|
260
|
+
const newBuf = Buffer.from(newText);
|
|
261
|
+
let cap = Math.max(oldBuf.length + newBuf.length, 4096);
|
|
262
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
263
|
+
const outBuf = Buffer.alloc(cap);
|
|
264
|
+
const result = symbols.hyperdiff_patch(ptr(oldBuf), oldBuf.length, ptr(newBuf), newBuf.length, algorithm, contextLines, ptr(outBuf), cap);
|
|
265
|
+
const r = BigInt(result);
|
|
266
|
+
const bytesWritten = Number(r & 4294967295n);
|
|
267
|
+
const errorCode = Number(r >> 32n);
|
|
268
|
+
if (errorCode === 0) return outBuf.toString("utf8", 0, bytesWritten);
|
|
269
|
+
if (errorCode === 1) {
|
|
270
|
+
cap = Math.max(bytesWritten, cap * 2);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
throw new Error(`hyperdiff_patch failed with error code ${errorCode}`);
|
|
274
|
+
}
|
|
275
|
+
throw new Error("hyperdiff_patch: buffer too small after 3 retries");
|
|
276
|
+
},
|
|
277
|
+
inlineDiff(oldLine, newLine, mode) {
|
|
278
|
+
const oldBuf = Buffer.from(oldLine);
|
|
279
|
+
const newBuf = Buffer.from(newLine);
|
|
280
|
+
const resultPtr = assertNonNull(symbols.hyperdiff_inline_diff(ptr(oldBuf), oldBuf.length, ptr(newBuf), newBuf.length, mode));
|
|
281
|
+
const editsPtr = read.ptr(resultPtr, 0);
|
|
282
|
+
const editCount = read.u32(resultPtr, 8);
|
|
283
|
+
const errorCode = read.u32(resultPtr, 12);
|
|
284
|
+
if (errorCode !== 0) {
|
|
285
|
+
symbols.hyperdiff_inline_free(resultPtr);
|
|
286
|
+
throw new Error(`hyperdiff_inline_diff failed with error code ${errorCode}`);
|
|
287
|
+
}
|
|
288
|
+
const edits = new Array(editCount);
|
|
289
|
+
for (let i = 0; i < editCount; i++) {
|
|
290
|
+
const offset = Number(editsPtr) + i * CEDIT_BYTE_SIZE;
|
|
291
|
+
edits[i] = {
|
|
292
|
+
tag: read.u8(offset, 0),
|
|
293
|
+
oldStart: read.u32(offset, 4),
|
|
294
|
+
oldEnd: read.u32(offset, 8),
|
|
295
|
+
newStart: read.u32(offset, 12),
|
|
296
|
+
newEnd: read.u32(offset, 16)
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
symbols.hyperdiff_inline_free(resultPtr);
|
|
300
|
+
return edits;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
//#endregion
|
|
305
|
+
export { createBunAdapter, resolveDylibPath };
|
|
306
|
+
|
|
307
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/utils/platform.ts","../src/ffi.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\n\n/**\n * Get the shared library file extension for the current platform.\n * @returns 'dylib' on macOS, 'so' on Linux, 'dll' on Windows\n */\nexport function getDylibExtension(): string {\n switch (process.platform) {\n case 'darwin':\n return 'dylib';\n case 'win32':\n return 'dll';\n default:\n return 'so';\n }\n}\n\n/**\n * Resolve the path to libhyperdiff shared library.\n *\n * Search order:\n * 1. HYPERDIFF_LIB_PATH env var (exact path)\n * 2. Relative to this package: ../../zig/zig-out/lib/ (monorepo dev)\n * 3. /usr/local/lib/ (system install)\n *\n * @param customPath - Optional explicit path override\n * @returns Resolved absolute path to the shared library\n * @throws Error if library not found in any search path\n */\nexport function resolveDylibPath(customPath?: string): string {\n const ext = getDylibExtension();\n const libName = `libhyperdiff.${ext}`;\n\n // 1. Explicit override\n if (customPath) {\n const resolved = resolve(customPath);\n if (existsSync(resolved)) return resolved;\n throw new Error(`Hyperdiff library not found at explicit path: ${resolved}`);\n }\n\n // 2. Environment variable\n const envPath = process.env['HYPERDIFF_LIB_PATH'];\n if (envPath) {\n const resolved = resolve(envPath);\n if (existsSync(resolved)) return resolved;\n }\n\n // 3. Monorepo relative (core/packages/bun/ → core/zig/zig-out/lib/)\n const monorepoPath = join(import.meta.dir, '..', '..', '..', 'zig', 'zig-out', 'lib', libName);\n if (existsSync(monorepoPath)) return monorepoPath;\n\n // 4. System install\n const systemPath = join('/usr/local/lib', libName);\n if (existsSync(systemPath)) return systemPath;\n\n throw new Error(\n `Hyperdiff library (${libName}) not found. Searched:\\n` +\n ` - HYPERDIFF_LIB_PATH env var\\n` +\n ` - ${monorepoPath} (monorepo)\\n` +\n ` - ${systemPath} (system)\\n` +\n `Run 'zig build -Doptimize=ReleaseFast' in core/zig/ first.`,\n );\n}\n","/**\n * Bun FFI bindings for the Hyperdiff Zig engine.\n *\n * Uses bun:ffi dlopen to load libhyperdiff and expose typed wrappers.\n * Handles DiffResult/CEdit struct reading from raw pointers.\n */\nimport { dlopen, FFIType, ptr, read } from 'bun:ffi';\nimport {\n createLogger,\n type IRawDiffEdit,\n type IRawHunk,\n type IRawContent,\n type IFFIAdapter,\n type IRawDiffResult,\n type IRawMetadataResult,\n} from '@mks2508/hyperdiff-utils';\nimport { resolveDylibPath } from './utils/platform';\n\nconst log = createLogger('BunFFI');\n\n/** CEdit struct size: u8 + pad[3] + u32×4 = 20 bytes. */\nconst CEDIT_BYTE_SIZE = 20;\n\n/** CHunk struct size: 15×u32 + 2×u8 + 2×pad = 64 bytes. */\nconst CHUNK_BYTE_SIZE = 64;\n\n/** CContent struct size: u8 + pad[3] + u32×4 = 20 bytes. */\nconst CCONTENT_BYTE_SIZE = 20;\n\n/** FFI symbol definitions matching exports.zig C-ABI functions. */\nconst SYMBOLS = {\n hyperdiff_compute: {\n args: [FFIType.ptr, FFIType.u64, FFIType.ptr, FFIType.u64, FFIType.u8],\n returns: FFIType.ptr,\n },\n hyperdiff_free: {\n args: [FFIType.ptr],\n returns: FFIType.void,\n },\n hyperdiff_ping: {\n args: [],\n returns: FFIType.u32,\n },\n hyperdiff_cedit_size: {\n args: [],\n returns: FFIType.u64,\n },\n hyperdiff_abi_version: {\n args: [],\n returns: FFIType.u32,\n },\n hyperdiff_metadata: {\n args: [FFIType.ptr, FFIType.u64, FFIType.ptr, FFIType.u64, FFIType.u8, FFIType.u32, FFIType.u8, FFIType.ptr],\n returns: FFIType.void,\n },\n hyperdiff_metadata_free_raw: {\n args: [FFIType.ptr, FFIType.u32, FFIType.ptr, FFIType.u32],\n returns: FFIType.void,\n },\n hyperdiff_patch: {\n args: [\n FFIType.ptr, FFIType.u64, // old_ptr, old_len\n FFIType.ptr, FFIType.u64, // new_ptr, new_len\n FFIType.u8, // algorithm\n FFIType.u32, // context_lines\n FFIType.ptr, FFIType.u64, // out_buf, out_cap\n ],\n returns: FFIType.u64, // low32=bytes_written, high32=error_code\n },\n hyperdiff_inline_diff: {\n args: [\n FFIType.ptr, FFIType.u64, // old_ptr, old_len\n FFIType.ptr, FFIType.u64, // new_ptr, new_len\n FFIType.u8, // mode (0=word, 1=char)\n ],\n returns: FFIType.ptr, // InlineDiffResult\n },\n hyperdiff_inline_free: {\n args: [FFIType.ptr],\n returns: FFIType.void,\n },\n} as const;\n\n// Helper to assert non-null for Bun FFI types\nfunction assertNonNull<T>(value: T | null): T {\n if (value === null) {\n throw new Error('Unexpected null pointer from FFI');\n }\n return value;\n}\n\n/**\n * Create a Bun FFI adapter for the Hyperdiff engine.\n *\n * @param libraryPath - Optional explicit path to libhyperdiff.dylib\n * @returns IFFIAdapter implementation using bun:ffi\n */\nexport function createBunAdapter(libraryPath?: string): IFFIAdapter {\n const dylibPath = resolveDylibPath(libraryPath);\n log.info(`Loading library from ${dylibPath}`);\n\n const lib = dlopen(dylibPath, SYMBOLS);\n const { symbols } = lib;\n\n return {\n runtime: 'ffi-bun' as const,\n\n compute(oldText: string, newText: string, algorithm: number): IRawDiffResult {\n const oldBuf = Buffer.from(oldText);\n const newBuf = Buffer.from(newText);\n\n const resultPtr = assertNonNull(symbols.hyperdiff_compute(\n assertNonNull(ptr(oldBuf)),\n oldBuf.length,\n assertNonNull(ptr(newBuf)),\n newBuf.length,\n algorithm,\n ));\n\n // DiffResult is 16 bytes: [ptr:8][edit_count:u32][error_code:u32]\n const editsPtr = Number(assertNonNull(read.ptr(resultPtr, 0)));\n const editCount = read.u32(resultPtr, 8);\n const errorCode = read.u32(resultPtr, 12);\n\n return { editsPtr, editCount, errorCode };\n },\n\n free(resultPtr: number): void {\n // Convert number back to pointer for FFI\n symbols.hyperdiff_free(resultPtr as never);\n },\n\n ping(): number {\n return symbols.hyperdiff_ping();\n },\n\n ceditSize(): number {\n return Number(symbols.hyperdiff_cedit_size());\n },\n\n abiVersion(): number {\n return symbols.hyperdiff_abi_version();\n },\n\n readEdits(editsPtr: number, editCount: number): IRawDiffEdit[] {\n if (editCount === 0) return [];\n\n const edits: IRawDiffEdit[] = new Array(editCount);\n\n for (let i = 0; i < editCount; i++) {\n const offset = editsPtr + i * CEDIT_BYTE_SIZE;\n // CEdit layout: [tag:u8][_pad:3][old_start:u32][old_end:u32][new_start:u32][new_end:u32]\n edits[i] = {\n tag: read.u8(offset as never, 0),\n oldStart: read.u32(offset as never, 4),\n oldEnd: read.u32(offset as never, 8),\n newStart: read.u32(offset as never, 12),\n newEnd: read.u32(offset as never, 16),\n };\n }\n\n return edits;\n },\n\n metadata(oldText: string, newText: string, algorithm: number, contextLines: number, flags: number = 0): IRawMetadataResult {\n // Bun FFI rejects zero-length buffers — use 1-byte dummy for empty strings.\n const oldBuf = oldText.length > 0 ? Buffer.from(oldText) : Buffer.alloc(1);\n const newBuf = newText.length > 0 ? Buffer.from(newText) : Buffer.alloc(1);\n const oldLen = Buffer.byteLength(oldText);\n const newLen = Buffer.byteLength(newText);\n\n // Allocate a buffer for the output MetadataResult (48 bytes).\n // Zig writes the result into this buffer via output parameter.\n const outBuf = Buffer.alloc(48);\n\n symbols.hyperdiff_metadata(\n assertNonNull(ptr(oldBuf)),\n oldLen,\n assertNonNull(ptr(newBuf)),\n newLen,\n algorithm,\n contextLines,\n flags,\n assertNonNull(ptr(outBuf)),\n );\n\n // MetadataResult extern struct layout (48 bytes on 64-bit):\n // [0..8) hunks ptr\n // [8..12) hunk_count u32\n // [12..16) pad (pointer alignment)\n // [16..24) contents ptr\n // [24..28) content_count u32\n // [28..32) split_line_count u32\n // [32..36) unified_line_count u32\n // [36..40) old_line_count u32\n // [40..44) new_line_count u32\n // [44..48) error_code u32\n const resultPtr = assertNonNull(ptr(outBuf));\n const hunksPtr = Number(assertNonNull(read.ptr(resultPtr, 0)));\n const hunkCount = read.u32(resultPtr, 8);\n const contentsPtr = Number(assertNonNull(read.ptr(resultPtr, 16)));\n const contentCount = read.u32(resultPtr, 24);\n const splitLineCount = read.u32(resultPtr, 28);\n const unifiedLineCount = read.u32(resultPtr, 32);\n const oldLineCount = read.u32(resultPtr, 36);\n const newLineCount = read.u32(resultPtr, 40);\n const errorCode = read.u32(resultPtr, 44);\n\n return {\n hunksPtr,\n hunkCount,\n contentsPtr,\n contentCount,\n splitLineCount,\n unifiedLineCount,\n oldLineCount,\n newLineCount,\n errorCode,\n };\n },\n\n readHunks(hunksPtr: number, hunkCount: number): IRawHunk[] {\n if (hunkCount === 0) return [];\n\n const hunks: IRawHunk[] = new Array(hunkCount);\n\n for (let i = 0; i < hunkCount; i++) {\n const offset = hunksPtr + i * CHUNK_BYTE_SIZE;\n // CHunk layout: 15×u32 (60 bytes) + 2×u8 + 2×pad = 64 bytes\n hunks[i] = {\n collapsedBefore: read.u32(offset as never, 0),\n additionStart: read.u32(offset as never, 4),\n additionCount: read.u32(offset as never, 8),\n additionLines: read.u32(offset as never, 12),\n additionLineIndex: read.u32(offset as never, 16),\n deletionStart: read.u32(offset as never, 20),\n deletionCount: read.u32(offset as never, 24),\n deletionLines: read.u32(offset as never, 28),\n deletionLineIndex: read.u32(offset as never, 32),\n splitLineStart: read.u32(offset as never, 36),\n splitLineCount: read.u32(offset as never, 40),\n unifiedLineStart: read.u32(offset as never, 44),\n unifiedLineCount: read.u32(offset as never, 48),\n contentOffset: read.u32(offset as never, 52),\n contentCount: read.u32(offset as never, 56),\n noEofcrAdditions: read.u8(offset as never, 60),\n noEofcrDeletions: read.u8(offset as never, 61),\n };\n }\n\n return hunks;\n },\n\n readContents(contentsPtr: number, contentCount: number): IRawContent[] {\n if (contentCount === 0) return [];\n\n const contents: IRawContent[] = new Array(contentCount);\n\n for (let i = 0; i < contentCount; i++) {\n const offset = contentsPtr + i * CCONTENT_BYTE_SIZE;\n // CContent layout: [tag:u8][_pad:3][param1:u32][param2:u32][add_idx:u32][del_idx:u32]\n contents[i] = {\n tag: read.u8(offset as never, 0) as 0 | 1,\n param1: read.u32(offset as never, 4),\n param2: read.u32(offset as never, 8),\n additionLineIndex: read.u32(offset as never, 12),\n deletionLineIndex: read.u32(offset as never, 16),\n };\n }\n\n return contents;\n },\n\n metadataFree(hunksPtr: number, hunkCount: number, contentsPtr: number, contentCount: number): void {\n symbols.hyperdiff_metadata_free_raw(\n hunksPtr as never,\n hunkCount,\n contentsPtr as never,\n contentCount,\n );\n },\n\n patch(oldText: string, newText: string, algorithm: number, contextLines: number): string {\n const oldBuf = Buffer.from(oldText);\n const newBuf = Buffer.from(newText);\n let cap = Math.max(oldBuf.length + newBuf.length, 4096);\n for (let attempt = 0; attempt < 3; attempt++) {\n const outBuf = Buffer.alloc(cap);\n const result = symbols.hyperdiff_patch(\n ptr(oldBuf), oldBuf.length,\n ptr(newBuf), newBuf.length,\n algorithm,\n contextLines,\n ptr(outBuf), cap,\n );\n // u64: low 32 bits = bytes_written, high 32 bits = error_code\n const r = BigInt(result);\n const bytesWritten = Number(r & 0xFFFFFFFFn);\n const errorCode = Number(r >> 32n);\n if (errorCode === 0) {\n return outBuf.toString('utf8', 0, bytesWritten);\n }\n if (errorCode === 1) {\n cap = Math.max(bytesWritten, cap * 2);\n continue;\n }\n throw new Error(`hyperdiff_patch failed with error code ${errorCode}`);\n }\n throw new Error('hyperdiff_patch: buffer too small after 3 retries');\n },\n\n inlineDiff(oldLine: string, newLine: string, mode: number): IRawDiffEdit[] {\n const oldBuf = Buffer.from(oldLine);\n const newBuf = Buffer.from(newLine);\n const resultPtr = assertNonNull(symbols.hyperdiff_inline_diff(\n ptr(oldBuf), oldBuf.length,\n ptr(newBuf), newBuf.length,\n mode,\n ));\n // InlineDiffResult layout: [edits_ptr:ptr(8)][edit_count:u32][error_code:u32]\n const editsPtr = read.ptr(resultPtr as never, 0);\n const editCount = read.u32(resultPtr as never, 8);\n const errorCode = read.u32(resultPtr as never, 12);\n if (errorCode !== 0) {\n symbols.hyperdiff_inline_free(resultPtr as never);\n throw new Error(`hyperdiff_inline_diff failed with error code ${errorCode}`);\n }\n // Read CInlineEdit array (same layout as CEdit: 20 bytes each)\n const edits: IRawDiffEdit[] = new Array(editCount);\n for (let i = 0; i < editCount; i++) {\n const offset = Number(editsPtr) + i * CEDIT_BYTE_SIZE;\n edits[i] = {\n tag: read.u8(offset as never, 0),\n oldStart: read.u32(offset as never, 4),\n oldEnd: read.u32(offset as never, 8),\n newStart: read.u32(offset as never, 12),\n newEnd: read.u32(offset as never, 16),\n };\n }\n symbols.hyperdiff_inline_free(resultPtr as never);\n return edits;\n },\n };\n}\n"],"mappings":"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"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { IRawDiffResult, IFFIAdapter, IRawDiffEdit } from './ffi.types';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { resolveDylibPath, getDylibExtension } from './platform';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the shared library file extension for the current platform.
|
|
3
|
+
* @returns 'dylib' on macOS, 'so' on Linux, 'dll' on Windows
|
|
4
|
+
*/
|
|
5
|
+
export declare function getDylibExtension(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the path to libhyperdiff shared library.
|
|
8
|
+
*
|
|
9
|
+
* Search order:
|
|
10
|
+
* 1. HYPERDIFF_LIB_PATH env var (exact path)
|
|
11
|
+
* 2. Relative to this package: ../../zig/zig-out/lib/ (monorepo dev)
|
|
12
|
+
* 3. /usr/local/lib/ (system install)
|
|
13
|
+
*
|
|
14
|
+
* @param customPath - Optional explicit path override
|
|
15
|
+
* @returns Resolved absolute path to the shared library
|
|
16
|
+
* @throws Error if library not found in any search path
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveDylibPath(customPath?: string): string;
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mks2508/hyperdiff-ffi-bun",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "rm -rf dist && ../../../node_modules/.bin/rolldown --config rolldown.config.ts && ../../../node_modules/.bin/tsc --emitDeclarationOnly && node scripts/copy-lib.mjs",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"dev": "../../../node_modules/.bin/rolldown --config rolldown.config.ts --watch"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@mks2508/hyperdiff-utils": "workspace:*"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/bun": "^1.2.12"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"bun": ">=1.1.0"
|
|
32
|
+
}
|
|
33
|
+
}
|