@obelusfi/bun-cstruct 0.0.1 → 0.0.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/LICENSE +21 -0
- package/README.md +27 -2
- package/index.ts +36 -19
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Obelus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -25,7 +25,17 @@ This library exists as a practical solution while waiting for an official Bun AP
|
|
|
25
25
|
bun add @obelusfi/bun-cstruct
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
add
|
|
28
|
+
add
|
|
29
|
+
|
|
30
|
+
```jsonc
|
|
31
|
+
{
|
|
32
|
+
"compilerOptions": {
|
|
33
|
+
"experimentalDecorators": true,
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
to your `compilerOptions` in `tsconfig.json`
|
|
29
39
|
|
|
30
40
|
## Basic Usage
|
|
31
41
|
|
|
@@ -77,6 +87,9 @@ class SomeStruct extends CStruct {
|
|
|
77
87
|
import { dlopen, type Pointer } from "bun:ffi";
|
|
78
88
|
|
|
79
89
|
const { symbols: lib, close } = dlopen("./libexample.dylib", {
|
|
90
|
+
initStruct: {
|
|
91
|
+
args: ["pointer"],
|
|
92
|
+
},
|
|
80
93
|
doSomethingWithStruct: {
|
|
81
94
|
args: ["pointer"],
|
|
82
95
|
},
|
|
@@ -107,7 +120,19 @@ The static method `alloc(): Pointer` allows you to allocate memory for a struct
|
|
|
107
120
|
|
|
108
121
|
```ts
|
|
109
122
|
const ptr: Pointer = SomeStruct.alloc();
|
|
110
|
-
lib.
|
|
123
|
+
lib.initStruct(ptr);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Allocate and get an instance of a struct
|
|
127
|
+
|
|
128
|
+
The static method `new<T>(): T` allocates a `T` and returns an instance of `T` you can use
|
|
129
|
+
`T.pointerTo(insance):Pointer` to get a `Pointer`
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const item: SomeStruct = SomeStruct.new();
|
|
133
|
+
item.a = 42;
|
|
134
|
+
const p: Pointer = SomeStruct.pointerTo(item);
|
|
135
|
+
lib.doSomethingWithStruct(p);
|
|
111
136
|
```
|
|
112
137
|
|
|
113
138
|
### Get size of struct
|
package/index.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { CString, type Pointer, read, ptr as pt, toBuffer } from 'bun:ffi';
|
|
2
2
|
import { endianness } from 'os';
|
|
3
3
|
|
|
4
|
+
type CheckRefPointer<T, K extends keyof T> = K extends `$${infer U}` ? U extends keyof T ? [] : [U] : [K];
|
|
5
|
+
type Checks<T, K extends keyof T, Expected> = T[K] extends Expected ? [] : [Expected]
|
|
6
|
+
type TypedDecorator<Expected> = <T extends CStruct, K extends keyof T>(target: T, key: K, ...property_and_decorator_type_mismatch: Checks<T, K, Expected>) => void;
|
|
7
|
+
type Extract<T> = T extends TypedDecorator<infer U> ? U : never
|
|
8
|
+
type Layout = {
|
|
9
|
+
cursor: number
|
|
10
|
+
alignment: number
|
|
11
|
+
}
|
|
4
12
|
|
|
5
13
|
function alignUp(n: number, alignment: number) {
|
|
6
14
|
return (n + alignment - 1) & ~(alignment - 1);
|
|
@@ -10,7 +18,7 @@ const p = Symbol.for('p');
|
|
|
10
18
|
const o = Symbol.for('o');
|
|
11
19
|
const e = endianness();
|
|
12
20
|
|
|
13
|
-
|
|
21
|
+
|
|
14
22
|
|
|
15
23
|
const read2w = {
|
|
16
24
|
"f32": `writeFloat${e}` as const,
|
|
@@ -22,17 +30,14 @@ const read2w = {
|
|
|
22
30
|
'i64': `writeBigInt64${e}` as const,
|
|
23
31
|
'u64': `writeBigUInt64${e}` as const,
|
|
24
32
|
|
|
25
|
-
'intptr': `writeUInt32${e}` as const,
|
|
26
|
-
'ptr': `writeBigUInt64${e}` as const,
|
|
33
|
+
'intptr': `writeUInt32${e}` as const,
|
|
34
|
+
'ptr': `writeBigUInt64${e}` as const,
|
|
27
35
|
|
|
28
36
|
'i8': 'writeInt8' as const,
|
|
29
37
|
'u8': 'writeUInt8' as const,
|
|
30
|
-
} satisfies Record<keyof typeof read,
|
|
38
|
+
} satisfies Record<keyof typeof read, keyof Buffer>;
|
|
39
|
+
|
|
31
40
|
|
|
32
|
-
type Layout = {
|
|
33
|
-
cursor: number
|
|
34
|
-
alignment: number
|
|
35
|
-
}
|
|
36
41
|
const layoutMap = new WeakMap<Function, Layout>();
|
|
37
42
|
|
|
38
43
|
export abstract class CStruct {
|
|
@@ -68,6 +73,21 @@ export abstract class CStruct {
|
|
|
68
73
|
return pt(buff);
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
static new<T extends typeof CStruct>(this: T): InstanceType<T> {
|
|
77
|
+
const p = this.alloc();
|
|
78
|
+
//@ts-ignore
|
|
79
|
+
return new this(p, 0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static toBuffer(item: CStruct) {
|
|
83
|
+
const ctr = Object.getPrototypeOf(item).constructor as (typeof CStruct);
|
|
84
|
+
return toBuffer(item[p], 0, ctr.size);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static pointerTo(item: CStruct): Pointer {
|
|
88
|
+
return item[p]
|
|
89
|
+
}
|
|
90
|
+
|
|
71
91
|
|
|
72
92
|
constructor(ptr: Pointer, offset = 0) {
|
|
73
93
|
this[p] = ptr;
|
|
@@ -116,6 +136,10 @@ export function struct<T extends typeof CStruct>(cls: T) {
|
|
|
116
136
|
const reader = (p: Pointer, offset: number) => {
|
|
117
137
|
return cls.reader(p, offset);
|
|
118
138
|
}
|
|
139
|
+
const writer = (v: any, p: Pointer, offset: number) => {
|
|
140
|
+
const buff = CStruct.toBuffer(v);
|
|
141
|
+
toBuffer(p, offset, cls.size).fill(buff)
|
|
142
|
+
}
|
|
119
143
|
const deco = function (target: CStruct, key: string) {
|
|
120
144
|
const ctr = target.constructor as typeof CStruct;
|
|
121
145
|
const layout = ctr['getLayout']();
|
|
@@ -128,11 +152,10 @@ export function struct<T extends typeof CStruct>(cls: T) {
|
|
|
128
152
|
|
|
129
153
|
Object.defineProperty(target, key, {
|
|
130
154
|
get() {
|
|
131
|
-
|
|
132
|
-
return reader(ptr, offset + this[o]);
|
|
155
|
+
return reader(this[p], offset + this[o]);
|
|
133
156
|
},
|
|
134
157
|
set(v) {
|
|
135
|
-
|
|
158
|
+
writer(v, this[p], offset + this[o])
|
|
136
159
|
},
|
|
137
160
|
enumerable: true,
|
|
138
161
|
});
|
|
@@ -358,8 +381,8 @@ export const i32 = primitiveDecorator(4, 'i32', 4) as TypedDecorator<number>;
|
|
|
358
381
|
export const u32 = primitiveDecorator(4, 'u32', 4) as TypedDecorator<number>;
|
|
359
382
|
export const f32 = primitiveDecorator(4, 'f32', 4) as TypedDecorator<number>;
|
|
360
383
|
|
|
361
|
-
export const i64 = primitiveDecorator(8, 'i64', 8) as TypedDecorator<
|
|
362
|
-
export const u64 = primitiveDecorator(8, 'u64', 8) as TypedDecorator<
|
|
384
|
+
export const i64 = primitiveDecorator(8, 'i64', 8) as TypedDecorator<bigint>;
|
|
385
|
+
export const u64 = primitiveDecorator(8, 'u64', 8) as TypedDecorator<bigint>;
|
|
363
386
|
export const f64 = primitiveDecorator(8, 'f64', 8) as TypedDecorator<number>;
|
|
364
387
|
|
|
365
388
|
export const ptr = primitiveDecorator(8, 'ptr', 8) as TypedDecorator<number>;
|
|
@@ -368,9 +391,3 @@ export const string = stringDecorator();
|
|
|
368
391
|
|
|
369
392
|
|
|
370
393
|
export const refPointer = ((a: CStruct, b: string) => { }) as <T extends CStruct, K extends keyof T>(target: T, key: K, ...this_pointer_doesnt_exist_in_this_struct: CheckRefPointer<T, K>) => void;
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
type CheckRefPointer<T, K extends keyof T> = K extends `$${infer U}` ? U extends keyof T ? [] : [U] : [K];
|
|
374
|
-
type Checks<T, K extends keyof T, Expected> = T[K] extends Expected ? [] : [Expected]
|
|
375
|
-
type TypedDecorator<Expected> = <T extends CStruct, K extends keyof T>(target: T, key: K, ...property_and_decorator_type_mismatch: Checks<T, K, Expected>) => void;
|
|
376
|
-
type Extract<T> = T extends TypedDecorator<infer U> ? U : never
|