buffer-backed-object
Advanced tools
Comparing version 0.3.1 to 1.0.0
@@ -1,246 +0,344 @@ | ||
/** | ||
* Copyright 2020 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
import { expect, test } from "vitest"; | ||
import { | ||
ArrayOfBufferBackedObjects, | ||
BufferBackedObject, | ||
structSize, | ||
} from "./buffer-backed-object.js"; | ||
import * as BBO from "./buffer-backed-object.ts"; | ||
describe("structSize", function () { | ||
it("calculates the size of a struct correctly", function () { | ||
const size = structSize({ | ||
id: BufferBackedObject.Uint8(), | ||
x: BufferBackedObject.Float64(), | ||
y: BufferBackedObject.Int16(), | ||
z: BufferBackedObject.BigUint64(), | ||
_: BufferBackedObject.reserved(1), | ||
test("structSize calculates the size of a struct correctly", function () { | ||
{ | ||
const size = BBO.structSize({ | ||
id: BBO.Uint8(), | ||
}); | ||
expect(size).toBe(20); | ||
}); | ||
}); | ||
expect(size).toBe(1); | ||
} | ||
describe("ArrayOfBufferBackedObjects", function () { | ||
it("calculates length correctly", function () { | ||
// Add one stray byte | ||
const { buffer } = new Uint8Array([0, 0, 1, 0, 2, 0, 1]); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, { | ||
id: BufferBackedObject.Uint8(), | ||
_: BufferBackedObject.reserved(1), | ||
{ | ||
const size = BBO.structSize({ | ||
id: BBO.Uint16(), | ||
}); | ||
expect(aosv.length).toBe(3); | ||
}); | ||
expect(size).toBe(2); | ||
} | ||
it("decodes items correctly", function () { | ||
const descriptor = { | ||
id: BufferBackedObject.Uint8(), | ||
x: BufferBackedObject.Float64({ endianness: "big" }), | ||
y: BufferBackedObject.Float64({ endianness: "little" }), | ||
texture: BufferBackedObject.Int32(), | ||
_: BufferBackedObject.reserved(1), | ||
}; | ||
{ | ||
const size = BBO.structSize({ | ||
id: BBO.Uint16(), | ||
id2: BBO.Uint8(), | ||
}); | ||
expect(size).toBe(4); | ||
} | ||
const buffer = new ArrayBuffer(structSize(descriptor) * 2); | ||
const dataView = new DataView(buffer); | ||
dataView.setUint8(0 + 0, 1); | ||
dataView.setUint8(22 + 0, 2); | ||
dataView.setFloat64(0 + 1, 20, false); | ||
dataView.setFloat64(0 + 9, 30, true); | ||
dataView.setFloat64(22 + 1, 40, false); | ||
dataView.setFloat64(22 + 9, 50, true); | ||
dataView.setInt32(0 + 17, 9, true); | ||
dataView.setInt32(22 + 17, 10, true); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, descriptor); | ||
expect(aosv[0].id).toBe(1); | ||
expect(aosv[1].id).toBe(2); | ||
expect(aosv[0].x).toBe(20); | ||
expect(aosv[1].x).toBe(40); | ||
expect(aosv[0].y).toBe(30); | ||
expect(aosv[1].y).toBe(50); | ||
expect(aosv[0].texture).toBe(9); | ||
expect(aosv[1].texture).toBe(10); | ||
}); | ||
{ | ||
const size = BBO.structSize({ | ||
id: BBO.Uint8(), | ||
id2: BBO.Uint16(), | ||
}); | ||
expect(size).toBe(4); | ||
} | ||
it("can have an offset", function () { | ||
const descriptor = { | ||
id: BufferBackedObject.Uint8(), | ||
_: BufferBackedObject.reserved(1), | ||
}; | ||
const buffer = new ArrayBuffer(structSize(descriptor) * 4 + 1); | ||
const dataView = new DataView(buffer); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, descriptor, { | ||
byteOffset: 1, | ||
length: 2, | ||
{ | ||
const size = BBO.structSize({ | ||
id: BBO.Uint8(), | ||
id2: BBO.Uint32(), | ||
id3: BBO.Uint32(), | ||
}); | ||
expect(aosv.length).toBe(2); | ||
aosv[0].id = 1; | ||
aosv[1].id = 1; | ||
expect(dataView.getUint8(1)).toBe(1); | ||
}); | ||
expect(size).toBe(12); | ||
} | ||
it("handles nested Array of BBOs", function () { | ||
const descriptors = { | ||
id: BufferBackedObject.Uint8(), | ||
vertices: BufferBackedObject.NestedArrayOfBufferBackedObjects(3, { | ||
x: BufferBackedObject.Float64(), | ||
y: BufferBackedObject.Float64(), | ||
}), | ||
}; | ||
const buffer = new ArrayBuffer(structSize(descriptors) * 3); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, descriptors); | ||
expect(aosv.length).toBe(3); | ||
aosv[2].id = 1; | ||
aosv[2].vertices[0].x = 0; | ||
aosv[2].vertices[0].y = 1; | ||
aosv[2].vertices[1].x = 2; | ||
aosv[2].vertices[1].y = 3; | ||
aosv[2].vertices[2].x = 4; | ||
aosv[2].vertices[2].y = 5; | ||
expect(aosv.length).toBe(3); | ||
expect(JSON.stringify(aosv[2])).toBe( | ||
JSON.stringify({ | ||
id: 1, | ||
vertices: [ | ||
{ x: 0, y: 1 }, | ||
{ x: 2, y: 3 }, | ||
{ x: 4, y: 5 }, | ||
], | ||
}) | ||
); | ||
}); | ||
{ | ||
const size = BBO.structSize({ | ||
id: BBO.Uint8(), // 0...7 | ||
x: BBO.Float64({ endianness: "big" }), // 8...15 | ||
y: BBO.Float64({ endianness: "little" }), // 16...23 | ||
texture: BBO.Int32(), // 24...28 | ||
_: BBO.reserved(1), // 28...29 | ||
}); | ||
expect(size).toBe(32); | ||
} | ||
}); | ||
it("handles nested BBO", function () { | ||
const descriptors = { | ||
id: BufferBackedObject.Uint8(), | ||
pos: BufferBackedObject.NestedBufferBackedObject({ | ||
x: BufferBackedObject.Float64(), | ||
y: BufferBackedObject.Float64(), | ||
}), | ||
}; | ||
const buffer = new ArrayBuffer(structSize(descriptors) * 3); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, descriptors); | ||
test("ArrayOfBufferBackedObjects calculates length correctly", function () { | ||
{ | ||
const buffer = new ArrayBuffer(7); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, { | ||
id: BBO.Uint8(), | ||
_: BBO.reserved(1), | ||
}); | ||
expect(aosv.length).toBe(3); | ||
aosv[2].id = 1; | ||
aosv[2].pos.x = 3; | ||
aosv[2].pos.y = 2; | ||
expect(aosv.length).toBe(3); | ||
expect(JSON.stringify(aosv[2])).toBe( | ||
JSON.stringify({ id: 1, pos: { x: 3, y: 2 } }) | ||
); | ||
expect(JSON.stringify(aosv)).toBe( | ||
JSON.stringify([ | ||
{ id: 0, pos: { x: 0, y: 0 } }, | ||
{ id: 0, pos: { x: 0, y: 0 } }, | ||
{ id: 1, pos: { x: 3, y: 2 } }, | ||
]) | ||
); | ||
}); | ||
} | ||
it("can return the buffer", function () { | ||
const buffer = new ArrayBuffer(22); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, { | ||
x: BufferBackedObject.Uint8(), | ||
{ | ||
const buffer = new ArrayBuffer(47); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, { | ||
id: BBO.Uint8(), | ||
i2: BBO.BigInt64(), | ||
}); | ||
expect(aosv.buffer).toBe(buffer); | ||
}); | ||
expect(aosv.length).toBe(2); | ||
} | ||
}); | ||
it("encodes to JSON", function () { | ||
const { buffer } = new Uint8Array([0, 0, 1, 0, 2, 0, 1]); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, { | ||
id: BufferBackedObject.Uint8(), | ||
_: BufferBackedObject.reserved(1), | ||
}); | ||
expect(JSON.stringify(aosv)).toBe( | ||
JSON.stringify([{ id: 0 }, { id: 1 }, { id: 2 }]) | ||
); | ||
}); | ||
test("ArrayOfBufferBackedObjects decodes items correctly", function () { | ||
const descriptor = { | ||
id: BBO.Uint8(), // 0...7 | ||
x: BBO.Float64({ endianness: "big" }), // 8...15 | ||
y: BBO.Float64({ endianness: "little" }), // 16...23 | ||
texture: BBO.Int32(), // 24...27 | ||
_: BBO.reserved(1), // 28...29 | ||
}; | ||
it("can write items", function () { | ||
const descriptor = { | ||
id: BufferBackedObject.Uint8(), | ||
x: BufferBackedObject.Float64(), | ||
_: BufferBackedObject.reserved(1), | ||
}; | ||
const buffer = new ArrayBuffer(structSize(descriptor) * 2); | ||
const dataView = new DataView(buffer); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, descriptor); | ||
aosv[0].x = 10; | ||
aosv[1].x = 20; | ||
expect(dataView.getFloat64(1, true)).toBe(10); | ||
expect(dataView.getFloat64(11, true)).toBe(20); | ||
}); | ||
console.log(BBO.structSize(descriptor), BBO.structAlign(descriptor)); | ||
const buffer = new ArrayBuffer(BBO.structSize(descriptor) * 2); | ||
const dataView = new DataView(buffer); | ||
dataView.setUint8(0 + 0, 1); | ||
dataView.setUint8(32 + 0, 2); | ||
dataView.setFloat64(0 + 8, 20, false); | ||
dataView.setFloat64(0 + 16, 30, true); | ||
dataView.setFloat64(32 + 8, 40, false); | ||
dataView.setFloat64(32 + 16, 50, true); | ||
dataView.setInt32(0 + 24, 9, true); | ||
dataView.setInt32(32 + 24, 10, true); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, descriptor); | ||
expect(aosv[0].id).toBe(1); | ||
expect(aosv[1].id).toBe(2); | ||
expect(aosv[0].x).toBe(20); | ||
expect(aosv[1].x).toBe(40); | ||
expect(aosv[0].y).toBe(30); | ||
expect(aosv[1].y).toBe(50); | ||
expect(aosv[0].texture).toBe(9); | ||
expect(aosv[1].texture).toBe(10); | ||
}); | ||
it("handles filter()", function () { | ||
const descriptor = { | ||
id: BufferBackedObject.Uint8(), | ||
data: BufferBackedObject.Uint8(), | ||
}; | ||
const { buffer } = new Uint8Array([0, 10, 1, 11, 2, 12, 3, 13]); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, descriptor); | ||
const even = aosv.filter(({ id }) => id % 2 == 0); | ||
expect(even.length).toBe(2); | ||
even[1].data = 99; | ||
expect(aosv[2].data).toBe(99); | ||
test("ArrayOfBufferBackedObjects can have an offset", function () { | ||
const descriptor = { | ||
id: BBO.Uint8(), | ||
_: BBO.reserved(1), | ||
}; | ||
const buffer = new ArrayBuffer(BBO.structSize(descriptor) * 4 + 1); | ||
const dataView = new DataView(buffer); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, descriptor, { | ||
byteOffset: 1, | ||
length: 2, | ||
}); | ||
expect(aosv.length).toBe(2); | ||
aosv[0].id = 1; | ||
aosv[1].id = 1; | ||
expect(dataView.getUint8(1)).toBe(1); | ||
}); | ||
it("rejects new properties", function () { | ||
const descriptor = { | ||
id: BufferBackedObject.Uint8(), | ||
data: BufferBackedObject.Uint8(), | ||
}; | ||
const { buffer } = new Uint8Array([0, 10, 1, 11, 2, 12, 3, 13]); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, descriptor); | ||
expect(() => { | ||
aosv[0].lol = 4; | ||
}).toThrow(); | ||
test("ArrayOfBufferBackedObjects handles nested Array of BBOs", function () { | ||
const descriptors = { | ||
id: BBO.Uint8(), | ||
vertices: BBO.NestedArrayOfBufferBackedObjects(3, { | ||
x: BBO.Float64(), | ||
y: BBO.Float64(), | ||
}), | ||
}; | ||
const buffer = new ArrayBuffer(BBO.structSize(descriptors) * 3); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, descriptors); | ||
expect(aosv.length).toBe(3); | ||
aosv[2].id = 1; | ||
aosv[2].vertices[0].x = 0; | ||
aosv[2].vertices[0].y = 1; | ||
aosv[2].vertices[1].x = 2; | ||
aosv[2].vertices[1].y = 3; | ||
aosv[2].vertices[2].x = 4; | ||
aosv[2].vertices[2].y = 5; | ||
expect(aosv.length).toBe(3); | ||
expect(JSON.stringify(aosv[2])).toBe( | ||
JSON.stringify({ | ||
id: 1, | ||
vertices: [ | ||
{ x: 0, y: 1 }, | ||
{ x: 2, y: 3 }, | ||
{ x: 4, y: 5 }, | ||
], | ||
}) | ||
); | ||
}); | ||
test("ArrayOfBufferBackedObjects handles nested BBO", function () { | ||
const descriptors = { | ||
id: BBO.Uint8(), | ||
pos: BBO.NestedBufferBackedObject({ | ||
x: BBO.Float64(), | ||
y: BBO.Float64(), | ||
}), | ||
}; | ||
const buffer = new ArrayBuffer(BBO.structSize(descriptors) * 3); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, descriptors); | ||
expect(aosv.length).toBe(3); | ||
aosv[2].id = 1; | ||
aosv[2].pos.x = 3; | ||
aosv[2].pos.y = 2; | ||
expect(aosv.length).toBe(3); | ||
expect(JSON.stringify(aosv[2])).toBe( | ||
JSON.stringify({ id: 1, pos: { x: 3, y: 2 } }) | ||
); | ||
expect(JSON.stringify(aosv)).toBe( | ||
JSON.stringify([ | ||
{ id: 0, pos: { x: 0, y: 0 } }, | ||
{ id: 0, pos: { x: 0, y: 0 } }, | ||
{ id: 1, pos: { x: 3, y: 2 } }, | ||
]) | ||
); | ||
}); | ||
test("ArrayOfBufferBackedObjects handles nested BBO with nested arrays", function () { | ||
const PathNodeDescription = { | ||
type: BBO.Uint8(), | ||
x: BBO.Uint32(), | ||
y: BBO.Uint32(), | ||
}; | ||
const EnemyDescription = { | ||
type: BBO.Uint8(), | ||
x: BBO.Float32(), | ||
y: BBO.Float32(), | ||
path: BBO.NestedArrayOfBufferBackedObjects(1, PathNodeDescription), | ||
}; | ||
const GameStateDescription = { | ||
gametime: BBO.Uint32(), | ||
season: BBO.Uint8(), | ||
enemies: BBO.NestedArrayOfBufferBackedObjects(1, EnemyDescription), | ||
}; | ||
const gameStateBuffer = new ArrayBuffer(BBO.structSize(GameStateDescription)); | ||
const gameState = BBO.BufferBackedObject( | ||
gameStateBuffer, | ||
GameStateDescription | ||
); | ||
gameState.gametime = 12345; | ||
gameState.season = 3; | ||
expect(gameState.enemies.length).toBe(1); | ||
gameState.enemies[0].type = 1; | ||
gameState.enemies[0].x = 512; | ||
gameState.enemies[0].y = 0; | ||
expect(gameState.enemies.length).toBe(1); | ||
expect(JSON.stringify(gameState.enemies[0])).toBe( | ||
JSON.stringify({ type: 1, x: 512, y: 0, path: [{ type: 0, x: 0, y: 0 }] }) | ||
); | ||
expect(JSON.stringify(gameState)).toBe( | ||
JSON.stringify({ | ||
gametime: 12345, | ||
season: 3, | ||
enemies: [{ type: 1, x: 512, y: 0, path: [{ type: 0, x: 0, y: 0 }] }], | ||
}) | ||
); | ||
}); | ||
test("ArrayOfBufferBackedObjects can return the buffer", function () { | ||
const buffer = new ArrayBuffer(22); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, { | ||
x: BBO.Uint8(), | ||
}); | ||
expect(aosv.buffer).toBe(buffer); | ||
}); | ||
it("can handle UTF8 strings", function () { | ||
const descriptor = { | ||
name: BufferBackedObject.UTF8String(32), | ||
id: BufferBackedObject.Uint8(), | ||
}; | ||
const buffer = new ArrayBuffer(structSize(descriptor) * 2); | ||
const aosv = new ArrayOfBufferBackedObjects(buffer, descriptor); | ||
aosv[0].name = "Surma"; | ||
aosv[1].name = "Jason"; | ||
const name1 = new TextDecoder().decode(new Uint8Array(buffer, 0, 5)); | ||
const name2 = new TextDecoder().decode(new Uint8Array(buffer, 33, 5)); | ||
expect(name1).toBe("Surma"); | ||
expect(name2).toBe("Jason"); | ||
test("ArrayOfBufferBackedObjects encodes to JSON", function () { | ||
const { buffer } = new Uint8Array([0, 0, 1, 0, 2, 0, 1]); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, { | ||
id: BBO.Uint8(), | ||
_: BBO.reserved(1), | ||
}); | ||
expect(JSON.stringify(aosv)).toBe( | ||
JSON.stringify([{ id: 0 }, { id: 1 }, { id: 2 }]) | ||
); | ||
}); | ||
describe("StructuredDataView", function () { | ||
it("decodes items correctly", function () { | ||
const descriptor = { | ||
id: BufferBackedObject.Uint8(), | ||
x: BufferBackedObject.Float64({ endianness: "big" }), | ||
y: BufferBackedObject.Float64({ endianness: "little" }), | ||
texture: BufferBackedObject.Int32(), | ||
_: BufferBackedObject.reserved(1), | ||
}; | ||
test("ArrayOfBufferBackedObjects can write items", function () { | ||
const descriptor = { | ||
id: BBO.Uint8(), | ||
x: BBO.Float64(), | ||
_: BBO.reserved(1), | ||
}; | ||
const buffer = new ArrayBuffer(BBO.structSize(descriptor) * 2); | ||
const dataView = new DataView(buffer); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, descriptor); | ||
aosv[0].x = 10; | ||
aosv[1].x = 20; | ||
expect(dataView.getFloat64(8, true)).toBe(10); | ||
expect(dataView.getFloat64(32, true)).toBe(20); | ||
}); | ||
const buffer = new ArrayBuffer(structSize(descriptor)); | ||
const dataView = new DataView(buffer); | ||
dataView.setUint8(0 + 0, 1); | ||
dataView.setFloat64(0 + 1, 20, false); | ||
dataView.setFloat64(0 + 9, 30, true); | ||
dataView.setInt32(0 + 17, 9, true); | ||
const sdv = new BufferBackedObject(buffer, descriptor); | ||
expect(sdv.id).toBe(1); | ||
expect(sdv.x).toBe(20); | ||
expect(sdv.y).toBe(30); | ||
expect(sdv.texture).toBe(9); | ||
}); | ||
test("ArrayOfBufferBackedObjects handles filter()", function () { | ||
const descriptor = { | ||
id: BBO.Uint8(), | ||
data: BBO.Uint8(), | ||
}; | ||
const { buffer } = new Uint8Array([0, 10, 1, 11, 2, 12, 3, 13]); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, descriptor); | ||
const even = aosv.filter(({ id }) => id % 2 == 0); | ||
expect(even.length).toBe(2); | ||
even[1].data = 99; | ||
expect(aosv[2].data).toBe(99); | ||
}); | ||
test("ArrayOfBufferBackedObjects rejects new properties", function () { | ||
const descriptor = { | ||
id: BBO.Uint8(), | ||
data: BBO.Uint8(), | ||
}; | ||
const { buffer } = new Uint8Array([0, 10, 1, 11, 2, 12, 3, 13]); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, descriptor); | ||
expect(() => { | ||
aosv[0].lol = 4; | ||
}).toThrow(); | ||
}); | ||
test("ArrayOfBufferBackedObjects can handle UTF8 strings", function () { | ||
const descriptor = { | ||
name: BBO.UTF8String(32), | ||
id: BBO.Uint8(), | ||
}; | ||
const buffer = new ArrayBuffer(BBO.structSize(descriptor) * 2); | ||
const aosv = BBO.ArrayOfBufferBackedObjects(buffer, descriptor); | ||
aosv[0].name = "Surma"; | ||
aosv[1].name = "Jason"; | ||
const name1 = new TextDecoder().decode(new Uint8Array(buffer, 0, 5)); | ||
const name2 = new TextDecoder().decode(new Uint8Array(buffer, 33, 5)); | ||
expect(name1).toBe("Surma"); | ||
expect(name2).toBe("Jason"); | ||
}); | ||
test("BufferBackedObject decodes items correctly", function () { | ||
const descriptor = { | ||
id: BBO.Uint8(), | ||
x: BBO.Float64({ endianness: "big" }), | ||
y: BBO.Float64({ endianness: "little" }), | ||
texture: BBO.Int32(), | ||
_: BBO.reserved(1), | ||
}; | ||
const buffer = new ArrayBuffer(BBO.structSize(descriptor)); | ||
const dataView = new DataView(buffer); | ||
dataView.setUint8(0 + 0, 1); | ||
dataView.setFloat64(0 + 8, 20, false); | ||
dataView.setFloat64(0 + 16, 30, true); | ||
dataView.setInt32(0 + 24, 9, true); | ||
const sdv = BBO.BufferBackedObject(buffer, descriptor); | ||
expect(sdv.id).toBe(1); | ||
expect(sdv.x).toBe(20); | ||
expect(sdv.y).toBe(30); | ||
expect(sdv.texture).toBe(9); | ||
}); | ||
test("BufferBackedObject decodes items correctly with custom align", function () { | ||
const descriptor = { | ||
id: BBO.Uint8(), | ||
x: BBO.Float64({ endianness: "big", align: 1 }), | ||
y: BBO.Float64({ endianness: "little", align: 1 }), | ||
texture: BBO.Int32({ align: 1 }), | ||
_: BBO.reserved(1), | ||
}; | ||
const buffer = new ArrayBuffer(BBO.structSize(descriptor)); | ||
const dataView = new DataView(buffer); | ||
dataView.setUint8(0 + 0, 1); | ||
dataView.setFloat64(0 + 1, 20, false); | ||
dataView.setFloat64(0 + 9, 30, true); | ||
dataView.setInt32(0 + 17, 9, true); | ||
const sdv = BBO.BufferBackedObject(buffer, descriptor); | ||
expect(sdv.id).toBe(1); | ||
expect(sdv.x).toBe(20); | ||
expect(sdv.y).toBe(30); | ||
expect(sdv.texture).toBe(9); | ||
}); |
@@ -1,14 +0,13 @@ | ||
import {assert, IsExact} from "conditional-type-checks"; | ||
import { assert, IsExact } from "conditional-type-checks"; | ||
import {BufferBackedObject, ArrayOfBufferBackedObjects} from "."; | ||
import * as BBO from "./buffer-backed-object.js"; | ||
const view = new BufferBackedObject(null as any, { | ||
id: BufferBackedObject.Uint16({ endianness: "little" }), | ||
name: BufferBackedObject.UTF8String(32), | ||
data: BufferBackedObject.ArrayBuffer(100), | ||
position: BufferBackedObject.NestedBufferBackedObject({ | ||
x: BufferBackedObject.Float64(), | ||
y: BufferBackedObject.Float64(), | ||
z: BufferBackedObject.Float64(), | ||
}) | ||
const view = BBO.BufferBackedObject(null as any, { | ||
id: BBO.Uint16({ endianness: "little" }), | ||
name: BBO.UTF8String(32), | ||
position: BBO.NestedBufferBackedObject({ | ||
x: BBO.Float64(), | ||
y: BBO.Float64(), | ||
z: BBO.Float64(), | ||
}), | ||
}); | ||
@@ -18,11 +17,10 @@ | ||
assert<IsExact<typeof view.name, string>>(true); | ||
assert<IsExact<typeof view.data, ArrayBuffer>>(true); | ||
assert<IsExact<typeof view.position.x, number>>(true); | ||
const descriptors = { | ||
id: BufferBackedObject.Uint16({ endianness: "little" }), | ||
name: BufferBackedObject.UTF8String(32), | ||
id: BBO.Uint16({ endianness: "little" }), | ||
name: BBO.UTF8String(32), | ||
}; | ||
const view2 = new ArrayOfBufferBackedObjects(null as any, descriptors); | ||
const view2 = BBO.ArrayOfBufferBackedObjects(null as any, descriptors); | ||
assert<IsExact<typeof view2, Array<{id: number, name: string}>>>(true); | ||
assert<IsExact<typeof view2, Array<{ id: number; name: string }>>>(true); |
@@ -1,79 +0,45 @@ | ||
/** | ||
* Copyright 2020 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
export type Descriptor<T = any> = { | ||
size: number; | ||
get(dataview: DataView, byteOffset: number): T; | ||
set(dataview: DataView, byteOffset: number, value: T): void; | ||
}; | ||
export type Descriptors = { | ||
[key: string]: Descriptor<any>; | ||
}; | ||
export type DecodedBuffer<E extends Descriptors> = { | ||
[K in keyof E]: ReturnType<E[K]["get"]>; | ||
}; | ||
export function structSize(descriptors: Descriptors): number; | ||
export interface BufferBackedObjectOptions { | ||
byteOffset?: number; | ||
declare module "buffer-backed-object" { | ||
export type Descriptor<T = any> = { | ||
size: number; | ||
align?: number; | ||
get(dataview: DataView, byteOffset: number): T; | ||
set(dataview: DataView, byteOffset: number, value: T): void; | ||
}; | ||
export type Descriptors<T = Descriptor<any>> = { | ||
[key: string]: T; | ||
}; | ||
export type DecodedBuffer<E extends Descriptors> = { | ||
[K in keyof E]: ReturnType<E[K]["get"]>; | ||
}; | ||
export function structSize(descriptors: Descriptors): number; | ||
export function structAlign(descriptors: Descriptors): number; | ||
export function ArrayOfBufferBackedObjects<T extends Descriptors>(buffer: ArrayBuffer, descriptors: T, { byteOffset, length, align }?: { | ||
byteOffset?: number; | ||
length?: number; | ||
align?: number; | ||
}): Array<DecodedBuffer<T>>; | ||
export function BufferBackedObject<T extends Descriptors>(buffer: ArrayBuffer, descriptors: T, { byteOffset, align }?: { | ||
byteOffset?: number; | ||
align?: number; | ||
}): DecodedBuffer<T>; | ||
export interface EndiannessOption { | ||
endianness: "little" | "big"; | ||
} | ||
export interface AlignOption { | ||
align: number; | ||
} | ||
export function Uint16({ endianness, align, }?: Partial<EndiannessOption & AlignOption>): Descriptor<number>; | ||
export function Uint32({ endianness, align, }?: Partial<EndiannessOption & AlignOption>): Descriptor<number>; | ||
export function Int16({ endianness, align, }?: Partial<EndiannessOption & AlignOption>): Descriptor<number>; | ||
export function Int32({ endianness, align, }?: Partial<EndiannessOption & AlignOption>): Descriptor<number>; | ||
export function Float32({ endianness, align, }?: Partial<EndiannessOption & AlignOption>): Descriptor<number>; | ||
export function Float64({ endianness, align, }?: Partial<EndiannessOption & AlignOption>): Descriptor<number>; | ||
export function BigInt64({ endianness, align, }?: Partial<EndiannessOption & AlignOption>): Descriptor<bigint>; | ||
export function BigUint64({ endianness, align, }?: Partial<EndiannessOption & AlignOption>): Descriptor<bigint>; | ||
export function Uint8(): Descriptor<number>; | ||
export function Int8(): Descriptor<number>; | ||
export function NestedBufferBackedObject<T extends Descriptors>(descriptors: T): Descriptor<DecodedBuffer<T>>; | ||
export function NestedArrayOfBufferBackedObjects<T extends Descriptors>(length: number, descriptors: T): Descriptor<Array<DecodedBuffer<T>>>; | ||
export function UTF8String(maxBytes: number): Descriptor<string>; | ||
export function reserved(size: number): Descriptor<void>; | ||
} | ||
type EndianOption = { | ||
endianness?: "big" | "little"; | ||
}; | ||
export const BufferBackedObject: { | ||
new <T extends Descriptors>( | ||
buffer: ArrayBuffer, | ||
descriptor: T, | ||
opts?: BufferBackedObjectOptions | ||
): DecodedBuffer<T>; | ||
reserved(numBytes: number): Descriptor<number>; | ||
Int8(): Descriptor<number>; | ||
Uint8(): Descriptor<number>; | ||
Int16(options?: EndianOption): Descriptor<number>; | ||
Uint16(options?: EndianOption): Descriptor<number>; | ||
Int32(options?: EndianOption): Descriptor<number>; | ||
Uint32(options?: EndianOption): Descriptor<number>; | ||
BigInt64(options?: EndianOption): Descriptor<number>; | ||
BigUint64(options?: EndianOption): Descriptor<number>; | ||
Float32(options?: EndianOption): Descriptor<number>; | ||
Float64(options?: EndianOption): Descriptor<number>; | ||
UTF8String(maxBytes: number): Descriptor<string>; | ||
ArrayBuffer(size: number): Descriptor<ArrayBuffer>; | ||
NestedBufferBackedObject<E extends Descriptors>( | ||
descriptors: E | ||
): Descriptor<DecodedBuffer<E>>; | ||
NestedArrayOfBufferBackedObjects<A extends Descriptors>( | ||
numItems: number, | ||
descriptors: A | ||
): Descriptor<Array<DecodedBuffer<A>>>; | ||
}; | ||
export interface ArrayOfBufferBackedObjectsOptions { | ||
byteOffset?: number; | ||
length?: number; | ||
} | ||
export const ArrayOfBufferBackedObjects: { | ||
new <T extends Descriptors>( | ||
buffer: ArrayBuffer, | ||
descriptors: T, | ||
options?: ArrayOfBufferBackedObjectsOptions | ||
): Array<DecodedBuffer<T>>; | ||
}; | ||
export default BufferBackedObject; |
@@ -1,2 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).bufferBackedObject={})}(this,function(e){function t(e){return"symbol"==typeof e||isNaN(e)}function n(e){for(var t=0,n=0,r=Object.values(e);n<r.length;n++)t+=r[n].size;return t}function r(e,n,r){var i=void 0===r?{}:r,f=i.byteOffset,o=void 0===f?0:f,u=i.length,c=void 0===u?0:u,s=new DataView(e,o),a=0;n=Object.assign({},n);for(var b=0,d=Object.entries(n);b<d.length;b++){var g=d[b],l=g[1];n[g[0]]=Object.assign({},l,{offset:a}),a+=l.size}return c||(c=Math.floor((e.byteLength-o)/a)),new Proxy(new Array(c),{has:function(e,n){return t(n)?"buffer"===n||n in e:n<c},get:function(r,i,f){if("buffer"===i)return e;if(t(i)){var o=r[i];return"function"==typeof o&&(o=o.bind(f)),o}var u=parseInt(i),c=u*a;if(!(u>=r.length)){if(!r[u]){r[u]={};for(var b=function(){var e=g[d],t=e[1];if(!("get"in t))return"continue";Object.defineProperty(r[u],e[0],{enumerable:!0,get:function(){return t.get(s,c+t.offset)},set:function(e){return t.set(s,c+t.offset,e)}})},d=0,g=Object.entries(n);d<g.length;d++)b();Object.freeze(r[u])}return r[u]}}})}function i(e,t,n){var i=(void 0===n?{}:n).byteOffset;return r(e,t,{byteOffset:void 0===i?0:i})[0]}"object"!=typeof globalThis&&(Object.prototype.__defineGetter__("__magic__",function(){return this}),__magic__.globalThis=__magic__,delete Object.prototype.__magic__),["Uint16","Uint32","Int16","Int32","Float32","Float64","BigInt64","BigUint64"].forEach(function(e){i[e]=function(t){var n=(void 0===t?{}:t).endianness,r=void 0===n?"little":n;if("big"!==r&&"little"!==r)throw Error("Endianness needs to be either 'big' or 'little'");var i="little"===r;return{size:globalThis[e+"Array"].BYTES_PER_ELEMENT,get:function(t,n){return t["get"+e](n,i)},set:function(t,n,r){return t["set"+e](n,r,i)}}}}),i.Uint8=function(){return{size:1,get:function(e,t){return e.getUint8(t)},set:function(e,t,n){return e.setUint8(t,n)}}},i.Int8=function(){return{size:1,get:function(e,t){return e.getInt8(t)},set:function(e,t,n){return e.setInt8(t,n)}}},i.NestedBufferBackedObject=function(e){return{size:n(e),get:function(t,n){return new r(t.buffer,e,{byteOffset:n,length:1})[0]},set:function(e,t,n){throw Error("Can’t set an entire struct")}}},i.NestedArrayOfBufferBackedObjects=function(e,t){return{size:n(t)*e,get:function(n,i){return new r(n.buffer,t,{byteOffset:i,length:e})},set:function(e,t,n){throw Error("Can’t set an entire array")}}},i.UTF8String=function(e){return{size:e,get:function(t,n){return(new TextDecoder).decode(new Uint8Array(t.buffer,n,e)).replace(/\u0000+$/,"")},set:function(t,n,r){var i=(new TextEncoder).encode(r),f=new Uint8Array(t.buffer,n,e);f.fill(0),f.set(i.subarray(0,e))}}},i.reserved=function(e){return{size:e}},e.ArrayOfBufferBackedObjects=r,e.BufferBackedObject=i,e.default=i,e.structSize=n}); | ||
//# sourceMappingURL=buffer-backed-object.umd.js.map | ||
(function(l,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(l=typeof globalThis<"u"?globalThis:l||self,s(l["buffer-backed-object"]={}))})(this,function(l){"use strict";function s(t){return typeof t=="symbol"?!1:!isNaN(t)}function b(t,e){let n=t-t%e;return t%e!=0&&(n+=e),n}function y(t){let e=0;for(const{align:n=1,size:i}of Object.values(t))e=b(e,n)+i;return e=b(e,O(t)),e}function O(t){return Math.max(...Object.values(t).map(e=>e.align??1))}function d(t,e,{byteOffset:n=0,length:i=0,align:r=O(e)}={}){const f=new DataView(t,n);let E=0;const B={...e};for(const[u,o]of Object.entries(B))B[u]={...o,offset:b(E,o.align??1)},E=B[u].offset+o.size;return E=b(E,r),i||(i=Math.floor((t.byteLength-n)/E)),new Proxy(new Array(i),{has(u,o){return s(o)?o<i:o==="buffer"?!0:o in u},get(u,o,N){if(o==="buffer")return t;if(!s(o)){let g=u[o];return typeof g=="function"&&(g=g.bind(N)),g}const c=parseInt(o),h=c*E;if(!(c>=u.length)){if(!u[c]){u[c]={};for(const[g,a]of Object.entries(B))"get"in a&&Object.defineProperty(u[c],g,{enumerable:!0,get(){return a.get(f,h+a.offset)},set(R){return a.set(f,h+a.offset,R)}});Object.freeze(u[c])}return u[c]}}})}function T(t,e,{byteOffset:n=0,align:i=1}={}){return d(t,e,{byteOffset:n,align:i})[0]}function U({endianness:t="little",align:e=2}={}){if(t!=="big"&&t!=="little")throw Error("Endianness needs to be either 'big' or 'little'");const n=t==="little";return{align:e,size:Uint16Array.BYTES_PER_ELEMENT,get:(i,r)=>i.getUint16(r,n),set:(i,r,f)=>i.setUint16(r,f,n)}}function w({endianness:t="little",align:e=4}={}){if(t!=="big"&&t!=="little")throw Error("Endianness needs to be either 'big' or 'little'");const n=t==="little";return{align:e,size:Uint32Array.BYTES_PER_ELEMENT,get:(i,r)=>i.getUint32(r,n),set:(i,r,f)=>i.setUint32(r,f,n)}}function I({endianness:t="little",align:e=2}={}){if(t!=="big"&&t!=="little")throw Error("Endianness needs to be either 'big' or 'little'");const n=t==="little";return{align:e,size:Int16Array.BYTES_PER_ELEMENT,get:(i,r)=>i.getInt16(r,n),set:(i,r,f)=>i.setInt16(r,f,n)}}function j({endianness:t="little",align:e=4}={}){if(t!=="big"&&t!=="little")throw Error("Endianness needs to be either 'big' or 'little'");const n=t==="little";return{align:e,size:Int32Array.BYTES_PER_ELEMENT,get:(i,r)=>i.getInt32(r,n),set:(i,r,f)=>i.setInt32(r,f,n)}}function z({endianness:t="little",align:e=4}={}){if(t!=="big"&&t!=="little")throw Error("Endianness needs to be either 'big' or 'little'");const n=t==="little";return{align:e,size:Float32Array.BYTES_PER_ELEMENT,get:(i,r)=>i.getFloat32(r,n),set:(i,r,f)=>i.setFloat32(r,f,n)}}function A({endianness:t="little",align:e=8}={}){if(t!=="big"&&t!=="little")throw Error("Endianness needs to be either 'big' or 'little'");const n=t==="little";return{align:e,size:Float64Array.BYTES_PER_ELEMENT,get:(i,r)=>i.getFloat64(r,n),set:(i,r,f)=>i.setFloat64(r,f,n)}}function _({endianness:t="little",align:e=8}={}){if(t!=="big"&&t!=="little")throw Error("Endianness needs to be either 'big' or 'little'");const n=t==="little";return{align:e,size:BigInt64Array.BYTES_PER_ELEMENT,get:(i,r)=>i.getBigInt64(r,n),set:(i,r,f)=>i.setBigInt64(r,f,n)}}function S({endianness:t="little",align:e=8}={}){if(t!=="big"&&t!=="little")throw Error("Endianness needs to be either 'big' or 'little'");const n=t==="little";return{align:e,size:BigUint64Array.BYTES_PER_ELEMENT,get:(i,r)=>i.getBigUint64(r,n),set:(i,r,f)=>i.setBigUint64(r,f,n)}}function F(){return{align:1,size:1,get:(t,e)=>t.getUint8(e),set:(t,e,n)=>t.setUint8(e,n)}}function M(){return{align:1,size:1,get:(t,e)=>t.getInt8(e),set:(t,e,n)=>t.setInt8(e,n)}}function P(t){const e=y(t);return{align:Object.values(t)[0].align??1,size:e,get:(n,i)=>d(n.buffer,t,{byteOffset:i,length:1})[0],set:(n,i,r)=>{throw Error("Can’t set an entire struct")}}}function v(t,e){const n=y(e)*t;return{align:Object.values(e)[0].align??1,size:n,get:(i,r)=>d(i.buffer,e,{byteOffset:r+i.byteOffset,length:t}),set:(i,r,f)=>{throw Error("Can’t set an entire array")}}}function k(t){return{align:1,size:t,get:(e,n)=>new TextDecoder().decode(new Uint8Array(e.buffer,n,t)).replace(/\u0000+$/,""),set:(e,n,i)=>{const r=new TextEncoder().encode(i),f=new Uint8Array(e.buffer,n,t);f.fill(0),f.set(r.subarray(0,t))}}}function L(t){return{align:1,size:t,get(){},set(){}}}l.ArrayOfBufferBackedObjects=d,l.BigInt64=_,l.BigUint64=S,l.BufferBackedObject=T,l.Float32=z,l.Float64=A,l.Int16=I,l.Int32=j,l.Int8=M,l.NestedArrayOfBufferBackedObjects=v,l.NestedBufferBackedObject=P,l.UTF8String=k,l.Uint16=U,l.Uint32=w,l.Uint8=F,l.reserved=L,l.structAlign=O,l.structSize=y,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}); |
{ | ||
"name": "buffer-backed-object", | ||
"version": "0.3.1", | ||
"version": "1.0.0", | ||
"description": "", | ||
"repository": "github:GoogleChromeLabs/buffer-backed-object", | ||
"homepage": "https://github.com/GoogleChromeLabs/buffer-backed-object#readme", | ||
"source": "buffer-backed-object.js", | ||
"module": "dist/buffer-backed-object.modern.js", | ||
"source": "buffer-backed-object.ts", | ||
"module": "dist/buffer-backed-object.js", | ||
"main": "dist/buffer-backed-object.umd.js", | ||
"types": "dist/buffer-backed-object.d.ts", | ||
"scripts": { | ||
"build": "mkdir -p dist && run-p build:*", | ||
"build:bundle": "microbundle -f modern && microbundle -f umd", | ||
"build:types": "cp buffer-backed-object.d.ts dist/", | ||
"build": "mkdir -p dist && run-s build:bundle build:types", | ||
"build:bundle": "vite build", | ||
"build:types": "tsc --emitDeclarationOnly -d --outFile dist/buffer-backed-object.d.ts buffer-backed-object.ts", | ||
"test": "run-p test:*", | ||
"test:unit": "karmatic", | ||
"test:unit": "vitest run --coverage", | ||
"test:types": "tsc --noEmit buffer-backed-object.type-test.ts" | ||
@@ -22,19 +22,9 @@ }, | ||
"devDependencies": { | ||
"conditional-type-checks": "^1.0.5", | ||
"husky": "^4.2.3", | ||
"karmatic": "^1.4.0", | ||
"lint-staged": "^10.1.2", | ||
"microbundle": "^0.12.0-next.8", | ||
"@vitest/coverage-c8": "^0.26.3", | ||
"conditional-type-checks": "^1.0.6", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^2.0.4", | ||
"webpack": "^4.42.1" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
"*.{js,css,md}": "prettier --write" | ||
"typescript": "^4.9.4", | ||
"vite": "^4.0.4", | ||
"vitest": "^0.26.3" | ||
} | ||
} |
@@ -19,21 +19,25 @@ # `BufferBackedObject` | ||
### WebGPU | ||
Similary, you can define structs in WGLS and read from/write to GPU memory buffers. With `BufferBackedObject` or `ArrayOfBufferBackedObjects`, you can manipulate those structs from JavaScript more easily and efficiently. | ||
## Example | ||
```js | ||
import { BufferBackedObject } from "buffer-backed-object"; | ||
import * as BBO from "buffer-backed-object"; | ||
const buffer = new ArrayBuffer(100); | ||
const view = new BufferBackedObject(buffer, { | ||
id: BufferBackedObject.Uint16({ endianness: "big" }), | ||
position: BufferBackedObject.NestedBufferBackedObject({ | ||
x: BufferBackedObject.Float32(), | ||
y: BufferBackedObject.Float32(), | ||
z: BufferBackedObject.Float32(), | ||
const view = BBO.BufferBackedObject(buffer, { | ||
id: BBO.BufferBackedObject.Uint16({ endianness: "big" }), | ||
position: BBO.NestedBufferBackedObject({ | ||
x: BBO.Float32(), | ||
y: BBO.Float32(), | ||
z: BBO.Float32(), | ||
}), | ||
normal: BufferBackedObject.NestedBufferBackedObject({ | ||
x: BufferBackedObject.Float32(), | ||
y: BufferBackedObject.Float32(), | ||
z: BufferBackedObject.Float32(), | ||
normal: BBO.NestedBufferBackedObject({ | ||
x: BBO.Float32(), | ||
y: BBO.Float32(), | ||
z: BBO.Float32(), | ||
}), | ||
textureId: BufferBackedObject.Uint8(), | ||
textureId: BBO.Uint8(), | ||
}); | ||
@@ -51,21 +55,18 @@ | ||
```js | ||
import { | ||
ArrayOfBufferBackedObjects, | ||
BufferBackedObject, | ||
} from "buffer-backed-object"; | ||
import * as BBO from "buffer-backed-object"; | ||
const buffer = new ArrayBuffer(100); | ||
const view = new ArrayOfBufferBackedObjects(buffer, { | ||
id: BufferBackedObject.Uint16({ endianness: "big" }), | ||
position: BufferBackedObject.NestedBufferBackedObject({ | ||
x: BufferBackedObject.Float32(), | ||
y: BufferBackedObject.Float32(), | ||
z: BufferBackedObject.Float32(), | ||
const view = BBO.ArrayOfBufferBackedObjects(buffer, { | ||
id: BBO.Uint16({ endianness: "big" }), | ||
position: BBO.NestedBufferBackedObject({ | ||
x: BBO.Float32(), | ||
y: BBO.Float32(), | ||
z: BBO.Float32(), | ||
}), | ||
normal: BufferBackedObject.NestedBufferBackedObject({ | ||
x: BufferBackedObject.Float32(), | ||
y: BufferBackedObject.Float32(), | ||
z: BufferBackedObject.Float32(), | ||
normal: BBO.NestedBufferBackedObject({ | ||
x: BBO.Float32(), | ||
y: BBO.Float32(), | ||
z: BBO.Float32(), | ||
}), | ||
textureId: BufferBackedObject.Uint8(), | ||
textureId: BBO.Uint8(), | ||
}); | ||
@@ -91,32 +92,33 @@ | ||
### `new BufferBackedObject(buffer, descriptors, {byteOffset = 0})` | ||
### `function BufferBackedObject(buffer, descriptors, {byteOffset = 0})` | ||
The key/value pairs in the `descriptors` object must be declared in the same order as they are laid out in the buffer. The returned object has getters and setters for each of `descriptors` properties and de/serializes them `buffer`, starting at the given `byteOffset`. | ||
The following descriptor types are available as built-ins: | ||
### `function ArrayOfBufferBackedObjects(buffer, descriptors, {byteOffset = 0, length = 0})` | ||
- `BufferBackedObject.reserved(numBytes)`: A number of unused bytes. This field will now show up in the object. | ||
- `BufferBackedObject.Int8()`: An 8-bit signed integer | ||
- `BufferBackedObject.Uint8()`: An 8-bit unsigned integer | ||
- `BufferBackedObject.Int16({endianness = 'little'})`: An 16-bit signed integer | ||
- `BufferBackedObject.Uint16({endianness = 'little'})`: An 16-bit unsigned integer | ||
- `BufferBackedObject.Int32({endianness = 'little'})`: An 32-bit signed integer | ||
- `BufferBackedObject.Uint32({endianness = 'little'})`: An 32-bit unsigned integer | ||
- `BufferBackedObject.BigInt64({endianness = 'little'})`: An 64-bit signed [`BigInt`][bigint] | ||
- `BufferBackedObject.BigUint64({endianness = 'little'})`: An 64-bit unsigned [`BigInt`][bigint] | ||
- `BufferBackedObject.Float32({endianness = 'little'})`: An 32-bit IEEE754 float | ||
- `BufferBackedObject.Float64({endianness = 'little'})`: An 64-bit IEEE754 float (“double”) | ||
- `BufferBackedObject.UTF8String(maxBytes)`: A UTF-8 encoded string with the given maximum number of bytes. Trailing NULL bytes will be trimmed after decoding. | ||
- `BufferBackedObject.ArrayBuffer(size)`: An `ArrayBuffer` of the given size | ||
- `BufferBackedObject.NestedBufferBackedObject(descriptors)`: A nested `BufferBackedObject` with the given descriptors | ||
- `BufferBackedObject.NestedArrayOfBufferBackedObjects(numItems, descriptors)`: A nested `ArrayOfBufferBackedObjects` of length `numItems` with the given descriptors | ||
### `new ArrayOfBufferBackedObjects(buffer, descriptors, {byteOffset = 0, length = 0})` | ||
Like `BufferBackedObject`, but returns an _array_ of `BufferBackedObject`s. If `length` is 0, as much of the buffer is used as possible. The array is populated lazily under the hood for performance purposes. That is, the individual `BufferBackedObject`s will only be created when their index is accessed. | ||
### `structSize(descriptors)` | ||
### `function structSize(descriptors)` | ||
Returns the number of bytes required to store a value with the schema outlined by `descriptors`. | ||
### Descriptors | ||
The following descriptor types are available as individually exported functions | ||
- `function reserved(numBytes)`: A number of unused bytes. This field will now show up in the object. | ||
- `function Int8()`: An 8-bit signed integer | ||
- `function Uint8()`: An 8-bit unsigned integer | ||
- `function Int16({align = 2, endianness = 'little'})`: An 16-bit signed integer | ||
- `function Uint16({align = 2, endianness = 'little'})`: An 16-bit unsigned integer | ||
- `function Int32({align = 4, endianness = 'little'})`: An 32-bit signed integer | ||
- `function Uint32({align = 4, endianness = 'little'})`: An 32-bit unsigned integer | ||
- `function BigInt64({align = 8, endianness = 'little'})`: An 64-bit signed [`BigInt`][bigint] | ||
- `function BigUint64({align = 8, endianness = 'little'})`: An 64-bit unsigned [`BigInt`][bigint] | ||
- `function Float32({align = 4, endianness = 'little'})`: An 32-bit IEEE754 float | ||
- `function Float64({align = 8, endianness = 'little'})`: An 64-bit IEEE754 float (“double”) | ||
- `function UTF8String(maxBytes)`: A UTF-8 encoded string with the given maximum number of bytes. Trailing NULL bytes will be trimmed after decoding. | ||
- `function NestedBufferBackedObject(descriptors)`: A nested `BufferBackedObject` with the given descriptors | ||
- `function NestedArrayOfBufferBackedObjects(numItems, descriptors)`: A nested `ArrayOfBufferBackedObjects` of length `numItems` with the given descriptors | ||
## Defining your own descriptor types | ||
@@ -128,2 +130,3 @@ | ||
{ | ||
align?: 1, // Required aligment | ||
size: 4, // Size required by the type | ||
@@ -130,0 +133,0 @@ get(dataView, byteOffset) { |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 2 instances in 1 package
6
0
100
1036
0
155
62198
1