ya-struct 0.0.4 → 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.
- package/.editorconfig +8 -0
- package/.github/workflows/ci.yml +23 -0
- package/.github/workflows/npm-publish.yml +28 -0
- package/README.md +150 -18
- package/dist/lib/common.d.ts +14 -0
- package/dist/lib/common.js +30 -0
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/index.js +21 -0
- package/dist/lib/layout.d.ts +48 -0
- package/dist/lib/layout.js +262 -0
- package/dist/lib/parser.d.ts +51 -0
- package/dist/lib/parser.js +87 -0
- package/dist/lib/types/array.d.ts +10 -0
- package/dist/lib/types/array.js +90 -0
- package/dist/lib/types/c-types.d.ts +13 -0
- package/dist/lib/types/c-types.js +222 -0
- package/dist/lib/types/index.d.ts +93 -0
- package/dist/lib/types/index.js +122 -0
- package/dist/lib/types/integer.d.ts +9 -0
- package/dist/lib/types/integer.js +160 -0
- package/dist/lib/types/pointer.d.ts +8 -0
- package/dist/lib/types/pointer.js +27 -0
- package/dist/lib/types/string.d.ts +6 -0
- package/dist/lib/types/string.js +56 -0
- package/dist/lib/types/struct.d.ts +11 -0
- package/dist/lib/types/struct.js +113 -0
- package/dist/lib/types/value.d.ts +12 -0
- package/dist/lib/types/value.js +8 -0
- package/eslint.config.js +127 -0
- package/lib/bit-buffer.ts +70 -0
- package/lib/common.ts +30 -0
- package/lib/index.ts +21 -0
- package/lib/layout.ts +262 -0
- package/lib/parser.ts +87 -0
- package/lib/types/array.ts +90 -0
- package/lib/types/c-types.ts +222 -0
- package/lib/types/index.ts +122 -0
- package/lib/types/integer.ts +160 -0
- package/lib/types/pointer.ts +27 -0
- package/lib/types/string.ts +56 -0
- package/lib/types/struct.ts +113 -0
- package/lib/types/value.ts +8 -0
- package/package.json +19 -15
- package/package.npm.json +25 -0
- package/samples/basic.ts +40 -0
- package/test/c-structs.ts +399 -0
- package/test/compile-util.ts +92 -0
- package/tsconfig.json +10 -0
- package/.eslintrc +0 -92
- package/.github/workflows/CI.yml +0 -39
- package/.prettierrc +0 -5
- package/lib/builder.js +0 -62
- package/lib/index.js +0 -159
- package/lib/marshaller.js +0 -80
- package/lib/refbuf.js +0 -11
- package/lib/types/basic.js +0 -200
- package/lib/types/ctypes.js +0 -160
- package/test/abi.js +0 -203
- package/test/basic.js +0 -92
- package/test/ctypes.js +0 -166
- package/test/ref.js +0 -35
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/*import type { TEndianness } from "../common.ts";*/
|
|
2
|
+
/*import type { TValueParser } from "./value.ts";*/
|
|
3
|
+
|
|
4
|
+
/*type TIntegerParser = TValueParser<bigint>;*/
|
|
5
|
+
|
|
6
|
+
const createIntegerParser = ({
|
|
7
|
+
sizeInBits,
|
|
8
|
+
signed,
|
|
9
|
+
endianness
|
|
10
|
+
}/*: {
|
|
11
|
+
sizeInBits: number,
|
|
12
|
+
signed: boolean,
|
|
13
|
+
endianness: TEndianness
|
|
14
|
+
}*/)/*: TIntegerParser*/ => {
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line max-statements, complexity
|
|
17
|
+
const parse/*: TIntegerParser["parse"]*/ = ({ data, offsetInBits }) => {
|
|
18
|
+
if (data.length < sizeInBits / 8) {
|
|
19
|
+
throw Error("BUG: not enough data for integer parsing");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (offsetInBits !== 0) {
|
|
23
|
+
throw Error("unaligned data in integer parser, not supported yet");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const view = new DataView(data.buffer, data.byteOffset);
|
|
27
|
+
|
|
28
|
+
if (sizeInBits === 8) {
|
|
29
|
+
if (signed) {
|
|
30
|
+
return BigInt(view.getInt8(0));
|
|
31
|
+
} else {
|
|
32
|
+
return BigInt(view.getUint8(0));
|
|
33
|
+
}
|
|
34
|
+
} else if (sizeInBits === 16) {
|
|
35
|
+
if (signed) {
|
|
36
|
+
if (endianness === "little") {
|
|
37
|
+
return BigInt(view.getInt16(0, true));
|
|
38
|
+
} else {
|
|
39
|
+
return BigInt(view.getInt16(0, false));
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
// eslint-disable-next-line no-lonely-if
|
|
43
|
+
if (endianness === "little") {
|
|
44
|
+
return BigInt(view.getUint16(0, true));
|
|
45
|
+
} else {
|
|
46
|
+
return BigInt(view.getUint16(0, false));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else if (sizeInBits === 32) {
|
|
50
|
+
if (signed) {
|
|
51
|
+
if (endianness === "little") {
|
|
52
|
+
return BigInt(view.getInt32(0, true));
|
|
53
|
+
} else {
|
|
54
|
+
return BigInt(view.getInt32(0, false));
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
// eslint-disable-next-line no-lonely-if
|
|
58
|
+
if (endianness === "little") {
|
|
59
|
+
return BigInt(view.getUint32(0, true));
|
|
60
|
+
} else {
|
|
61
|
+
return BigInt(view.getUint32(0, false));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} else if (sizeInBits === 64) {
|
|
65
|
+
if (signed) {
|
|
66
|
+
if (endianness === "little") {
|
|
67
|
+
return view.getBigInt64(0, true);
|
|
68
|
+
} else {
|
|
69
|
+
return view.getBigInt64(0, false);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
// eslint-disable-next-line no-lonely-if
|
|
73
|
+
if (endianness === "little") {
|
|
74
|
+
return view.getBigUint64(0, true);
|
|
75
|
+
} else {
|
|
76
|
+
return view.getBigUint64(0, false);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw Error("not implemented yet");
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// eslint-disable-next-line max-statements, complexity
|
|
85
|
+
const format/*: TIntegerParser["format"]*/ = ({ value, target, offsetInBits }) => {
|
|
86
|
+
if (offsetInBits !== 0) {
|
|
87
|
+
throw Error("unaligned data in integer formatter, not supported yet");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (typeof value !== "bigint") {
|
|
91
|
+
throw Error("invalid value type for integer formatter");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const view = new DataView(target.buffer, target.byteOffset);
|
|
95
|
+
|
|
96
|
+
if (sizeInBits === 8) {
|
|
97
|
+
if (signed) {
|
|
98
|
+
view.setInt8(0, Number(value));
|
|
99
|
+
} else {
|
|
100
|
+
view.setUint8(0, Number(value));
|
|
101
|
+
}
|
|
102
|
+
} else if (sizeInBits === 16) {
|
|
103
|
+
if (signed) {
|
|
104
|
+
if (endianness === "little") {
|
|
105
|
+
view.setInt16(0, Number(value), true);
|
|
106
|
+
} else {
|
|
107
|
+
view.setInt16(0, Number(value), false);
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
// eslint-disable-next-line no-lonely-if
|
|
111
|
+
if (endianness === "little") {
|
|
112
|
+
view.setUint16(0, Number(value), true);
|
|
113
|
+
} else {
|
|
114
|
+
view.setUint16(0, Number(value), false);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} else if (sizeInBits === 32) {
|
|
118
|
+
if (signed) {
|
|
119
|
+
if (endianness === "little") {
|
|
120
|
+
view.setInt32(0, Number(value), true);
|
|
121
|
+
} else {
|
|
122
|
+
view.setInt32(0, Number(value), false);
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
// eslint-disable-next-line no-lonely-if
|
|
126
|
+
if (endianness === "little") {
|
|
127
|
+
view.setUint32(0, Number(value), true);
|
|
128
|
+
} else {
|
|
129
|
+
view.setUint32(0, Number(value), false);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} else if (sizeInBits === 64) {
|
|
133
|
+
if (signed) {
|
|
134
|
+
if (endianness === "little") {
|
|
135
|
+
view.setBigInt64(0, value, true);
|
|
136
|
+
} else {
|
|
137
|
+
view.setBigInt64(0, value, false);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
// eslint-disable-next-line no-lonely-if
|
|
141
|
+
if (endianness === "little") {
|
|
142
|
+
view.setBigUint64(0, value, true);
|
|
143
|
+
} else {
|
|
144
|
+
view.setBigUint64(0, value, false);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
throw Error("not implemented yet");
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
parse,
|
|
154
|
+
format
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
createIntegerParser
|
|
160
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TEndianness } from "../common.js";
|
|
2
|
+
import type { TValueParser } from "./value.js";
|
|
3
|
+
type TPointerParser = TValueParser<bigint>;
|
|
4
|
+
declare const createPointerParser: ({ sizeInBits, endianness }: {
|
|
5
|
+
sizeInBits: number;
|
|
6
|
+
endianness: TEndianness;
|
|
7
|
+
}) => TPointerParser;
|
|
8
|
+
export { createPointerParser };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*import type { TEndianness } from "../common.ts";*/
|
|
2
|
+
import { createIntegerParser } from "./integer.js";
|
|
3
|
+
/*import type { TValueParser } from "./value.ts";*/
|
|
4
|
+
|
|
5
|
+
/*type TPointerParser = TValueParser<bigint>;*/
|
|
6
|
+
|
|
7
|
+
const createPointerParser = ({ sizeInBits, endianness }/*: { sizeInBits: number, endianness: TEndianness }*/)/*: TPointerParser*/ => {
|
|
8
|
+
|
|
9
|
+
const integerParser = createIntegerParser({ sizeInBits, signed: false, endianness });
|
|
10
|
+
|
|
11
|
+
const parse/*: TPointerParser["parse"]*/ = ({ data, offsetInBits }) => {
|
|
12
|
+
return integerParser.parse({ data, offsetInBits });
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const format/*: TPointerParser["format"]*/ = ({ value, target, offsetInBits }) => {
|
|
16
|
+
return integerParser.format({ value, target, offsetInBits });
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
parse,
|
|
21
|
+
format
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
createPointerParser
|
|
27
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*import type { TValueParser } from "./value.ts";*/
|
|
2
|
+
|
|
3
|
+
/*type TStringParser = TValueParser<string>;*/
|
|
4
|
+
|
|
5
|
+
const createStringParser = ({ length }/*: { length: number }*/)/*: TStringParser*/ => {
|
|
6
|
+
|
|
7
|
+
const decoder = new TextDecoder();
|
|
8
|
+
const encoder = new TextEncoder();
|
|
9
|
+
|
|
10
|
+
const parse/*: TStringParser["parse"]*/ = ({ data, offsetInBits }) => {
|
|
11
|
+
if (offsetInBits !== 0) {
|
|
12
|
+
throw Error("unaligned data in string parser, not supported yet");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (data.length < length) {
|
|
16
|
+
throw Error("not enough data for string parsing");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const stringData = data.subarray(0, length);
|
|
20
|
+
const nullTerminatorIndex = stringData.indexOf(0);
|
|
21
|
+
|
|
22
|
+
if (nullTerminatorIndex < 0) {
|
|
23
|
+
return decoder.decode(stringData);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return decoder.decode(stringData.subarray(0, nullTerminatorIndex));
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const format/*: TStringParser["format"]*/ = ({ value, target, offsetInBits }) => {
|
|
30
|
+
if (offsetInBits !== 0) {
|
|
31
|
+
throw Error("unaligned data in string formatter, not supported yet");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (target.length < length) {
|
|
35
|
+
throw Error("not enough space in target for string formatting");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const encoded = encoder.encode(value);
|
|
39
|
+
|
|
40
|
+
if (encoded.length + 1 >= length) {
|
|
41
|
+
throw Error("string too long to fit in target");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
target.set(encoded, 0);
|
|
45
|
+
target[encoded.length] = 0;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
parse,
|
|
50
|
+
format
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
createStringParser
|
|
56
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TEndianness } from "../common.js";
|
|
2
|
+
import type { TLayoutedField } from "../layout.js";
|
|
3
|
+
import type { TValueParser } from "./value.js";
|
|
4
|
+
type TStructParser = TValueParser<Record<string, unknown>>;
|
|
5
|
+
declare const createStructParser: ({ layoutedFields, endianness }: {
|
|
6
|
+
layoutedFields: (TLayoutedField & {
|
|
7
|
+
type: "struct";
|
|
8
|
+
})["fields"];
|
|
9
|
+
endianness: TEndianness;
|
|
10
|
+
}) => TStructParser;
|
|
11
|
+
export { createStructParser };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*import type { TEndianness } from "../common.ts";*/
|
|
2
|
+
/*import type { TLayoutedField } from "../layout.ts";*/
|
|
3
|
+
import { createIntegerParser } from "./integer.js";
|
|
4
|
+
import { createPointerParser } from "./pointer.js";
|
|
5
|
+
import { createStringParser } from "./string.js";
|
|
6
|
+
import { createArrayParser } from "./array.js";
|
|
7
|
+
/*import type { TValueParser } from "./value.ts";*/
|
|
8
|
+
/*import type { TFieldType } from "./index.ts";*/
|
|
9
|
+
|
|
10
|
+
/*type TStructParser = TValueParser<Record<string, unknown>>;*/
|
|
11
|
+
|
|
12
|
+
const createStructParser = ({
|
|
13
|
+
layoutedFields,
|
|
14
|
+
endianness
|
|
15
|
+
}/*: {
|
|
16
|
+
layoutedFields: (TLayoutedField & { type: "struct" })["fields"];
|
|
17
|
+
endianness: TEndianness
|
|
18
|
+
}*/)/*: TStructParser*/ => {
|
|
19
|
+
|
|
20
|
+
// eslint-disable-next-line complexity, @typescript-eslint/no-explicit-any
|
|
21
|
+
const fieldParsers/*: TValueParser<any>[]*/ = layoutedFields.map((field) => {
|
|
22
|
+
if (field.definition.type === "integer") {
|
|
23
|
+
return createIntegerParser({
|
|
24
|
+
sizeInBits: field.definition.sizeInBits,
|
|
25
|
+
signed: field.definition.signed,
|
|
26
|
+
endianness
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (field.definition.type === "pointer") {
|
|
31
|
+
return createPointerParser({
|
|
32
|
+
sizeInBits: field.definition.sizeInBits,
|
|
33
|
+
endianness
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (field.definition.type === "struct") {
|
|
38
|
+
return createStructParser({
|
|
39
|
+
layoutedFields: field.definition.fields,
|
|
40
|
+
endianness
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (field.definition.type === "string") {
|
|
45
|
+
return createStringParser({
|
|
46
|
+
length: field.definition.length,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (field.definition.type === "array") {
|
|
51
|
+
return createArrayParser({
|
|
52
|
+
// TODO: cast should not be necessary
|
|
53
|
+
elementType: field.definition.elementType /*as TFieldType*/,
|
|
54
|
+
endianness,
|
|
55
|
+
length: field.definition.length
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
throw Error("not implemented yet");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const parse/*: TStructParser["parse"]*/ = ({ data, offsetInBits }) => {
|
|
63
|
+
if (offsetInBits !== 0) {
|
|
64
|
+
throw Error("unaligned struct parsing not supported yet");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// eslint-disable-next-line prefer-const
|
|
68
|
+
let result/*: Record<string, unknown>*/ = {};
|
|
69
|
+
|
|
70
|
+
layoutedFields.forEach((field, idx) => {
|
|
71
|
+
const fieldParser = fieldParsers[idx];
|
|
72
|
+
|
|
73
|
+
const offsetInBitsInByte = field.definition.offsetInBits % 8;
|
|
74
|
+
if (offsetInBitsInByte !== 0) {
|
|
75
|
+
throw Error("not implemented yet: unaligned field parsing");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const fieldData = new Uint8Array(data.buffer, data.byteOffset + (field.definition.offsetInBits / 8));
|
|
79
|
+
result[field.name] = fieldParser.parse({ data: fieldData, offsetInBits: offsetInBitsInByte });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return result;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const format/*: TStructParser["format"]*/ = ({ value, target, offsetInBits }) => {
|
|
86
|
+
layoutedFields.forEach((field, idx) => {
|
|
87
|
+
const fieldValue = value[field.name];
|
|
88
|
+
const fieldParser = fieldParsers[idx];
|
|
89
|
+
|
|
90
|
+
const offsetInBitsInByte = field.definition.offsetInBits % 8;
|
|
91
|
+
if (offsetInBitsInByte !== 0) {
|
|
92
|
+
throw Error("not implemented yet: unaligned field formatting");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const fieldTarget = new Uint8Array(target.buffer, target.byteOffset + (field.definition.offsetInBits / 8));
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
fieldParser.format({ value: fieldValue, target: fieldTarget, offsetInBits });
|
|
99
|
+
} catch (ex) {
|
|
100
|
+
throw Error(`failed to format field "${field.name}"`, { cause: ex });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
parse,
|
|
107
|
+
format
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
createStructParser
|
|
113
|
+
};
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/* c8 ignore start */
|
|
2
|
+
import eslint from "@eslint/js";
|
|
3
|
+
import tseslint from "typescript-eslint";
|
|
4
|
+
|
|
5
|
+
export default tseslint.config(
|
|
6
|
+
{
|
|
7
|
+
ignores: [
|
|
8
|
+
"dist/**/*"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
eslint.configs.recommended,
|
|
12
|
+
...tseslint.configs.recommended,
|
|
13
|
+
{
|
|
14
|
+
rules: {
|
|
15
|
+
"global-require": "off",
|
|
16
|
+
"quote-props": ["warn", "consistent-as-needed"],
|
|
17
|
+
|
|
18
|
+
"quotes": ["error", "double", {
|
|
19
|
+
allowTemplateLiterals: true,
|
|
20
|
+
}],
|
|
21
|
+
|
|
22
|
+
"no-plusplus": "error",
|
|
23
|
+
"no-nested-ternary": "error",
|
|
24
|
+
"no-multiple-empty-lines": "error",
|
|
25
|
+
"no-inline-comments": "error",
|
|
26
|
+
"no-lonely-if": "error",
|
|
27
|
+
"no-array-constructor": "error",
|
|
28
|
+
"no-delete-var": "error",
|
|
29
|
+
"no-param-reassign": "error",
|
|
30
|
+
"no-return-assign": "error",
|
|
31
|
+
"no-import-assign": "error",
|
|
32
|
+
"no-multi-assign": "error",
|
|
33
|
+
"keyword-spacing": "error",
|
|
34
|
+
|
|
35
|
+
"max-len": ["warn", {
|
|
36
|
+
code: 140,
|
|
37
|
+
}],
|
|
38
|
+
|
|
39
|
+
"max-params": ["error", 4],
|
|
40
|
+
"max-statements": ["error", 15],
|
|
41
|
+
"no-loss-of-precision": "error",
|
|
42
|
+
"no-unreachable-loop": "error",
|
|
43
|
+
"require-atomic-updates": "error",
|
|
44
|
+
"complexity": ["error", 4],
|
|
45
|
+
|
|
46
|
+
"max-statements-per-line": ["error", {
|
|
47
|
+
max: 1,
|
|
48
|
+
}],
|
|
49
|
+
|
|
50
|
+
"no-tabs": "error",
|
|
51
|
+
"no-underscore-dangle": "error",
|
|
52
|
+
"no-negated-condition": "error",
|
|
53
|
+
"no-use-before-define": "error",
|
|
54
|
+
|
|
55
|
+
"no-shadow": "off",
|
|
56
|
+
"@typescript-eslint/no-shadow": "error",
|
|
57
|
+
|
|
58
|
+
"no-labels": "error",
|
|
59
|
+
"no-throw-literal": "error",
|
|
60
|
+
"default-case": "error",
|
|
61
|
+
"default-case-last": "error",
|
|
62
|
+
"no-caller": "error",
|
|
63
|
+
"no-eval": "error",
|
|
64
|
+
"no-implied-eval": "error",
|
|
65
|
+
"no-new": "error",
|
|
66
|
+
"no-new-func": "error",
|
|
67
|
+
"no-new-object": "error",
|
|
68
|
+
"no-new-wrappers": "error",
|
|
69
|
+
"no-useless-concat": "error",
|
|
70
|
+
|
|
71
|
+
"no-unused-vars": "off",
|
|
72
|
+
"@typescript-eslint/no-unused-vars": ["error", {
|
|
73
|
+
ignoreRestSiblings: true,
|
|
74
|
+
}],
|
|
75
|
+
|
|
76
|
+
"array-bracket-newline": ["error", "consistent"],
|
|
77
|
+
"func-names": ["error", "never"],
|
|
78
|
+
|
|
79
|
+
"func-style": ["error", "expression", {
|
|
80
|
+
allowArrowFunctions: true,
|
|
81
|
+
}],
|
|
82
|
+
|
|
83
|
+
"max-depth": ["error", 4],
|
|
84
|
+
"arrow-parens": "error",
|
|
85
|
+
"no-confusing-arrow": "error",
|
|
86
|
+
"prefer-const": "error",
|
|
87
|
+
"rest-spread-spacing": ["error", "never"],
|
|
88
|
+
"template-curly-spacing": ["error", "never"],
|
|
89
|
+
"prefer-rest-params": "error",
|
|
90
|
+
"prefer-spread": "error",
|
|
91
|
+
"prefer-template": "error",
|
|
92
|
+
"object-shorthand": ["error", "properties"],
|
|
93
|
+
"no-var": "error",
|
|
94
|
+
"no-useless-computed-key": "error",
|
|
95
|
+
"array-callback-return": "error",
|
|
96
|
+
"consistent-return": "error",
|
|
97
|
+
"dot-notation": "error",
|
|
98
|
+
"eqeqeq": "error",
|
|
99
|
+
"no-eq-null": "error",
|
|
100
|
+
"no-implicit-coercion": "error",
|
|
101
|
+
"no-multi-spaces": "error",
|
|
102
|
+
"no-proto": "error",
|
|
103
|
+
"yoda": "error",
|
|
104
|
+
"indent": ["error", 2, { SwitchCase: 1 }],
|
|
105
|
+
"object-curly-spacing": ["error", "always"],
|
|
106
|
+
|
|
107
|
+
"object-curly-newline": ["error", {
|
|
108
|
+
consistent: true,
|
|
109
|
+
multiline: true,
|
|
110
|
+
}],
|
|
111
|
+
|
|
112
|
+
"space-before-blocks": "error",
|
|
113
|
+
"space-before-function-paren": ["error", "always"],
|
|
114
|
+
"spaced-comment": "error",
|
|
115
|
+
"no-whitespace-before-property": "error",
|
|
116
|
+
|
|
117
|
+
"brace-style": ["error", "1tbs", {
|
|
118
|
+
allowSingleLine: false,
|
|
119
|
+
}],
|
|
120
|
+
|
|
121
|
+
"eol-last": ["error", "always"],
|
|
122
|
+
"func-call-spacing": ["error", "never"],
|
|
123
|
+
"semi": ["error", "always"],
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
/* c8 ignore stop */
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
type TBitBuffer = {
|
|
2
|
+
sizeInBits: number;
|
|
3
|
+
slice: (args: { startOffsetInBits: number, endOffsetInBits: number }) => TBitBuffer;
|
|
4
|
+
readBits: (args: { offsetInBits: number, lengthInBits: number }) => { data: Uint8Array, offsetInBits: number };
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const bitBufferFromUint8Array = ({
|
|
8
|
+
data,
|
|
9
|
+
offsetInBits: dataOffsetInBits,
|
|
10
|
+
sizeInBits
|
|
11
|
+
}: {
|
|
12
|
+
data: Uint8Array,
|
|
13
|
+
offsetInBits: number,
|
|
14
|
+
sizeInBits: number
|
|
15
|
+
}): TBitBuffer => {
|
|
16
|
+
|
|
17
|
+
const slice: TBitBuffer["slice"] = ({ startOffsetInBits, endOffsetInBits }) => {
|
|
18
|
+
const totalStartOffsetInBits = dataOffsetInBits + startOffsetInBits;
|
|
19
|
+
const totalEndOffsetInBits = dataOffsetInBits + endOffsetInBits;
|
|
20
|
+
|
|
21
|
+
const byteStartOffset = (totalStartOffsetInBits) / 8;
|
|
22
|
+
const byteEndOffset = (totalEndOffsetInBits) / 8;
|
|
23
|
+
|
|
24
|
+
const newData = data.slice(byteStartOffset, byteEndOffset);
|
|
25
|
+
const newOffsetInBits = totalStartOffsetInBits % 8;
|
|
26
|
+
|
|
27
|
+
return bitBufferFromUint8Array({
|
|
28
|
+
data: newData,
|
|
29
|
+
offsetInBits: newOffsetInBits,
|
|
30
|
+
sizeInBits: endOffsetInBits - startOffsetInBits
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const readBits: TBitBuffer["readBits"] = ({ offsetInBits: readOffsetInBits, lengthInBits }) => {
|
|
35
|
+
const totalOffsetInBits = dataOffsetInBits + readOffsetInBits;
|
|
36
|
+
const totalEndOffsetInBits = totalOffsetInBits + lengthInBits;
|
|
37
|
+
|
|
38
|
+
const byteOffset = (totalOffsetInBits) / 8;
|
|
39
|
+
const byteEndOffset = (totalEndOffsetInBits) / 8;
|
|
40
|
+
|
|
41
|
+
const bitData = data.slice(byteOffset, byteEndOffset);
|
|
42
|
+
const bitOffset = totalOffsetInBits % 8;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
offsetInBits: bitOffset,
|
|
46
|
+
data: bitData
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
sizeInBits,
|
|
52
|
+
readBits,
|
|
53
|
+
slice,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const createBitBuffer = ({ sizeInBits, offsetInBits }: { sizeInBits: number, offsetInBits: number }) => {
|
|
58
|
+
const byteLength = Math.ceil(sizeInBits / 8);
|
|
59
|
+
const buffer = new Uint8Array(byteLength);
|
|
60
|
+
return bitBufferFromUint8Array({ data: buffer, offsetInBits, sizeInBits });
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
createBitBuffer,
|
|
65
|
+
bitBufferFromUint8Array
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type {
|
|
69
|
+
TBitBuffer
|
|
70
|
+
};
|
package/lib/common.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type TDataModel = "LP64" | "ILP32";
|
|
2
|
+
type TCompiler = "gcc";
|
|
3
|
+
type TEndianness = "little" | "big";
|
|
4
|
+
|
|
5
|
+
type TAbi = {
|
|
6
|
+
endianness: TEndianness;
|
|
7
|
+
compiler: TCompiler;
|
|
8
|
+
dataModel: TDataModel;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const align = ({ offset, alignment }: { offset: number; alignment: number }): number => {
|
|
12
|
+
const remainder = offset % alignment;
|
|
13
|
+
if (remainder === 0) {
|
|
14
|
+
return offset;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return offset + (alignment - remainder);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type {
|
|
21
|
+
TDataModel,
|
|
22
|
+
TCompiler,
|
|
23
|
+
TEndianness,
|
|
24
|
+
|
|
25
|
+
TAbi
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
align
|
|
30
|
+
};
|
package/lib/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { define } from "./parser.ts";
|
|
2
|
+
import { types } from "./types/index.ts";
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
TAbi,
|
|
6
|
+
TCompiler,
|
|
7
|
+
TDataModel,
|
|
8
|
+
TEndianness,
|
|
9
|
+
} from "./common.ts";
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
define,
|
|
13
|
+
types
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
TAbi,
|
|
18
|
+
TEndianness,
|
|
19
|
+
TCompiler,
|
|
20
|
+
TDataModel
|
|
21
|
+
};
|