import { parseArgs } from "util"; let types = { u8: { c: "unsigned char", js: "Uint8", size: 1, }, i8: { c: "char", js: "Int8", size: 1, }, u16: { c: "unsigned short", js: "Uint16", size: 2, }, i16: { c: "short", js: "Int16", size: 2, }, u32: { c: "unisgned int", js: "Uint32", size: 4, }, i32: { c: "int", js: "Int32", size: 4, }, f32: { c: "float", js: "Float32", size: 4, }, f64: { c: "double", js: "Float64", size: 8, }, }; const { values } = parseArgs({ args: Bun.argv, options: { schema: { type: "string", short: "S", }, jsout: { type: "string", short: "j" }, cout: { type: "string", short: "c" }, }, strict: true, allowPositionals: true, }); function jsStructConstructor(size, containsString) { return ` get bytes() { return new Uint8Array(this._ptr); } constructor(init = {}, ptr = undefined) { this._size = ${size}; this._ptr = ptr.buffer || new ArrayBuffer(this._size); this._data = new DataView(this._ptr); ${ containsString ? ` this._encoder = new TextEncoder(); this._decoder = new TextDecoder();` : "" } for (const key of Object.keys(init)) { this[key] = init[key]; } }`; } const sFile = Bun.file(values.schema); const schema = await sFile.json(); let cData = ""; for (const type of Object.keys(schema)) { let containsString = false; let offset = 0; let size = 0; let importStatements = ""; let jsData = ""; const props = schema[type]; cData += `typedef struct ${type} {`; jsData += `class ${type} {`; for (const prop of Object.keys(props)) { const propType = props[prop].type; const kind = props[prop].kind; let typeSize = parseInt(types[propType]?.size); switch (kind) { case "string": containsString = true; typeSize = props[prop].size; const iSize = parseInt(offset) + parseInt(typeSize); jsData += ` get ${prop}() { return this._decoder.decode(new Uint8Array(this._ptr.slice(${parseInt( offset )}, ${iSize}))); } set ${prop}(v) { this._data.set(this._encoder.encode(v), ${parseInt(offset)}); }`; cData += ` char ${prop}[${iSize}];`; break; case "scalar": typeSize = types[propType].size; jsData += ` get ${prop}() { return this._data.get${types[propType].js}(${parseInt(offset)}, true); } set ${prop}(v) { return this._data.set${types[propType].js}(${parseInt( offset )}, v, true); }`; cData += ` ${types[propType].c} ${prop};`; break; case "struct": const jsSize = parseInt(offset) + parseInt(types[propType].size); jsData += ` get ${prop}() { return new ${propType}({}, new Uint8Array(this._ptr.slice(${offset}, ${jsSize}))); } set ${prop}(v) { this._data.set(v.bytes(), ${offset}); }`; importStatements += `import ${propType} from "./${propType}"\n\n`; cData += `\n\t\t${types[propType].c} ${prop};`; break; case "array": break; default: break; } size += parseInt(typeSize); offset += parseInt(typeSize); } /** * add the new type to the list so we can use it for structs later. */ types[type] = { c: type, js: type, size: parseInt(size), }; jsData += jsStructConstructor(size, containsString); jsData += ` } export default ${type}`; cData += ` } ${type}; `; await Bun.write(Bun.file(values.jsout + type + ".js"), (importStatements + jsData)); } await Bun.write(Bun.file(values.cout + "types.h"), cData);