add jsdoc, add logical

This commit is contained in:
zongor 2024-06-12 23:05:45 -04:00
parent 5026958057
commit f4bde93974
11 changed files with 242 additions and 120 deletions

3
.ccls Normal file
View File

@ -0,0 +1,3 @@
clang
-I/Users/zongor/emsdk/upstream/emscripten/system/include
-I/Users/zongor/lib/raylib

2
.gitignore vendored
View File

@ -359,3 +359,5 @@ dist
# Finder (MacOS) folder config # Finder (MacOS) folder config
.DS_Store .DS_Store
.ccls-cache

View File

@ -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 { class Login {
/** /**
* Email of the user * Email of the user
* @return {string} gets the value of Email
*/ */
get Email() { get Email() {
return this._decoder.decode(new Uint8Array(this._ptr.slice(0, 256))); 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) { set Email(v) {
this._data.set(this._encoder.encode(v), 0); this._data.set(this._encoder.encode(v), 0);
} }
/** /**
* Password of the user * Password of the user
* @return {string} gets the value of Password
*/ */
get Password() { get Password() {
return this._decoder.decode(new Uint8Array(this._ptr.slice(256, 320))); 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) { set Password(v) {
this._data.set(this._encoder.encode(v), 256); 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() { get bytes() {
return new Uint8Array(this._ptr); 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) { constructor(init = {}, ptr = undefined) {
this._size = 320; 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._data = new DataView(this._ptr);
this._encoder = new TextEncoder(); this._encoder = new TextEncoder();

View File

@ -1,26 +1,39 @@
import Login from "./Login" import Login from "./Login"
/**
* @typedef {Object} LoginRequest a request for a login
* @property Login Login user login info
*/
class LoginRequest { class LoginRequest {
/** /**
* user login info * user login info
* @return {Login} gets the value of Login
*/ */
get Login() { get Login() {
return new Login({}, new Uint8Array(this._ptr.slice(0, 320))); return new Login({}, new Uint8Array(this._ptr.slice(0, 320)));
} }
/**
* user login info
* @param {Login} sets the value of Login
*/
set Login(v) { set Login(v) {
this._data.set(v.bytes(), 0); 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() { get bytes() {
return new Uint8Array(this._ptr); 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) { constructor(init = {}, ptr = undefined) {
this._size = 320; 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._data = new DataView(this._ptr);
for (const key of Object.keys(init)) { for (const key of Object.keys(init)) {

View File

@ -1,25 +1,38 @@
/**
* @typedef {Object} LoginResponse the response from a login request
* @property boolean logical login was successful or not
*/
class LoginResponse { class LoginResponse {
/** /**
* login was successful or not * login was successful or not
* @return {boolean} gets the value of success
*/ */
get success() { get success() {
return this._data.getInt8(0, true); return this._data.getboolean(0, true);
}
set success(v) {
return this._data.setInt8(0, v, true);
} }
/** /**
* get the struct representation of the object * login was successful or not
* @param {boolean} sets the value of success
*/
set success(v) {
return this._data.setboolean(0, v, true);
}
/**
* Get the struct representation of the object
* @return {Uint8Array} u8 array of the C struct.
*/ */
get bytes() { get bytes() {
return new Uint8Array(this._ptr); 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) { constructor(init = {}, ptr = undefined) {
this._size = 1; 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); this._data = new DataView(this._ptr);
for (const key of Object.keys(init)) { for (const key of Object.keys(init)) {

View File

@ -1,45 +1,70 @@
import Login from "./Login" import Login from "./Login"
import Vector3 from "./Vector3" 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 { class User {
/** /**
* Name of the user * Name of the user
* @return {string} gets the value of Name
*/ */
get Name() { get Name() {
return this._decoder.decode(new Uint8Array(this._ptr.slice(0, 24))); 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) { set Name(v) {
this._data.set(this._encoder.encode(v), 0); this._data.set(this._encoder.encode(v), 0);
} }
/** /**
* user login info * user login info
* @return {Login} gets the value of Login
*/ */
get Login() { get Login() {
return new Login({}, new Uint8Array(this._ptr.slice(24, 344))); return new Login({}, new Uint8Array(this._ptr.slice(24, 344)));
} }
/**
* user login info
* @param {Login} sets the value of Login
*/
set Login(v) { set Login(v) {
this._data.set(v.bytes(), 24); this._data.set(v.bytes(), 24);
} }
/** /**
* last logout position of user * last logout position of user
* @return {Vector3} gets the value of Position
*/ */
get Position() { get Position() {
return new Vector3({}, new Uint8Array(this._ptr.slice(344, 356))); 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) { set Position(v) {
this._data.set(v.bytes(), 344); 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() { get bytes() {
return new Uint8Array(this._ptr); 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) { constructor(init = {}, ptr = undefined) {
this._size = 356; 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._data = new DataView(this._ptr);
this._encoder = new TextEncoder(); this._encoder = new TextEncoder();

View File

@ -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 { class Vector3 {
/** /**
* x coordinate * x coordinate
* @return {Float32} gets the value of x
*/ */
get x() { get x() {
return this._data.getFloat32(0, true); return this._data.getFloat32(0, true);
} }
/**
* x coordinate
* @param {Float32} sets the value of x
*/
set x(v) { set x(v) {
return this._data.setFloat32(0, v, true); return this._data.setFloat32(0, v, true);
} }
/** /**
* y coordinate * y coordinate
* @return {Float32} gets the value of y
*/ */
get y() { get y() {
return this._data.getFloat32(4, true); return this._data.getFloat32(4, true);
} }
/**
* y coordinate
* @param {Float32} sets the value of y
*/
set y(v) { set y(v) {
return this._data.setFloat32(4, v, true); return this._data.setFloat32(4, v, true);
} }
/** /**
* z coordinate * z coordinate
* @return {Float32} gets the value of z
*/ */
get z() { get z() {
return this._data.getFloat32(8, true); return this._data.getFloat32(8, true);
} }
/**
* z coordinate
* @param {Float32} sets the value of z
*/
set z(v) { set z(v) {
return this._data.setFloat32(8, v, true); 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() { get bytes() {
return new Uint8Array(this._ptr); 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) { constructor(init = {}, ptr = undefined) {
this._size = 12; 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); this._data = new DataView(this._ptr);
for (const key of Object.keys(init)) { for (const key of Object.keys(init)) {

View File

@ -1,65 +1,80 @@
{ {
"Vector3": { "Vector3": {
"x": { "comment": "A representation of a position in 3D space",
"type": "f32", "members": {
"kind": "scalar", "x": {
"comment": "x coordinate" "type": "f32",
}, "kind": "scalar",
"y": { "comment": "x coordinate"
"type": "f32", },
"kind": "scalar", "y": {
"comment": "y coordinate" "type": "f32",
}, "kind": "scalar",
"z": { "comment": "y coordinate"
"type": "f32", },
"kind": "scalar", "z": {
"comment": "z coordinate" "type": "f32",
"kind": "scalar",
"comment": "z coordinate"
}
} }
}, },
"Login": { "Login": {
"Email": { "comment": "The login object",
"type": "string", "members": {
"kind": "string", "Email": {
"size": "256", "type": "string",
"comment": "Email of the user" "kind": "string",
}, "size": "256",
"Password": { "comment": "Email of the user"
"type": "string", },
"kind": "string", "Password": {
"size": "64", "type": "string",
"comment": "Password of the user" "kind": "string",
"size": "64",
"comment": "Password of the user"
}
} }
}, },
"User": { "User": {
"Name": { "comment": "The user object",
"type": "string", "members": {
"kind": "string", "Name": {
"size": "24", "type": "string",
"comment": "Name of the user" "kind": "string",
}, "size": "24",
"Login": { "comment": "Name of the user"
"type": "Login", },
"kind": "struct", "Login": {
"comment": "user login info" "type": "Login",
}, "kind": "struct",
"Position": { "comment": "user login info"
"type": "Vector3", },
"kind": "struct", "Position": {
"comment": "last logout position of user" "type": "Vector3",
"kind": "struct",
"comment": "last logout position of user"
}
} }
}, },
"LoginRequest": { "LoginRequest": {
"Login": { "comment": "a request for a login",
"type": "Login", "members": {
"kind": "struct", "Login": {
"comment": "user login info" "type": "Login",
"kind": "struct",
"comment": "user login info"
}
} }
}, },
"LoginResponse": { "LoginResponse": {
"success": { "comment": "the response from a login request",
"type": "i8", "members": {
"kind": "scalar", "success": {
"comment": "login was successful or not" "type": "logical",
"kind": "scalar",
"comment": "login was successful or not"
}
} }
} }
} }

View File

@ -2,32 +2,17 @@
#include <stdlib.h> #include <stdlib.h>
#include <emscripten/websocket.h> #include <emscripten/websocket.h>
#include <assert.h> #include <assert.h>
#include "out/types.h" #include "build/types.h"
EM_BOOL WebSocketOpen(int eventType, const EmscriptenWebSocketOpenEvent *e, void *userData) { EM_BOOL WebSocketOpen(int eventType, const EmscriptenWebSocketOpenEvent *e, void *userData) {
printf("open(eventType=%d, userData=%p)\n", eventType, userData); printf("open(eventType=%d, userData=%p)\n", eventType, userData);
Camera3D camera = {0}; LoginRequest req = (LoginRequest){
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){
"Zongor", "Zongor",
camera, "Password"
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
}; };
emscripten_websocket_send_binary(e->socket, &entity, sizeof(entity)); emscripten_websocket_send_binary(e->socket, &req, sizeof(req));
return 0; 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) { 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); 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; LoginResponse response;
memcpy(&entity, e->data, sizeof entity); memcpy(&response, e->data, sizeof response);
printf("x: %f", entity.Camera.position.x); printf("response: %d\n", response.success);
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");
emscripten_websocket_close(e->socket, 0, 0); emscripten_websocket_close(e->socket, 0, 0);
emscripten_websocket_delete(e->socket); emscripten_websocket_delete(e->socket);

View File

@ -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 decoder = new TextDecoder("utf-8");
var port = 8089; var port = 8089;
@ -13,13 +14,12 @@ wss.on("connection", function (ws) {
console.log("received TEXT: " + text.length + " characters:"); console.log("received TEXT: " + text.length + " characters:");
console.log(' "' + text + '"'); console.log(' "' + text + '"');
} else { } else {
const entity = new Entity({}, new Uint8Array(message)); const entity = new LoginRequest({}, new Uint8Array(message));
console.log(entity.Camera.position.x, entity.Camera.position.y, entity.Camera.position.z); console.log(entity.Login.Email);
console.log(entity.Name); console.log(entity.Login.Password);
console.log(entity.Luck);
console.log(entity.bytes);
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
} }
}); });
}); });

View File

@ -1,6 +1,12 @@
import { parseArgs } from "util"; import { parseArgs } from "util";
let types = { let types = {
logical: {
c: "char",
js: "boolean",
sql: "INTEGER",
size: 1,
},
u8: { u8: {
c: "unsigned char", c: "unsigned char",
js: "Uint8", js: "Uint8",
@ -85,20 +91,24 @@ const { values } = parseArgs({
allowPositionals: true, allowPositionals: true,
}); });
function jsStructConstructor(size, containsString) { function jsStructConstructor(size, containsString, type, args) {
return ` 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() { get bytes() {
return new Uint8Array(this._ptr); 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) { constructor(init = {}, ptr = undefined) {
this._size = ${size}; 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); this._data = new DataView(this._ptr);
${ ${
containsString containsString
@ -125,7 +135,9 @@ for (const type of Object.keys(schema)) {
let importStatements = ""; let importStatements = "";
let jsData = ""; let jsData = "";
let foreignKeys = ""; 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`; sqlData += `CREATE TABLE ${type} (id INTEGER PRIMARY KEY AUTOINCREMENT`;
cData += `typedef struct ${type} {`; cData += `typedef struct ${type} {`;
jsData += `class ${type} {`; jsData += `class ${type} {`;
@ -141,35 +153,49 @@ for (const type of Object.keys(schema)) {
typeSize = props[prop].size; typeSize = props[prop].size;
const iSize = parseInt(offset) + parseInt(typeSize); const iSize = parseInt(offset) + parseInt(typeSize);
jsData += ` jsData += `
${(comment) ? `/** /**
* ${comment} * ${comment}
*/` : ""} * @return {string} gets the value of ${prop}
*/
get ${prop}() { get ${prop}() {
return this._decoder.decode(new Uint8Array(this._ptr.slice(${parseInt( return this._decoder.decode(new Uint8Array(this._ptr.slice(${parseInt(
offset offset
)}, ${iSize}))); )}, ${iSize})));
} }
/**
* ${comment}
* @param {string} v sets the value of ${prop}
*/
set ${prop}(v) { set ${prop}(v) {
this._data.set(this._encoder.encode(v), ${parseInt(offset)}); this._data.set(this._encoder.encode(v), ${parseInt(offset)});
}`; }`;
sqlData += `, ${prop} TEXT`; sqlData += `, ${prop} TEXT`;
cData += ` cData += `
char ${prop}[${iSize}]; // ${comment}`; char ${prop}[${iSize}]; // ${comment}`;
args += `${prop}: string, `;
typeDef += ` * @property {string} ${prop} ${comment}\n`;
break; break;
case "scalar": case "scalar":
typeSize = types[propType].size; typeSize = types[propType].size;
jsData += ` jsData += `
${(comment) ? `/** /**
* ${comment} * ${comment}
*/` : ""} * @return {${types[propType].js}} gets the value of ${prop}
*/
get ${prop}() { get ${prop}() {
return this._data.get${types[propType].js}(${parseInt(offset)}, true); return this._data.get${types[propType].js}(${parseInt(offset)}, true);
} }
/**
* ${comment}
* @param {${types[propType].js}} sets the value of ${prop}
*/
set ${prop}(v) { set ${prop}(v) {
return this._data.set${types[propType].js}(${parseInt( return this._data.set${types[propType].js}(${parseInt(
offset offset
)}, v, true); )}, v, true);
}`; }`;
args += `${prop}: ${types[propType].js}, `;
typeDef += ` * @property ${types[propType].js} ${propType} ${comment}\n`;
sqlData += `, ${prop} ${types[propType].sql}`; sqlData += `, ${prop} ${types[propType].sql}`;
cData += ` cData += `
${types[propType].c} ${prop}; // ${comment}`; ${types[propType].c} ${prop}; // ${comment}`;
@ -178,12 +204,17 @@ for (const type of Object.keys(schema)) {
case "struct": case "struct":
const jsSize = parseInt(offset) + parseInt(types[propType].size); const jsSize = parseInt(offset) + parseInt(types[propType].size);
jsData += ` jsData += `
${(comment) ? `/** /**
* ${comment} * ${comment}
*/` : ""} * @return {${types[propType].js}} gets the value of ${prop}
*/
get ${prop}() { get ${prop}() {
return new ${propType}({}, new Uint8Array(this._ptr.slice(${offset}, ${jsSize}))); return new ${propType}({}, new Uint8Array(this._ptr.slice(${offset}, ${jsSize})));
} }
/**
* ${comment}
* @param {${types[propType].js}} sets the value of ${prop}
*/
set ${prop}(v) { set ${prop}(v) {
this._data.set(v.bytes(), ${offset}); this._data.set(v.bytes(), ${offset});
}`; }`;
@ -192,7 +223,8 @@ for (const type of Object.keys(schema)) {
importStatements += importS; importStatements += importS;
} }
const localKey = `${prop.toLowerCase()}_id`; const localKey = `${prop.toLowerCase()}_id`;
args += `${prop}: ${types[propType].js}, `;
typeDef += ` * @property ${types[propType].js} ${propType} ${comment}\n`;
sqlData += `, ${localKey} INTEGER`; sqlData += `, ${localKey} INTEGER`;
foreignKeys += `\n, FOREIGN KEY(${localKey}) REFERENCES ${propType}(id)` foreignKeys += `\n, FOREIGN KEY(${localKey}) REFERENCES ${propType}(id)`
cData += `\n\t\t${types[propType].c} ${prop}; // ${comment}`; cData += `\n\t\t${types[propType].c} ${prop}; // ${comment}`;
@ -217,7 +249,10 @@ for (const type of Object.keys(schema)) {
size: parseInt(size), 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}`; jsData += `\n}\n\nexport default ${type}`;
cData += `\n} ${type};\n\n`; cData += `\n} ${type};\n\n`;
sqlData += `${foreignKeys});\n\n`; sqlData += `${foreignKeys});\n\n`;