ya-struct 0.0.5 → 0.0.6

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 (61) hide show
  1. package/.editorconfig +8 -0
  2. package/.github/workflows/ci.yml +23 -0
  3. package/.github/workflows/npm-publish.yml +28 -0
  4. package/README.md +150 -18
  5. package/dist/lib/common.d.ts +14 -0
  6. package/dist/lib/common.js +30 -0
  7. package/dist/lib/index.d.ts +5 -0
  8. package/dist/lib/index.js +21 -0
  9. package/dist/lib/layout.d.ts +48 -0
  10. package/dist/lib/layout.js +262 -0
  11. package/dist/lib/parser.d.ts +51 -0
  12. package/dist/lib/parser.js +87 -0
  13. package/dist/lib/types/array.d.ts +10 -0
  14. package/dist/lib/types/array.js +90 -0
  15. package/dist/lib/types/c-types.d.ts +13 -0
  16. package/dist/lib/types/c-types.js +222 -0
  17. package/dist/lib/types/index.d.ts +93 -0
  18. package/dist/lib/types/index.js +122 -0
  19. package/dist/lib/types/integer.d.ts +9 -0
  20. package/dist/lib/types/integer.js +160 -0
  21. package/dist/lib/types/pointer.d.ts +8 -0
  22. package/dist/lib/types/pointer.js +27 -0
  23. package/dist/lib/types/string.d.ts +6 -0
  24. package/dist/lib/types/string.js +56 -0
  25. package/dist/lib/types/struct.d.ts +11 -0
  26. package/dist/lib/types/struct.js +113 -0
  27. package/dist/lib/types/value.d.ts +12 -0
  28. package/dist/lib/types/value.js +8 -0
  29. package/eslint.config.js +127 -0
  30. package/lib/bit-buffer.ts +70 -0
  31. package/lib/common.ts +30 -0
  32. package/lib/index.ts +21 -0
  33. package/lib/layout.ts +262 -0
  34. package/lib/parser.ts +87 -0
  35. package/lib/types/array.ts +90 -0
  36. package/lib/types/c-types.ts +222 -0
  37. package/lib/types/index.ts +122 -0
  38. package/lib/types/integer.ts +160 -0
  39. package/lib/types/pointer.ts +27 -0
  40. package/lib/types/string.ts +56 -0
  41. package/lib/types/struct.ts +113 -0
  42. package/lib/types/value.ts +8 -0
  43. package/package.json +19 -15
  44. package/package.npm.json +25 -0
  45. package/samples/basic.ts +40 -0
  46. package/test/c-structs.ts +399 -0
  47. package/test/compile-util.ts +92 -0
  48. package/tsconfig.json +10 -0
  49. package/.eslintrc +0 -92
  50. package/.github/workflows/CI.yml +0 -39
  51. package/.prettierrc +0 -5
  52. package/lib/builder.js +0 -62
  53. package/lib/index.js +0 -159
  54. package/lib/marshaller.js +0 -88
  55. package/lib/refbuf.js +0 -11
  56. package/lib/types/basic.js +0 -200
  57. package/lib/types/ctypes.js +0 -160
  58. package/test/abi.js +0 -203
  59. package/test/basic.js +0 -92
  60. package/test/ctypes.js +0 -166
  61. package/test/ref.js +0 -35
