diff --git a/.ccls b/.ccls new file mode 100644 index 0000000..29f0f82 --- /dev/null +++ b/.ccls @@ -0,0 +1,3 @@ +clang +-I/Users/zongor/emsdk/upstream/emscripten/system/include +-I/Users/zongor/lib/raylib \ No newline at end of file diff --git a/.gitignore b/.gitignore index b6bb983..110308b 100644 --- a/.gitignore +++ b/.gitignore @@ -359,3 +359,5 @@ dist # Finder (MacOS) folder config .DS_Store + +.ccls-cache \ No newline at end of file diff --git a/tools/js-class-c-struct-transpiler/test/build/Login.js b/tools/js-class-c-struct-transpiler/test/build/Login.js index aebe5fd..14b91d8 100644 --- a/tools/js-class-c-struct-transpiler/test/build/Login.js +++ b/tools/js-class-c-struct-transpiler/test/build/Login.js @@ -1,34 +1,53 @@ +/** + * @typedef {Object} Login The login object + * @property {string} Email Email of the user + * @property {string} Password Password of the user + */ class Login { /** * Email of the user + * @return {string} gets the value of Email */ get Email() { return this._decoder.decode(new Uint8Array(this._ptr.slice(0, 256))); } + /** + * Email of the user + * @param {string} v sets the value of Email + */ set Email(v) { this._data.set(this._encoder.encode(v), 0); } /** * Password of the user + * @return {string} gets the value of Password */ get Password() { return this._decoder.decode(new Uint8Array(this._ptr.slice(256, 320))); } + /** + * Password of the user + * @param {string} v sets the value of Password + */ set Password(v) { this._data.set(this._encoder.encode(v), 256); } /** - * get the struct representation of the object + * Get the struct representation of the object + * @return {Uint8Array} u8 array of the C struct. */ get bytes() { return new Uint8Array(this._ptr); } /** - * constructor + * Constructs a new Login + * + * @param {{Email: string, Password: string, }} init The arguments to construct the object. + * @param {ArrayBuffer} ptr The pointer to the C struct. */ constructor(init = {}, ptr = undefined) { this._size = 320; - this._ptr = ptr.buffer || new ArrayBuffer(this._size); + this._ptr = ptr?.buffer || new ArrayBuffer(this._size); this._data = new DataView(this._ptr); this._encoder = new TextEncoder(); diff --git a/tools/js-class-c-struct-transpiler/test/build/LoginRequest.js b/tools/js-class-c-struct-transpiler/test/build/LoginRequest.js index 618d426..fc9269b 100644 --- a/tools/js-class-c-struct-transpiler/test/build/LoginRequest.js +++ b/tools/js-class-c-struct-transpiler/test/build/LoginRequest.js @@ -1,26 +1,39 @@ import Login from "./Login" +/** + * @typedef {Object} LoginRequest a request for a login + * @property Login Login user login info + */ class LoginRequest { /** * user login info + * @return {Login} gets the value of Login */ get Login() { return new Login({}, new Uint8Array(this._ptr.slice(0, 320))); } + /** + * user login info + * @param {Login} sets the value of Login + */ set Login(v) { this._data.set(v.bytes(), 0); } /** - * get the struct representation of the object + * Get the struct representation of the object + * @return {Uint8Array} u8 array of the C struct. */ get bytes() { return new Uint8Array(this._ptr); } /** - * constructor + * Constructs a new LoginRequest + * + * @param {{Login: Login, }} init The arguments to construct the object. + * @param {ArrayBuffer} ptr The pointer to the C struct. */ constructor(init = {}, ptr = undefined) { this._size = 320; - this._ptr = ptr.buffer || new ArrayBuffer(this._size); + this._ptr = ptr?.buffer || new ArrayBuffer(this._size); this._data = new DataView(this._ptr); for (const key of Object.keys(init)) { diff --git a/tools/js-class-c-struct-transpiler/test/build/LoginResponse.js b/tools/js-class-c-struct-transpiler/test/build/LoginResponse.js index f1b7504..8ca8868 100644 --- a/tools/js-class-c-struct-transpiler/test/build/LoginResponse.js +++ b/tools/js-class-c-struct-transpiler/test/build/LoginResponse.js @@ -1,25 +1,38 @@ +/** + * @typedef {Object} LoginResponse the response from a login request + * @property boolean logical login was successful or not + */ class LoginResponse { /** * login was successful or not + * @return {boolean} gets the value of success */ get success() { - return this._data.getInt8(0, true); + return this._data.getboolean(0, true); } + /** + * login was successful or not + * @param {boolean} sets the value of success + */ set success(v) { - return this._data.setInt8(0, v, true); + return this._data.setboolean(0, v, true); } /** - * get the struct representation of the object + * Get the struct representation of the object + * @return {Uint8Array} u8 array of the C struct. */ get bytes() { return new Uint8Array(this._ptr); } /** - * constructor + * Constructs a new LoginResponse + * + * @param {{success: boolean, }} init The arguments to construct the object. + * @param {ArrayBuffer} ptr The pointer to the C struct. */ constructor(init = {}, ptr = undefined) { this._size = 1; - this._ptr = ptr.buffer || new ArrayBuffer(this._size); + this._ptr = ptr?.buffer || new ArrayBuffer(this._size); this._data = new DataView(this._ptr); for (const key of Object.keys(init)) { diff --git a/tools/js-class-c-struct-transpiler/test/build/User.js b/tools/js-class-c-struct-transpiler/test/build/User.js index 4c7d217..1aa8e92 100644 --- a/tools/js-class-c-struct-transpiler/test/build/User.js +++ b/tools/js-class-c-struct-transpiler/test/build/User.js @@ -1,45 +1,70 @@ import Login from "./Login" import Vector3 from "./Vector3" +/** + * @typedef {Object} User The user object + * @property {string} Name Name of the user + * @property Login Login user login info + * @property Vector3 Vector3 last logout position of user + */ class User { /** * Name of the user + * @return {string} gets the value of Name */ get Name() { return this._decoder.decode(new Uint8Array(this._ptr.slice(0, 24))); } + /** + * Name of the user + * @param {string} v sets the value of Name + */ set Name(v) { this._data.set(this._encoder.encode(v), 0); } /** * user login info + * @return {Login} gets the value of Login */ get Login() { return new Login({}, new Uint8Array(this._ptr.slice(24, 344))); } + /** + * user login info + * @param {Login} sets the value of Login + */ set Login(v) { this._data.set(v.bytes(), 24); } /** * last logout position of user + * @return {Vector3} gets the value of Position */ get Position() { return new Vector3({}, new Uint8Array(this._ptr.slice(344, 356))); } + /** + * last logout position of user + * @param {Vector3} sets the value of Position + */ set Position(v) { this._data.set(v.bytes(), 344); } /** - * get the struct representation of the object + * Get the struct representation of the object + * @return {Uint8Array} u8 array of the C struct. */ get bytes() { return new Uint8Array(this._ptr); } /** - * constructor + * Constructs a new User + * + * @param {{Name: string, Login: Login, Position: Vector3, }} init The arguments to construct the object. + * @param {ArrayBuffer} ptr The pointer to the C struct. */ constructor(init = {}, ptr = undefined) { this._size = 356; - this._ptr = ptr.buffer || new ArrayBuffer(this._size); + this._ptr = ptr?.buffer || new ArrayBuffer(this._size); this._data = new DataView(this._ptr); this._encoder = new TextEncoder(); diff --git a/tools/js-class-c-struct-transpiler/test/build/Vector3.js b/tools/js-class-c-struct-transpiler/test/build/Vector3.js index 38051b4..946a68d 100644 --- a/tools/js-class-c-struct-transpiler/test/build/Vector3.js +++ b/tools/js-class-c-struct-transpiler/test/build/Vector3.js @@ -1,43 +1,68 @@ +/** + * @typedef {Object} Vector3 A representation of a position in 3D space + * @property Float32 f32 x coordinate + * @property Float32 f32 y coordinate + * @property Float32 f32 z coordinate + */ class Vector3 { /** * x coordinate + * @return {Float32} gets the value of x */ get x() { return this._data.getFloat32(0, true); } + /** + * x coordinate + * @param {Float32} sets the value of x + */ set x(v) { return this._data.setFloat32(0, v, true); } /** * y coordinate + * @return {Float32} gets the value of y */ get y() { return this._data.getFloat32(4, true); } + /** + * y coordinate + * @param {Float32} sets the value of y + */ set y(v) { return this._data.setFloat32(4, v, true); } /** * z coordinate + * @return {Float32} gets the value of z */ get z() { return this._data.getFloat32(8, true); } + /** + * z coordinate + * @param {Float32} sets the value of z + */ set z(v) { return this._data.setFloat32(8, v, true); } /** - * get the struct representation of the object + * Get the struct representation of the object + * @return {Uint8Array} u8 array of the C struct. */ get bytes() { return new Uint8Array(this._ptr); } /** - * constructor + * Constructs a new Vector3 + * + * @param {{x: Float32, y: Float32, z: Float32, }} init The arguments to construct the object. + * @param {ArrayBuffer} ptr The pointer to the C struct. */ constructor(init = {}, ptr = undefined) { this._size = 12; - this._ptr = ptr.buffer || new ArrayBuffer(this._size); + this._ptr = ptr?.buffer || new ArrayBuffer(this._size); this._data = new DataView(this._ptr); for (const key of Object.keys(init)) { diff --git a/tools/js-class-c-struct-transpiler/test/schema.json b/tools/js-class-c-struct-transpiler/test/schema.json index f0c7507..2c0aaa6 100644 --- a/tools/js-class-c-struct-transpiler/test/schema.json +++ b/tools/js-class-c-struct-transpiler/test/schema.json @@ -1,65 +1,80 @@ { "Vector3": { - "x": { - "type": "f32", - "kind": "scalar", - "comment": "x coordinate" - }, - "y": { - "type": "f32", - "kind": "scalar", - "comment": "y coordinate" - }, - "z": { - "type": "f32", - "kind": "scalar", - "comment": "z coordinate" + "comment": "A representation of a position in 3D space", + "members": { + "x": { + "type": "f32", + "kind": "scalar", + "comment": "x coordinate" + }, + "y": { + "type": "f32", + "kind": "scalar", + "comment": "y coordinate" + }, + "z": { + "type": "f32", + "kind": "scalar", + "comment": "z coordinate" + } } }, "Login": { - "Email": { - "type": "string", - "kind": "string", - "size": "256", - "comment": "Email of the user" - }, - "Password": { - "type": "string", - "kind": "string", - "size": "64", - "comment": "Password of the user" + "comment": "The login object", + "members": { + "Email": { + "type": "string", + "kind": "string", + "size": "256", + "comment": "Email of the user" + }, + "Password": { + "type": "string", + "kind": "string", + "size": "64", + "comment": "Password of the user" + } } }, "User": { - "Name": { - "type": "string", - "kind": "string", - "size": "24", - "comment": "Name of the user" - }, - "Login": { - "type": "Login", - "kind": "struct", - "comment": "user login info" - }, - "Position": { - "type": "Vector3", - "kind": "struct", - "comment": "last logout position of user" + "comment": "The user object", + "members": { + "Name": { + "type": "string", + "kind": "string", + "size": "24", + "comment": "Name of the user" + }, + "Login": { + "type": "Login", + "kind": "struct", + "comment": "user login info" + }, + "Position": { + "type": "Vector3", + "kind": "struct", + "comment": "last logout position of user" + } } }, "LoginRequest": { - "Login": { - "type": "Login", - "kind": "struct", - "comment": "user login info" + "comment": "a request for a login", + "members": { + "Login": { + "type": "Login", + "kind": "struct", + "comment": "user login info" + } } }, "LoginResponse": { - "success": { - "type": "i8", - "kind": "scalar", - "comment": "login was successful or not" + "comment": "the response from a login request", + "members": { + "success": { + "type": "logical", + "kind": "scalar", + "comment": "login was successful or not" + } } } } diff --git a/tools/js-class-c-struct-transpiler/test/test_client.c b/tools/js-class-c-struct-transpiler/test/test_client.c index 6baa91e..e5dfba2 100644 --- a/tools/js-class-c-struct-transpiler/test/test_client.c +++ b/tools/js-class-c-struct-transpiler/test/test_client.c @@ -2,32 +2,17 @@ #include #include #include -#include "out/types.h" +#include "build/types.h" EM_BOOL WebSocketOpen(int eventType, const EmscriptenWebSocketOpenEvent *e, void *userData) { printf("open(eventType=%d, userData=%p)\n", eventType, userData); - Camera3D camera = {0}; - camera.position = (Vector3){-9.0f, 9.0f, 4.0f}; - camera.target = (Vector3){9.0f, 9.0f, 0.0f}; - camera.up = (Vector3){0.0f, 1.0f, 0.0f}; - camera.fovy = 60.0f; - camera.projection = 0; - - Entity entity = (Entity){ + LoginRequest req = (LoginRequest){ "Zongor", - camera, - 1,1,1,1, - 1,1,1,1, - 1,1,1,1, - 1,1,1,1, - 1,1,1,1, - 1,1,1,1, - 1,42,1,1, - 1,1 + "Password" }; - emscripten_websocket_send_binary(e->socket, &entity, sizeof(entity)); + emscripten_websocket_send_binary(e->socket, &req, sizeof(req)); return 0; } @@ -44,24 +29,11 @@ EM_BOOL WebSocketError(int eventType, const EmscriptenWebSocketErrorEvent *e, vo EM_BOOL WebSocketMessage(int eventType, const EmscriptenWebSocketMessageEvent *e, void *userData) { printf("message(eventType=%d, userData=%p data=%p, numBytes=%d, isText=%d)\n", eventType, userData, e->data, e->numBytes, e->isText); - static int text_received = 0; - if (e->isText) { - printf("text data: \"%s\"\n", e->data); - assert(strcmp((const char*)e->data, "hello on the other side") == 0); - text_received = 1; - return 0; - } - Entity entity; - memcpy(&entity, e->data, sizeof entity); + LoginResponse response; + memcpy(&response, e->data, sizeof response); - printf("x: %f", entity.Camera.position.x); - printf(" y: %f", entity.Camera.position.y); - printf(" z: %f", entity.Camera.position.z); - printf(" name: %s", entity.Name); - printf(" fovy: %f", entity.Camera.fovy); - printf(" luck: %d", entity.Luck); - printf("\n"); + printf("response: %d\n", response.success); emscripten_websocket_close(e->socket, 0, 0); emscripten_websocket_delete(e->socket); diff --git a/tools/js-class-c-struct-transpiler/test/test_server.js b/tools/js-class-c-struct-transpiler/test/test_server.js index de123cf..3a41773 100644 --- a/tools/js-class-c-struct-transpiler/test/test_server.js +++ b/tools/js-class-c-struct-transpiler/test/test_server.js @@ -1,4 +1,5 @@ -import Entity from "./out/Entity" +import LoginRequest from "./build/LoginRequest" +import LoginResponse from "./build/LoginResponse" var decoder = new TextDecoder("utf-8"); var port = 8089; @@ -13,13 +14,12 @@ wss.on("connection", function (ws) { console.log("received TEXT: " + text.length + " characters:"); console.log(' "' + text + '"'); } else { - const entity = new Entity({}, new Uint8Array(message)); - console.log(entity.Camera.position.x, entity.Camera.position.y, entity.Camera.position.z); - console.log(entity.Name); - console.log(entity.Luck); - console.log(entity.bytes); + const entity = new LoginRequest({}, new Uint8Array(message)); + console.log(entity.Login.Email); + console.log(entity.Login.Password); - ws.send(entity.bytes, { binary: true }); // Echo back the received message + const response = new LoginResponse({success: true}); + ws.send(response.bytes, { binary: true }); // Echo back the received message } }); }); diff --git a/tools/js-class-c-struct-transpiler/transpile.js b/tools/js-class-c-struct-transpiler/transpile.js index c7f92a5..ada8bc9 100644 --- a/tools/js-class-c-struct-transpiler/transpile.js +++ b/tools/js-class-c-struct-transpiler/transpile.js @@ -1,6 +1,12 @@ import { parseArgs } from "util"; let types = { + logical: { + c: "char", + js: "boolean", + sql: "INTEGER", + size: 1, + }, u8: { c: "unsigned char", js: "Uint8", @@ -85,20 +91,24 @@ const { values } = parseArgs({ allowPositionals: true, }); -function jsStructConstructor(size, containsString) { +function jsStructConstructor(size, containsString, type, args) { return ` /** - * get the struct representation of the object + * Get the struct representation of the object + * @return {Uint8Array} u8 array of the C struct. */ get bytes() { return new Uint8Array(this._ptr); } /** - * constructor + * Constructs a new ${type} + * + * @param ${args} init The arguments to construct the object. + * @param {ArrayBuffer} ptr The pointer to the C struct. */ constructor(init = {}, ptr = undefined) { this._size = ${size}; - this._ptr = ptr.buffer || new ArrayBuffer(this._size); + this._ptr = ptr?.buffer || new ArrayBuffer(this._size); this._data = new DataView(this._ptr); ${ containsString @@ -125,7 +135,9 @@ for (const type of Object.keys(schema)) { let importStatements = ""; let jsData = ""; let foreignKeys = ""; - const props = schema[type]; + const props = schema[type].members; + let typeDef = `/**\n * @typedef {Object} ${type} ${schema[type].comment}\n`; + let args = `{{`; sqlData += `CREATE TABLE ${type} (id INTEGER PRIMARY KEY AUTOINCREMENT`; cData += `typedef struct ${type} {`; jsData += `class ${type} {`; @@ -141,35 +153,49 @@ for (const type of Object.keys(schema)) { typeSize = props[prop].size; const iSize = parseInt(offset) + parseInt(typeSize); jsData += ` - ${(comment) ? `/** + /** * ${comment} - */` : ""} + * @return {string} gets the value of ${prop} + */ get ${prop}() { return this._decoder.decode(new Uint8Array(this._ptr.slice(${parseInt( offset )}, ${iSize}))); } + /** + * ${comment} + * @param {string} v sets the value of ${prop} + */ set ${prop}(v) { this._data.set(this._encoder.encode(v), ${parseInt(offset)}); }`; sqlData += `, ${prop} TEXT`; cData += ` char ${prop}[${iSize}]; // ${comment}`; + args += `${prop}: string, `; + typeDef += ` * @property {string} ${prop} ${comment}\n`; break; case "scalar": typeSize = types[propType].size; jsData += ` - ${(comment) ? `/** + /** * ${comment} - */` : ""} + * @return {${types[propType].js}} gets the value of ${prop} + */ get ${prop}() { return this._data.get${types[propType].js}(${parseInt(offset)}, true); } + /** + * ${comment} + * @param {${types[propType].js}} sets the value of ${prop} + */ set ${prop}(v) { return this._data.set${types[propType].js}(${parseInt( offset )}, v, true); }`; + args += `${prop}: ${types[propType].js}, `; + typeDef += ` * @property ${types[propType].js} ${propType} ${comment}\n`; sqlData += `, ${prop} ${types[propType].sql}`; cData += ` ${types[propType].c} ${prop}; // ${comment}`; @@ -178,12 +204,17 @@ for (const type of Object.keys(schema)) { case "struct": const jsSize = parseInt(offset) + parseInt(types[propType].size); jsData += ` - ${(comment) ? `/** + /** * ${comment} - */` : ""} + * @return {${types[propType].js}} gets the value of ${prop} + */ get ${prop}() { return new ${propType}({}, new Uint8Array(this._ptr.slice(${offset}, ${jsSize}))); } + /** + * ${comment} + * @param {${types[propType].js}} sets the value of ${prop} + */ set ${prop}(v) { this._data.set(v.bytes(), ${offset}); }`; @@ -192,7 +223,8 @@ for (const type of Object.keys(schema)) { importStatements += importS; } const localKey = `${prop.toLowerCase()}_id`; - + args += `${prop}: ${types[propType].js}, `; + typeDef += ` * @property ${types[propType].js} ${propType} ${comment}\n`; sqlData += `, ${localKey} INTEGER`; foreignKeys += `\n, FOREIGN KEY(${localKey}) REFERENCES ${propType}(id)` cData += `\n\t\t${types[propType].c} ${prop}; // ${comment}`; @@ -217,7 +249,10 @@ for (const type of Object.keys(schema)) { size: parseInt(size), }; - jsData += jsStructConstructor(size, containsString); + typeDef += " */\n" + args += `}}` + jsData = typeDef + jsData; + jsData += jsStructConstructor(size, containsString, type, args); jsData += `\n}\n\nexport default ${type}`; cData += `\n} ${type};\n\n`; sqlData += `${foreignKeys});\n\n`;