c-structs
Version:
289 lines (288 loc) • 6.57 kB
JavaScript
// src/index.ts
var p = {
float32: {
size: 4,
arrayType: Float32Array,
getter: "getFloat32",
setter: "setFloat32"
},
float64: {
size: 8,
arrayType: Float64Array,
getter: "getFloat64",
setter: "setFloat64"
},
uint16: {
size: 2,
arrayType: Uint16Array,
getter: "getUint16",
setter: "setUint16"
},
uint32: {
size: 4,
arrayType: Uint32Array,
getter: "getUint32",
setter: "setUint32"
},
uint64: {
size: 8,
arrayType: BigUint64Array,
getter: "getBigUint64",
setter: "setBigUint64"
},
int16: {
size: 2,
arrayType: Int16Array,
getter: "getInt16",
setter: "setInt16"
},
int32: {
size: 4,
arrayType: Int32Array,
getter: "getInt32",
setter: "setInt32"
},
int64: {
size: 8,
arrayType: BigInt64Array,
getter: "getBigInt64",
setter: "setBigInt64"
}
};
var c = {
float() {
return p.float32;
},
float2() {
return [p.float32, p.float32];
},
float3() {
return [p.float32, p.float32, p.float32];
},
float4() {
return [p.float32, p.float32, p.float32, p.float32];
},
uint() {
return p.uint32;
},
uint2() {
return [p.uint32, p.uint32];
},
uint3() {
return [p.uint32, p.uint32, p.uint32];
},
uint4() {
return [p.uint32, p.uint32, p.uint32, p.uint32];
},
int() {
return p.int32;
},
int2() {
return [p.int32, p.int32];
},
int3() {
return [p.int32, p.int32, p.int32];
},
int4() {
return [p.int32, p.int32, p.int32, p.int32];
},
uint16() {
return p.uint16;
},
uint64() {
return p.uint64;
},
int16() {
return p.int16;
},
int64() {
return p.int64;
},
float64() {
return p.float64;
},
matrix3() {
return [
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32
];
},
matrix4() {
return [
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32,
p.float32
];
},
/**
* Create an array descriptor for nested structs.
*/
array(structDesc, length) {
if (typeof structDesc.size !== "number" || typeof structDesc.create !== "function") {
throw new Error("c.array: first arg must be a StructDescriptor");
}
if (!Number.isInteger(length) || length <= 0) {
throw new Error("c.array: length must be a positive integer");
}
return {
size: structDesc.size * length,
create(buffer = new ArrayBuffer(structDesc.size * length), baseOffset = 0) {
const arr = new Array(length);
for (let i = 0; i < length; i++) {
arr[i] = structDesc.create(buffer, baseOffset + i * structDesc.size);
}
Object.defineProperty(arr, "buffer", {
get: () => buffer,
enumerable: false
});
return arr;
}
};
},
/**
* Create a struct descriptor from a schema map.
*/
struct(schema) {
let offset = 0;
const fields = [];
for (const [name, type] of Object.entries(schema)) {
const fieldOffset = offset;
let entry;
if (Array.isArray(type)) {
const elem = type[0];
entry = {
kind: "vector",
name,
elem,
length: type.length,
offset: fieldOffset
};
offset += elem.size * type.length;
} else if (type.size && typeof type.create === "function" && Array.isArray(type.create())) {
entry = {
kind: "array",
name,
elemDesc: type,
length: type.length,
offset: fieldOffset
};
offset += type.size * type.length;
} else if (type.arrayType) {
const elem = type;
entry = {
kind: "scalar",
name,
desc: elem,
offset: fieldOffset
};
offset += elem.size;
} else if (type.size && typeof type.create === "function") {
entry = {
kind: "struct",
name,
desc: type,
offset: fieldOffset
};
offset += type.size;
} else {
throw new Error(`Unknown field type for "${name}"`);
}
fields.push(entry);
}
const totalSize = offset;
class Ctor {
buffer;
baseOffset;
__view;
constructor(buffer = new ArrayBuffer(totalSize), baseOffset = 0) {
this.buffer = buffer;
this.baseOffset = baseOffset;
this.__view = new DataView(buffer);
for (const f of fields) {
if (f.kind === "struct") {
this[f.name] = f.desc.create(buffer, baseOffset + f.offset);
} else if (f.kind === "array") {
this[f.name] = c.array(f.elemDesc, f.length).create(buffer, baseOffset + f.offset);
}
}
}
}
for (const f of fields) {
const abs = f.offset;
switch (f.kind) {
case "scalar":
Object.defineProperty(Ctor.prototype, f.name, {
enumerable: true,
get() {
return this.__view[f.desc.getter](
this.baseOffset + abs,
true
);
},
set(v) {
return this.__view[f.desc.setter](
this.baseOffset + abs,
v,
true
);
}
});
break;
case "vector": {
const Typed = f.elem.arrayType;
Object.defineProperty(Ctor.prototype, f.name, {
enumerable: true,
get() {
if (!this.hasOwnProperty("__" + f.name)) {
Object.defineProperty(this, "__" + f.name, {
value: new Typed(
this.buffer,
this.baseOffset + abs,
f.length
),
writable: false,
enumerable: false
});
}
return this["__" + f.name];
},
set(arr) {
const ta = this[f.name];
for (let i = 0; i < f.length; i++) ta[i] = arr[i];
}
});
break;
}
}
}
return {
size: totalSize,
create(buffer, baseOffset) {
return new Ctor(buffer, baseOffset);
}
};
}
};
export {
c
};