package/test/abi.js DELETED
@@ -1,203 +0,0 @@
1
- /* global describe */
2
- /* global it */
3
-
4
- import struct from "../lib/index.js";
5
- import assert from "assert";
6
-
7
- describe("abi", () => {
8
- const testEndiannessFor = ({ endianness }) => {
9
- it("should support structure definition", () => {
10
- const def = struct
11
- .define(({ field }) => {
12
- field.UInt32("myfield1");
13
- field.UInt32("myfield2");
14
- })
15
- .abi({ endianness });
16
-
17
- assert.strictEqual(def.size, 8);
18
- assert.strictEqual(def.fields.myfield1.offset, 0);
19
- assert.strictEqual(def.fields.myfield1.size, 4);
20
- assert.strictEqual(def.fields.myfield2.offset, 4);
21
- assert.strictEqual(def.fields.myfield2.size, 4);
22
- });
23
-
24
- it("should parse data correctly", () => {
25
- const def = struct
26
- .define(({ field }) => {
27
- field.UInt32("myfield1");
28
- field.UInt32("myfield2");
29
- })
30
- .abi({ endianness });
31
-
32
- const buf = def.format({});
33
-
34
- buf[`writeUInt32${endianness}`](20, 0);
35
- buf[`writeUInt32${endianness}`](30, 4);
36
-
37
- const data = def.parse(buf);
38
- assert.strictEqual(data.myfield1, 20n);
39
- assert.strictEqual(data.myfield2, 30n);
40
- });
41
-
42
- it("should format data correctly", () => {
43
- const def = struct
44
- .define(({ field }) => {
45
- field.UInt32("myfield1");
46
- field.UInt32("myfield2");
47
- })
48
- .abi({ endianness });
49
-
50
- const buf = def.format({
51
- myfield1: 20n,
52
- myfield2: 30n,
53
- });
54
-
55
- const myfield1 = buf[`readUInt32${endianness}`](0);
56
- const myfield2 = buf[`readUInt32${endianness}`](4);
57
-
58
- assert.strictEqual(myfield1, 20);
59
- assert.strictEqual(myfield2, 30);
60
- });
61
- };
62
-
63
- describe("little endian", () => {
64
- testEndiannessFor({ endianness: "LE" });
65
- });
66
-
67
- describe("big endian", () => {
68
- testEndiannessFor({ endianness: "BE" });
69
- });
70
-
71
- describe("data models", () => {
72
- describe("LP64", () => {
73
- const endianness = "LE";
74
- const dataModel = "LP64";
75
-
76
- it("should support structure definition", () => {
77
- const def = struct
78
- .define(({ field }) => {
79
- field.Pointer("myfield1");
80
- field.Pointer("myfield2");
81
- })
82
- .abi({ endianness, dataModel });
83
-
84
- assert.strictEqual(def.size, 16);
85
- assert.strictEqual(def.fields.myfield1.offset, 0);
86
- assert.strictEqual(def.fields.myfield1.size, 8);
87
- assert.strictEqual(def.fields.myfield2.offset, 8);
88
- assert.strictEqual(def.fields.myfield2.size, 8);
89
- });
90
-
91
- it("should parse data correctly", () => {
92
- const def = struct
93
- .define(({ field }) => {
94
- field.Pointer("myfield1");
95
- field.Pointer("myfield2");
96
- })
97
- .abi({ endianness, dataModel });
98
-
99
- const buf = def.format({});
100
-
101
- buf.writeBigUInt64LE(20n, 0);
102
- buf.writeBigUInt64LE(30n, 8);
103
-
104
- const data = def.parse(buf);
105
- assert.strictEqual(data.myfield1, 20n);
106
- assert.strictEqual(data.myfield2, 30n);
107
- });
108
-
109
- it("should format data correctly", () => {
110
- const def = struct
111
- .define(({ field }) => {
112
- field.Pointer("myfield1");
113
- field.Pointer("myfield2");
114
- })
115
- .abi({ endianness, dataModel });
116
-
117
- const buf = def.format({
118
- myfield1: 20n,
119
- myfield2: 30n,
120
- });
121
-
122
- const myfield1 = buf.readBigUInt64LE(0);
123
- const myfield2 = buf.readBigUInt64LE(8);
124
-
125
- assert.strictEqual(myfield1, 20n);
126
- assert.strictEqual(myfield2, 30n);
127
- });
128
- });
129
- });
130
-
131
- describe("alignment models", () => {
132
- describe("LP64 - gcc", () => {
133
- const endianness = "LE";
134
- const dataModel = "LP64";
135
- const compiler = "gcc";
136
-
137
- it("should align Int8 correctly", () => {
138
- const def = struct
139
- .define(({ field }) => {
140
- field.Int8("myfield1");
141
- field.Int8("myfield2");
142
- })
143
- .abi({ endianness, dataModel, compiler });
144
-
145
- assert.strictEqual(def.fields.myfield1.offset, 0);
146
- assert.strictEqual(def.fields.myfield2.offset, 1);
147
- });
148
-
149
- it("should align Int16 correctly", () => {
150
- const def = struct
151
- .define(({ field }) => {
152
- field.Int8("myfield1");
153
- field.Int16LE("myfield2");
154
- })
155
- .abi({ endianness, dataModel, compiler });
156
-
157
- assert.strictEqual(def.fields.myfield1.offset, 0);
158
- assert.strictEqual(def.fields.myfield2.offset, 2);
159
- });
160
-
161
- it("should align Int32 correctly", () => {
162
- const def = struct
163
- .define(({ field }) => {
164
- field.Int8("myfield1");
165
- field.Int32LE("myfield2");
166
- })
167
- .abi({ endianness, dataModel, compiler });
168
-
169
- assert.strictEqual(def.fields.myfield1.offset, 0);
170
- assert.strictEqual(def.fields.myfield2.offset, 4);
171
- });
172
-
173
- it("should align Int64 correctly", () => {
174
- const def = struct
175
- .define(({ field }) => {
176
- field.Int8("myfield1");
177
- field.Int64LE("myfield2");
178
- })
179
- .abi({ endianness, dataModel, compiler });
180
-
181
- assert.strictEqual(def.fields.myfield1.offset, 0);
182
- assert.strictEqual(def.fields.myfield2.offset, 8);
183
- });
184
- });
185
- });
186
-
187
- const supportedAbiPlatforms = [
188
- {
189
- arch: "x64",
190
- platform: "linux",
191
- },
192
- ];
193
-
194
- const isHostSupported = supportedAbiPlatforms.some(({ arch, platform }) => {
195
- return process.arch === arch && process.platform === platform;
196
- });
197
-
198
- describe("host detection", () => {
199
- (isHostSupported ? it : it.skip)("should detect host without error", () => {
200
- struct.define(() => {}).forHost();
201
- });
202
- });
203
- });
package/test/basic.js DELETED
@@ -1,92 +0,0 @@
1
- /* global describe */
2
- /* global it */
3
-
4
- import struct from "../lib/index.js";
5
- import assert from "assert";
6
-
7
- describe("basic", () => {
8
- it("should support structure definition", () => {
9
- const def = struct
10
- .define(({ field }) => {
11
- field.UInt32LE("myfield1");
12
- field.UInt32LE("myfield2");
13
- })
14
- .abi({});
15
-
16
- assert.strictEqual(def.size, 8);
17
- assert.strictEqual(def.fields.myfield1.offset, 0);
18
- assert.strictEqual(def.fields.myfield1.size, 4);
19
- assert.strictEqual(def.fields.myfield2.offset, 4);
20
- assert.strictEqual(def.fields.myfield2.size, 4);
21
- });
22
-
23
- it("should allow empty instantiation", () => {
24
- const def = struct
25
- .define(({ field }) => {
26
- field.UInt32LE("myfield1");
27
- field.UInt32LE("myfield2");
28
- })
29
- .abi({});
30
-
31
- const buf = def.format({});
32
-
33
- assert.strictEqual(buf.length, 8);
34
- assert.strictEqual(buf.readUInt32LE(0), 0);
35
- assert.strictEqual(buf.readUInt32LE(4), 0);
36
- });
37
-
38
- it("should format data correctly", () => {
39
- const def = struct
40
- .define(({ field }) => {
41
- field.UInt32LE("myfield1");
42
- field.UInt32LE("myfield2");
43
- })
44
- .abi({});
45
-
46
- const buf = def.format({
47
- myfield1: 10n,
48
- myfield2: 20n,
49
- });
50
-
51
- assert.strictEqual(buf.length, 8);
52
- assert.strictEqual(buf.readUInt32LE(0), 10);
53
- assert.strictEqual(buf.readUInt32LE(4), 20);
54
- });
55
-
56
- it("should partial-format data correctly", () => {
57
- const def = struct
58
- .define(({ field }) => {
59
- field.UInt32LE("myfield1");
60
- field.UInt32LE("myfield2");
61
- })
62
- .abi({});
63
-
64
- const buf = def.format({
65
- myfield2: 20n,
66
- });
67
-
68
- assert.strictEqual(buf.length, 8);
69
- assert.strictEqual(buf.readUInt32LE(0), 0);
70
- assert.strictEqual(buf.readUInt32LE(4), 20);
71
- });
72
-
73
- it("should parse data correctly", () => {
74
- const def = struct
75
- .define(({ field }) => {
76
- field.UInt32LE("myfield1");
77
- field.UInt32LE("myfield2");
78
- })
79
- .abi({});
80
-
81
- const buf = def.format({});
82
-
83
- assert.strictEqual(buf.length, 8);
84
-
85
- buf.writeUInt32LE(30, 0);
86
-
87
- const data = def.parse(buf);
88
-
89
- assert.strictEqual(data.myfield1, 30n);
90
- assert.strictEqual(data.myfield2, 0n);
91
- });
92
- });
package/test/ctypes.js DELETED
@@ -1,166 +0,0 @@
1
- /* global describe */
2
- /* global it */
3
-
4
- import struct from "../lib/index.js";
5
- import tmp from "tmp-promise";
6
- import path from "path";
7
- import fs from "fs";
8
- import child_process from "child_process";
9
- import assert from "assert";
10
-
11
- const cTypeNameMap = {
12
- signedChar: "signed char",
13
- signedShort: "signed short",
14
- signedInt: "signed int",
15
- signedLong: "signed long",
16
- signedLongLong: "signed long long",
17
-
18
- unsignedChar: "unsigned char",
19
- unsignedShort: "unsigned short",
20
- unsignedInt: "unsigned int",
21
- unsignedLong: "unsigned long",
22
- unsignedLongLong: "unsigned long long",
23
-
24
- // float: "float",
25
- // double: "double",
26
- // longDouble: "long double",
27
- };
28
-
29
- const typesToTest = Object.keys(cTypeNameMap);
30
-
31
- const exec = (command) => {
32
- return new Promise((resolve, reject) => {
33
- child_process.exec(command, (err, stdout, stderr) => {
34
- if (err) {
35
- reject(stderr || err);
36
- } else {
37
- resolve(stdout);
38
- }
39
- });
40
- });
41
- };
42
-
43
- const compileAndRun = async ({ code }) => {
44
- return await tmp.withDir(async (dir) => {
45
- const sourceFile = path.resolve(dir.path, "main.c");
46
- const binaryFile = path.resolve(dir.path, "main.out");
47
-
48
- await fs.promises.writeFile(sourceFile, code);
49
- try {
50
- await exec(`gcc "${sourceFile}" -o "${binaryFile}"`);
51
- try {
52
- return await exec(`"${binaryFile}"`);
53
- } finally {
54
- await fs.promises.unlink(binaryFile);
55
- }
56
- } finally {
57
- await fs.promises.unlink(sourceFile);
58
- }
59
- });
60
- };
61
-
62
- const testNativeStructOffsetAndSize = async ({ fields }) => {
63
- const code = `
64
- #include <stdio.h>
65
-
66
- struct test_struct {
67
- ${fields.map((field) => `${field.type} ${field.name};`).join("\n")}
68
- };
69
-
70
- int main(int argc, char* argv[]) {
71
- ${fields
72
- .map((field) => {
73
- return `printf("${field.name} %i %i\\n",
74
- __builtin_offsetof(struct test_struct, ${field.name}),
75
- sizeof(((struct test_struct*) 0)->${field.name}));`;
76
- })
77
- .join("\n")}
78
-
79
- return 0;
80
- }
81
- `;
82
-
83
- const output = await compileAndRun({
84
- code,
85
- });
86
-
87
- let result = {};
88
-
89
- const lines = output
90
- .trim()
91
- .split("\n")
92
- .map((line) => line.trim());
93
- lines.forEach((line) => {
94
- const parts = line.split(/\s+/);
95
- const fieldName = parts[0];
96
- const offset = parseInt(parts[1], 10);
97
- const size = parseInt(parts[2], 10);
98
-
99
- result = {
100
- ...result,
101
- [fieldName]: {
102
- offset,
103
- size,
104
- },
105
- };
106
- });
107
-
108
- return result;
109
- };
110
-
111
- const genTestStructures = ({ numFields }) => {
112
- if (numFields === 0) {
113
- return [[]];
114
- }
115
-
116
- const other = genTestStructures({ numFields: numFields - 1 });
117
-
118
- let result = [];
119
- other.forEach((entry) => {
120
- typesToTest.forEach((type) => {
121
- result = [...result, [type, ...entry]];
122
- });
123
- });
124
-
125
- return result;
126
- };
127
-
128
- describe("ctypes", () => {
129
- const testStructures = genTestStructures({ numFields: 2 });
130
-
131
- testStructures.forEach((testStructure, idx) => {
132
- describe(`c test structure #${idx + 1}`, () => {
133
- it("should have correct offsets and sizes", async () => {
134
- const fields = testStructure.map((typeName, fieldIdx) => {
135
- return {
136
- name: `field${fieldIdx}`,
137
- type: `${cTypeNameMap[typeName]}`,
138
- };
139
- });
140
-
141
- const result = await testNativeStructOffsetAndSize({ fields });
142
-
143
- const def = struct
144
- .define(({ field }) => {
145
- testStructure.forEach((typeName, fieldIdx) => {
146
- field.CTypes[typeName](`field${fieldIdx}`);
147
- });
148
- })
149
- .forHost();
150
-
151
- let jsFields = {};
152
- Object.keys(def.fields).forEach((fieldName) => {
153
- jsFields = {
154
- ...jsFields,
155
- [fieldName]: {
156
- offset: def.fields[fieldName].offset,
157
- size: def.fields[fieldName].size,
158
- },
159
- };
160
- });
161
-
162
- assert.deepEqual(jsFields, result);
163
- });
164
- });
165
- });
166
- });
package/test/ref.js DELETED
@@ -1,35 +0,0 @@
1
- /* global describe */
2
- /* global it */
3
-
4
- import struct from "../lib/index.js";
5
- import assert from "assert";
6
-
7
- describe("referencing", () => {
8
- it("should allow buffer referencing", () => {
9
- const def1 = struct
10
- .define(({ field }) => {
11
- field.UInt32LE("myfield1");
12
- field.UInt32LE("myfield2");
13
- })
14
- .abi({});
15
-
16
- const def2 = struct
17
- .define(({ field }) => {
18
- field.UInt64LE("pointerToDef1");
19
- })
20
- .abi({});
21
-
22
- const buf1 = def1.format({});
23
- const buf2 = def2.format({
24
- pointerToDef1: buf1,
25
- });
26
-
27
- const addr = buf2.readBigUInt64LE(0);
28
-
29
- assert.strictEqual(typeof addr, "bigint");
30
- assert(addr !== 0n);
31
- assert(Array.isArray(buf2.referencedBuffers));
32
- assert.strictEqual(buf2.referencedBuffers.length, 1);
33
- assert.strictEqual(buf2.referencedBuffers[0], buf1);
34
- });
35
- });