@rotu/structview 0.6.1

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/mod_test.ts ADDED
@@ -0,0 +1,319 @@
1
+ import {
2
+ bool,
3
+ defineArray,
4
+ defineStruct,
5
+ f16,
6
+ f32,
7
+ f64,
8
+ i16,
9
+ i32,
10
+ i64,
11
+ i8,
12
+ string,
13
+ Struct,
14
+ structDataView,
15
+ substruct,
16
+ u16,
17
+ u32,
18
+ u64,
19
+ u8,
20
+ } from "./mod.ts"
21
+
22
+ import {
23
+ assert,
24
+ assertEquals,
25
+ assertInstanceOf,
26
+ assertStrictEquals,
27
+ assertThrows,
28
+ fail,
29
+ } from "jsr:@std/assert@1"
30
+
31
+ class vec3_t extends defineStruct({
32
+ 0: f32(0),
33
+ 1: f32(4),
34
+ 2: f32(8),
35
+ }) {
36
+ get length() {
37
+ return 3
38
+ }
39
+ *[Symbol.iterator]() {
40
+ yield this[0]
41
+ yield this[1]
42
+ yield this[2]
43
+ }
44
+ }
45
+
46
+ Deno.test("struct has no enumerable properties", () => {
47
+ const s = new Struct({ buffer: new ArrayBuffer() })
48
+ for (const x in s) {
49
+ fail(`unexpected key '${x}'`)
50
+ }
51
+ })
52
+
53
+ Deno.test("struct", () => {
54
+ const s = new Struct({ buffer: new ArrayBuffer(10) })
55
+ assertInstanceOf(s, Struct)
56
+ assertEquals(String(s), "[object Struct]")
57
+ })
58
+
59
+ Deno.test("constructor", () => {
60
+ const buf = new ArrayBuffer(10)
61
+ const s = new Struct({ buffer: buf })
62
+ assertStrictEquals(structDataView(s).buffer, buf)
63
+ const s2 = new Struct({ byteLength: 13 })
64
+ assertEquals(structDataView(s2).byteLength, 13)
65
+ const s3 = new Struct({ byteLength: 5, byteOffset: 2 })
66
+ assertEquals(structDataView(s3).byteLength, 5)
67
+ assertEquals(structDataView(s3).byteOffset, 2)
68
+ assertInstanceOf(structDataView(s3).buffer, ArrayBuffer)
69
+
70
+ assertThrows(() => {
71
+ // @ts-expect-error invalid arg
72
+ new Struct()
73
+ })
74
+ assertThrows(() => {
75
+ // @ts-expect-error invalid arg
76
+ new Struct(null)
77
+ })
78
+ assertThrows(() => {
79
+ // @ts-expect-error invalid arg
80
+ new Struct({})
81
+ })
82
+ assertThrows(() => {
83
+ // @ts-expect-error invalid arg
84
+ new Struct({ byteOffset: 1 })
85
+ })
86
+ })
87
+
88
+ Deno.test("vec3", () => {
89
+ const bytes = new Uint8Array([
90
+ 0,
91
+ 0,
92
+ 0,
93
+ 0,
94
+ 0,
95
+ 0,
96
+ 0x28,
97
+ 0x42,
98
+ 0,
99
+ 0,
100
+ 0xc0,
101
+ 0x3f,
102
+ ])
103
+ const someVec = new vec3_t(bytes)
104
+ assert(someVec instanceof Struct)
105
+ assertEquals(Object.getOwnPropertyNames(someVec), [])
106
+ assertEquals(someVec[0], 0)
107
+ assertEquals(someVec[1], 42)
108
+ assertEquals(someVec[2], 1.5)
109
+
110
+ // trying to add an out of bound value errors
111
+ assertThrows(() => {
112
+ // @ts-expect-error assignment to undeclared property
113
+ someVec.blahbityblah = 5
114
+ })
115
+
116
+ assertThrows(() => {
117
+ // @ts-expect-error assignment to undeclared property
118
+ someVec[3] = 5
119
+ })
120
+
121
+ // can be converted to an array
122
+ assertEquals([...someVec], [0, 42, 1.5])
123
+
124
+ // can be mutated
125
+ someVec[0] = 42
126
+ // and mutations take
127
+ assertEquals(someVec[0], someVec[1])
128
+ // mutations are propagated to the underlying buffer
129
+ assertEquals(bytes.slice(0, 4), bytes.slice(4, 8))
130
+
131
+ assertEquals(Object.getOwnPropertyNames(someVec), [])
132
+ })
133
+
134
+ Deno.test("string", () => {
135
+ const Cls = defineStruct({
136
+ hello: string(10, 40),
137
+ })
138
+ const c = new Cls(new Uint8Array(60))
139
+ assertEquals(c.hello, "")
140
+ c.hello = "world!"
141
+ assertEquals(c.hello, "world!")
142
+ c.hello = "abc\0def"
143
+ assertEquals(c.hello, "abc\0def")
144
+ })
145
+
146
+ Deno.test("bool", () => {
147
+ const bytes = new Uint8Array([0, -1])
148
+ const Cls = defineStruct({
149
+ a: bool(0),
150
+ b: bool(1),
151
+ })
152
+ const c = new Cls(bytes)
153
+ assertEquals(c.a, false)
154
+ assertEquals(c.b, true)
155
+ c.a = true
156
+ assertEquals(c.a, true)
157
+ assertEquals(bytes[0], 1)
158
+ c.a = false
159
+ assertEquals(c.a, false)
160
+ assertEquals(bytes[0], 0)
161
+ })
162
+
163
+ Deno.test("substruct", () => {
164
+ const Point2D = defineStruct({ x: f32(0), y: f32(4) })
165
+ const Square = defineStruct({
166
+ size: f32(0),
167
+ center: substruct(Point2D, 4, 8),
168
+ })
169
+ const buf = new Float32Array([1, 3.5, 123])
170
+ const square = new Square(buf)
171
+ assertEquals(square.size, 1)
172
+ assertEquals(square.center.x, 3.5)
173
+ assertEquals(square.center.y, 123)
174
+ square.center.x = 18
175
+ assertEquals(buf[1], 18)
176
+ })
177
+
178
+ Deno.test("integers", () => {
179
+ const buf = new Uint8Array(16)
180
+ for (let i = 0; i < buf.length; ++i) {
181
+ buf[i] = i
182
+ }
183
+ const Integers = defineStruct({
184
+ as_i8: i8(1),
185
+ as_i16: i16(1),
186
+ as_i32: i32(1),
187
+ as_i64: i64(1),
188
+ as_u8: u8(1),
189
+ as_u16: u16(1),
190
+ as_u32: u32(1),
191
+ as_u64: u64(1),
192
+ })
193
+ const b = new Integers(buf)
194
+ assertEquals(b.as_i8, 0x01)
195
+ assertEquals(b.as_u8, 0x01)
196
+ assertEquals(b.as_i16, 0x0201)
197
+ assertEquals(b.as_u16, 0x0201)
198
+ assertEquals(b.as_i32, 0x04030201)
199
+ assertEquals(b.as_u32, 0x04030201)
200
+ assertEquals(b.as_i64, 0x0807060504030201n)
201
+ assertEquals(b.as_u64, 0x0807060504030201n)
202
+ })
203
+
204
+ Deno.test("floats", () => {
205
+ const Floats = defineStruct({
206
+ f16: f16(0),
207
+ f32: f32(4),
208
+ f64: f64(8),
209
+ })
210
+ const bytes = new Uint8Array(16)
211
+ const v = new Floats(bytes)
212
+ assertEquals(v.f16, 0)
213
+ assertEquals(v.f32, 0)
214
+ assertEquals(v.f64, 0)
215
+ v.f16 = 1 / 3
216
+ v.f32 = 1 / 3
217
+ v.f64 = 1 / 3
218
+ assertEquals(v.f16, Math.f16round(1 / 3))
219
+ assertEquals(v.f32, Math.fround(1 / 3))
220
+ assertEquals(v.f64, 1 / 3)
221
+ })
222
+
223
+ Deno.test("bad property descriptor", () => {
224
+ assertThrows(() => {
225
+ defineStruct({
226
+ a: { value: 10, get: () => 42 },
227
+ })
228
+ })
229
+ })
230
+
231
+ Deno.test("arrayRelative", () => {
232
+ const bytes = new Uint8Array(Array(255).keys())
233
+ const El = defineStruct({
234
+ x: u8(2),
235
+ })
236
+ const ElArray = defineArray({ struct: El, byteStride: 3, length: 3 })
237
+ const Cls = defineStruct({
238
+ els: substruct(ElArray, 5),
239
+ })
240
+ const instance = new Cls(bytes)
241
+ assertEquals(instance.els.element(0).x, 2 + 0 * 3 + 5)
242
+ assertEquals(instance.els.element(1).x, 2 + 1 * 3 + 5)
243
+ assertEquals(instance.els.element(2).x, 2 + 2 * 3 + 5)
244
+ })
245
+
246
+ Deno.test("structArray", () => {
247
+ const El = defineStruct({
248
+ x: u8(0),
249
+ y: u8(2),
250
+ })
251
+ const ElArray = defineArray({ struct: El, byteStride: 3, length: 2 })
252
+ const buf = new Uint8Array(6)
253
+ for (let i = 0; i < buf.length; ++i) {
254
+ buf[i] = i
255
+ }
256
+ const ar = new ElArray(buf)
257
+ assertEquals(ar.length, 2)
258
+ assertEquals(ar[0].x, 0x00)
259
+ assertEquals(ar[0].y, 0x02)
260
+ assertEquals(ar[1].x, 0x03)
261
+ assertEquals(ar[1].y, 0x05)
262
+
263
+ // and that iteration/unpacking works
264
+ const [el0, el1, el2] = ar
265
+ assertEquals(el0.x, 0x00)
266
+ assertEquals(el0.y, 0x02)
267
+ assertEquals(el1.x, 0x03)
268
+ assertEquals(el1.y, 0x05)
269
+ assertEquals(el2, undefined)
270
+ })
271
+
272
+ Deno.test("dynamicLength", () => {
273
+ const El = defineStruct({
274
+ x: i8(0),
275
+ y: i8(2),
276
+ })
277
+ const ElArray = defineArray({ struct: El, byteStride: 3 })
278
+ const buf1 = new Uint8Array(9)
279
+ const ar1 = new ElArray(buf1)
280
+ const buf2 = new Uint8Array(21)
281
+ const ar2 = new ElArray(buf2)
282
+
283
+ assertEquals(ar1.length, 3)
284
+ assertEquals(ar2.length, 7)
285
+
286
+ ar1[2].x = -21
287
+ assertEquals(buf1[6], 235)
288
+
289
+ ar2[6].y = -67
290
+ assertEquals(buf2[20], 189)
291
+ })
292
+
293
+ Deno.test("can copy", () => {
294
+ const bytes = new Uint8Array(48)
295
+ const Entree = defineStruct({
296
+ price: f32(0),
297
+ name: string(4, 12),
298
+ })
299
+ const Menu = defineArray({
300
+ struct: Entree,
301
+ byteStride: 16,
302
+ length: 3,
303
+ })
304
+
305
+ const myMenu = new Menu(bytes)
306
+ Object.assign(myMenu.element(0), { name: "garden salad", price: 4 })
307
+ Object.assign(myMenu.element(1), { name: "soup du jour", price: 2.5 })
308
+ Object.assign(myMenu.element(2), { name: "fries", price: 2.25 })
309
+
310
+ const bytesCopy = Uint8Array.from(bytes)
311
+ const menuCopy = new Menu(bytesCopy)
312
+ assertEquals(menuCopy.length, 3)
313
+ assertEquals(menuCopy.element(0).name, "garden salad")
314
+ assertEquals(menuCopy.element(0).price, 4)
315
+ assertEquals(menuCopy.element(1).name, "soup du jour")
316
+ assertEquals(menuCopy.element(1).price, 2.5)
317
+ assertEquals(menuCopy.element(2).name, "fries")
318
+ assertEquals(menuCopy.element(2).price, 2.25)
319
+ })
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@rotu/structview",
3
+ "version": "0.6.1",
4
+ "homepage": "https://jsr.io/@rotu/structview",
5
+ "type": "module",
6
+ "dependencies": {},
7
+ "exports": {
8
+ ".": {
9
+ "types": "./_dist/mod.d.ts",
10
+ "default": "./mod.js"
11
+ },
12
+ "./bigendian": {
13
+ "types": "./_dist/bigendian.d.ts",
14
+ "default": "./bigendian.js"
15
+ }
16
+ },
17
+ "_jsr_revision": 11
18
+ }