@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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +27 -2
  3. package/index.ts +36 -19
  4. 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 `"experimentalDecorators": true` to your `tsconfig.json`
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.doSomethingWithStruct(ptr);
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
- type Writes = keyof Buffer;
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, // see if we can find the size to use
26
- 'ptr': `writeBigUInt64${e}` as const, // see if we can find the size to use
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, Writes>;
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
- const ptr: Pointer = this[p];
132
- return reader(ptr, offset + this[o]);
155
+ return reader(this[p], offset + this[o]);
133
156
  },
134
157
  set(v) {
135
- throw new Error("Can only write to fields");
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<number>;
362
- export const u64 = primitiveDecorator(8, 'u64', 8) as TypedDecorator<number>;
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
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@obelusfi/bun-cstruct",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.0.1",
5
+ "version": "0.0.2",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/ObelusFi/bun-cstruct.git"