c-structs
Version:
222 lines (221 loc) • 5.3 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 = {
// Vector of floats
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];
},
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 = [];
for (let i = 0; i < length; i++) {
arr.push(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;
return {
size: totalSize,
create(buffer = new ArrayBuffer(totalSize), baseOffset = 0) {
const view = new DataView(buffer);
const inst = {};
for (const f of fields) {
const abs = baseOffset + f.offset;
switch (f.kind) {
case "scalar":
Object.defineProperty(inst, f.name, {
get: () => view[f.desc.getter](abs, true),
set: (v) => view[f.desc.setter](abs, v, true),
enumerable: true
});
break;
case "vector": {
const Typed = f.elem.arrayType;
const ta = new Typed(buffer, abs, f.length);
Object.defineProperty(inst, f.name, {
get: () => ta,
set: (arr) => {
for (let i = 0; i < f.length; i++) ta[i] = arr[i];
},
enumerable: true
});
break;
}
case "struct":
inst[f.name] = f.desc.create(buffer, abs);
break;
case "array":
inst[f.name] = c.array(f.elemDesc, f.length).create(buffer, abs);
break;
}
}
Object.defineProperty(inst, "buffer", {
get: () => buffer,
enumerable: false
});
return inst;
}
};
}
};
export {
c,
p
};