This commit is contained in:
2026-05-07 22:48:55 +03:00
parent 2ccd3a84b5
commit 9b16a7b8e2
6 changed files with 533 additions and 48 deletions

View File

@@ -600,6 +600,84 @@ static int luaArch_unicode_wtrunc(lua_State *L) {
return 1;
}
static int luaArch_userdata_free(lua_State *L) {
luaArch *arch = luaArch_from(L);
size_t user = (size_t)lua_touserdata(L, 1);
nn_freeUserdata(arch->computer, user);
return 0;
}
static int luaArch_userdata_methods(lua_State *L) {
luaArch *arch = luaArch_from(L);
size_t user = (size_t)lua_touserdata(L, 1);
if(!nn_isUserdataValid(arch->computer, user)) {
lua_pushnil(L);
lua_pushstring(L, "no such userdata");
return 2;
}
lua_createtable(L, 0, 0);
size_t idx = 0;
while(true) {
nn_Method m;
if(nn_getUserdataMethod(arch->computer, user, idx, &m)) break;
idx++;
if(m.name == NULL) continue;
lua_pushstring(L, m.name);
lua_createtable(L, 0, 4);
// the method data
{
lua_pushstring(L, "doc");
if(m.doc == NULL) lua_pushnil(L); else lua_pushstring(L, m.doc);
lua_settable(L, -3);
lua_pushstring(L, "direct");
lua_pushboolean(L, (m.flags & NN_DIRECT) != 0);
lua_settable(L, -3);
lua_pushstring(L, "getter");
lua_pushboolean(L, (m.flags & NN_GETTER) != 0);
lua_settable(L, -3);
lua_pushstring(L, "setter");
lua_pushboolean(L, (m.flags & NN_SETTER) != 0);
lua_settable(L, -3);
}
lua_settable(L, -3);
}
return 1;
}
static int luaArch_userdata_invoke(lua_State *L) {
luaArch *arch = luaArch_from(L);
size_t user = (size_t)lua_touserdata(L, 1);
if(!nn_isUserdataValid(arch->computer, user)) {
lua_pushnil(L);
lua_pushstring(L, "no such userdata");
return 2;
}
const char *method = luaL_checkstring(L, 2);
size_t argc = lua_gettop(L);
nn_clearstack(arch->computer);
for(size_t i = 3; i <= argc; i++) {
luaArch_luaToNN(arch, L, i);
}
nn_Exit err = nn_invokeUserdata(arch->computer, user, method);
if(err != NN_OK) {
lua_pushnil(L);
lua_pushstring(L, nn_getError(arch->computer));
return 2;
}
size_t retc = nn_getstacksize(arch->computer);
for(size_t i = 0; i < retc; i++) {
luaArch_nnToLua(arch, L, i);
}
nn_clearstack(arch->computer);
return retc;
}
static void luaArch_loadEnv(lua_State *L) {
lua_createtable(L, 0, 10);
int computer = lua_gettop(L);
@@ -644,6 +722,7 @@ static void luaArch_loadEnv(lua_State *L) {
lua_pushcfunction(L, luaArch_computer_getDeviceInfo);
lua_setfield(L, computer, "getDeviceInfo");
lua_setglobal(L, "computer");
lua_createtable(L, 0, 10);
int component = lua_gettop(L);
lua_pushcfunction(L, luaArch_component_list);
@@ -663,6 +742,7 @@ static void luaArch_loadEnv(lua_State *L) {
lua_pushcfunction(L, luaArch_component_fields);
lua_setfield(L, component, "fields");
lua_setglobal(L, "component");
lua_createtable(L, 0, 10);
int unicode = lua_gettop(L);
lua_pushcfunction(L, luaArch_unicode_char);
@@ -676,6 +756,16 @@ static void luaArch_loadEnv(lua_State *L) {
lua_pushcfunction(L, luaArch_unicode_wtrunc);
lua_setfield(L, unicode, "wtrunc");
lua_setglobal(L, "unicode");
lua_createtable(L, 0, 10);
int userdata = lua_gettop(L);
lua_pushcfunction(L, luaArch_userdata_free);
lua_setfield(L, userdata, "free");
lua_pushcfunction(L, luaArch_userdata_methods);
lua_setfield(L, userdata, "methods");
lua_pushcfunction(L, luaArch_userdata_invoke);
lua_setfield(L, userdata, "invoke");
lua_setglobal(L, "userdata");
}
static nn_Exit luaArch_handler(nn_ArchitectureRequest *req) {

View File

@@ -70,6 +70,44 @@ end
local syncedMethodStats
local function sandboxValue(val)
if type(val) == "table" then
local nt = {}
for k, v in pairs(val) do
local sk, sv = sandboxValue(k), sandboxValue(v)
if sk ~= nil then nt[sk] = sv end
end
return nt
end
if type(val) == "userdata" then
-- Light userdata shall never escape our shi!
-- This matches how OC wraps it
-- TODO: just make our own shi with fields and stuff
-- like a component proxy, because this sucks
local userMeta = {
__gc = function()
userdata.free(val)
end,
}
local wrapped = {type = "userdata"}
for name, m in pairs(userdata.methods(val)) do
wrapped[name] = {
name = name,
proxy = wrapped,
}
setmetatable(wrapped[name], {
__tostring = function() return m.doc or "function" end,
__call = function(_, ...)
return userdata.invoke(val, name, ...)
end,
})
end
return setmetatable(wrapped, userMeta)
end
return val
end
local function realInvoke(address, method, ...)
local t = {pcall(cinvoke, address, method, ...)}
if not _SYNCED and not os.getenv("NN_FAST") then
@@ -83,6 +121,8 @@ local function realInvoke(address, method, ...)
print("got", table.unpack(t))
end
for i=1,#t do t[i] = sandboxValue(t[i]) end
if t[1] then
return table.unpack(t, 2)
end
@@ -477,6 +517,9 @@ sandbox = {
},
utf8 = utf8,
-- unsafe, don't care
userdata = userdata,
}
sandbox._G = sandbox

View File

@@ -42,7 +42,7 @@ static nn_Exit sandbox_handler(nn_ComponentRequest *req) {
return NN_OK;
case NN_COMP_DROP:
return NN_OK;
case NN_COMP_SIGNAL:
case NN_COMP_USERDATA:
return NN_OK;
}
return NN_OK;

View File

@@ -1064,6 +1064,11 @@ nn_Exit nn_resizeDeviceInfoArray(nn_Context *ctx, nn_DeviceInfoArray *arr, size_
return NN_OK;
}
typedef struct nn_Userdata {
void *state;
char *compAddress;
} nn_Userdata;
typedef struct nn_Computer {
nn_ComputerState state;
nn_Universe *universe;
@@ -1092,6 +1097,7 @@ typedef struct nn_Computer {
nn_Architecture archs[NN_MAX_ARCHITECTURES];
nn_Signal signals[NN_MAX_SIGNALS];
char *users[NN_MAX_USERS];
nn_Userdata uservals[NN_MAX_USERDATA];
} nn_Computer;
nn_Universe *nn_createUniverse(nn_Context *ctx, void *userdata) {
@@ -1220,6 +1226,7 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
c->idleTimestamp = 0;
// set to empty string
c->errorBuffer[0] = '\0';
for(size_t i = 0; i < NN_MAX_USERDATA; i++) c->uservals[i].state = NULL;
return c;
}
@@ -1430,8 +1437,9 @@ void nn_destroyComputer(nn_Computer *computer) {
nn_strfree(ctx, computer->users[i]);
}
for(size_t i = 0; i < NN_MAX_USERDATA; i++) nn_freeUserdata(computer, i);
for(nn_ComponentEntry *c = nn_hashIterate(&computer->components, NULL); c != NULL; c = nn_hashIterate(&computer->components, c)) {
nn_signalComponent(c->comp, computer, NN_CSIGUNMOUNTED);
nn_dropComponent(c->comp);
}
@@ -2061,7 +2069,6 @@ nn_Exit nn_mountComponent(nn_Computer *c, nn_Component *comp, int slot, bool sil
};
if(!nn_hashPut(&c->components, &ent)) return NN_ELIMIT;
nn_retainComponent(comp);
nn_signalComponent(comp, c, NN_CSIGMOUNTED);
if(c->state == NN_RUNNING && !silent) {
return nn_pushComponentAdded(c, comp->address, comp->type);
}
@@ -2078,7 +2085,6 @@ nn_Exit nn_unmountComponent(nn_Computer *c, const char *address, bool silent) {
if(c->state == NN_RUNNING && !silent) {
e = nn_pushComponentRemoved(c, address, comp->type);
}
nn_signalComponent(comp, c, NN_CSIGUNMOUNTED);
nn_dropComponent(comp);
return e;
}
@@ -2184,16 +2190,250 @@ nn_Exit nn_invokeComponent(nn_Computer *computer, const char *compAddress, const
return NN_OK;
}
nn_Exit nn_signalComponent(nn_Component *component, nn_Computer *computer, const char *signal) {
nn_ComponentRequest req;
req.ctx = &component->universe->ctx;
req.computer = computer;
req.state = component->state;
req.classState = component->classState;
req.compAddress = component->address;
req.action = NN_COMP_SIGNAL;
req.signal = signal;
return component->handler(&req);
int nn_allocUserdata(nn_Computer *computer, void *state, const char *compAddress) {
for(size_t i = 0; i < NN_MAX_USERDATA; i++) {
if(nn_isUserdataValid(computer, i)) continue;
char *comp = nn_strdup(nn_getComputerContext(computer), compAddress);
if(comp == NULL) return -1;
computer->uservals[i].state = state;
computer->uservals[i].compAddress = comp;
return i;
}
return -1;
}
// Frees a userdata index.
void nn_freeUserdata(nn_Computer *computer, size_t userdata) {
if(!nn_isUserdataValid(computer, userdata)) return;
nn_Context *ctx = nn_getComputerContext(computer);
nn_Userdata *user = computer->uservals + userdata;
nn_UserdataRequest ureq = {
.state = user->state,
.action = NN_USER_DROP,
};
nn_Component *c = nn_getComponent(computer, user->compAddress);
// really, we should *panic*, as this is a BAD state
if(c == NULL) return;
nn_ComponentRequest creq = {
.ctx = ctx,
.computer = computer,
.state = c->state,
.classState = c->classState,
.compAddress = c->address,
.action = NN_COMP_USERDATA,
.methodIdx = 0,
.user = &ureq,
};
// errors in here are catastrophic
c->handler(&creq);
user->state = NULL;
nn_strfree(ctx, user->compAddress);
}
// Returns whether the userdata index is valid
bool nn_isUserdataValid(nn_Computer *computer, size_t userdata) {
if(userdata >= NN_MAX_USERDATA) return false;
return computer->uservals[userdata].state != NULL;
}
// If compAddress is correct and userdata is valid, returns the state pointer.
// If not, returns NULL, to prevent UB.
void *nn_unwrapUserdata(nn_Computer *computer, size_t userdata, const char *compAddress) {
if(!nn_isUserdataValid(computer, userdata)) return NULL;
nn_Userdata user = computer->uservals[userdata];
if(nn_strcmp(user.compAddress, compAddress) != 0) return NULL;
return user.state;
}
// gets the component address which manages this userdata
const char *nn_getUserdataComponent(nn_Computer *computer, size_t userdata) {
if(!nn_isUserdataValid(computer, userdata)) return NULL;
return computer->uservals[userdata].compAddress;
}
// Gets information about a method of this userdata, by index.
// If idx is out of bounds, this returns true, which means to stop iteration.
// If method->name is NULL, the method should be skipped.
bool nn_getUserdataMethod(nn_Computer *computer, size_t userdata, size_t idx, nn_Method *method) {
if(!nn_isUserdataValid(computer, userdata)) return true;
nn_Context *ctx = nn_getComputerContext(computer);
nn_Userdata *user = computer->uservals + userdata;
nn_UserdataRequest ureq = {
.state = user->state,
.action = NN_USER_GETMETHOD,
.getmethod.method = method,
.getmethod.idx = idx,
};
nn_Component *c = nn_getComponent(computer, user->compAddress);
// really, we should *panic*, as this is a BAD state
if(c == NULL) return true;
nn_ComponentRequest creq = {
.ctx = ctx,
.computer = computer,
.state = c->state,
.classState = c->classState,
.compAddress = c->address,
.action = NN_COMP_USERDATA,
.methodIdx = 0,
.user = &ureq,
};
// errors in here are catastrophic
if(c->handler(&creq)) return true;
return ureq.getmethod.method == NULL;
}
// Invokes a method on some userdata, same semantics as nn_invokeComponent
nn_Exit nn_invokeUserdata(nn_Computer *computer, size_t userdata, const char *method) {
if(!nn_isUserdataValid(computer, userdata)) return true;
nn_Context *ctx = nn_getComputerContext(computer);
nn_Userdata *user = computer->uservals + userdata;
nn_UserdataRequest ureq = {
.state = user->state,
.action = NN_USER_INVOKE,
.invoke.method = method,
.invoke.returnCount = 0,
};
nn_Component *c = nn_getComponent(computer, user->compAddress);
// really, we should *panic*, as this is a BAD state
if(c == NULL) return true;
nn_ComponentRequest creq = {
.ctx = ctx,
.computer = computer,
.state = c->state,
.classState = c->classState,
.compAddress = c->address,
.action = NN_COMP_USERDATA,
.methodIdx = 0,
.user = &ureq,
};
// prepare stack for call
while(nn_getstacksize(computer) > 0) {
if(!nn_isnull(computer, nn_getstacksize(computer) - 1)) break;
nn_pop(computer);
}
// errors in here are catastrophic
nn_Exit e = c->handler(&creq);
if(e) {
if(e != NN_EBADCALL) nn_setErrorFromExit(computer, e);
nn_clearstack(computer);
return e;
}
size_t endOfTrim = computer->stackSize - ureq.invoke.returnCount;
for(size_t i = 0; i < endOfTrim; i++) {
nn_dropValue(computer->callstack[i]);
}
for(size_t i = endOfTrim; i < computer->stackSize; i++) {
computer->callstack[i - endOfTrim] = computer->callstack[i];
}
computer->stackSize = ureq.invoke.returnCount;
if(nn_getEnergy(computer) <= 0) {
nn_setError(computer, "out of energy");
return NN_EBADCALL;
}
return NN_OK;
}
// Serializes the userdata into a buffer and pushes it as a string.
// Make sure to keep track of its index and component address!
nn_Exit nn_serializeUserdata(nn_Computer *computer, size_t userdata) {
if(!nn_isUserdataValid(computer, userdata)) return true;
nn_Context *ctx = nn_getComputerContext(computer);
nn_Userdata *user = computer->uservals + userdata;
nn_UserdataRequest ureq = {
.state = user->state,
.action = NN_USER_SERIALIZE,
};
nn_Component *c = nn_getComponent(computer, user->compAddress);
// really, we should *panic*, as this is a BAD state
if(c == NULL) return true;
nn_ComponentRequest creq = {
.ctx = ctx,
.computer = computer,
.state = c->state,
.classState = c->classState,
.compAddress = c->address,
.action = NN_COMP_USERDATA,
.methodIdx = 0,
.user = &ureq,
};
// errors in here are catastrophic
return c->handler(&creq);
}
// Deserializes userdata at a particular index.
// NOTE: if the component does not exist, or the userdata index is already taken, this errors.
nn_Exit nn_deserializeUserdata(nn_Computer *computer, size_t userdata, const char *compAddress, const char *buf, size_t len) {
if(userdata >= NN_MAX_USERDATA) {
nn_setError(computer, "invalid slot");
return NN_EBADCALL;
}
if(nn_isUserdataValid(computer, userdata)) {
nn_setError(computer, "slot taken");
return NN_EBADCALL;
}
nn_Component *c = nn_getComponent(computer, compAddress);
if(c == NULL) {
nn_setError(computer, "no such component");
return NN_EBADCALL;
}
nn_Context *ctx = nn_getComputerContext(computer);
nn_Userdata *user = computer->uservals + userdata;
nn_UserdataRequest ureq = {
.state = user->state,
.action = NN_USER_DESERIALIZE,
.deserialize.data = buf,
.deserialize.len = len,
};
nn_ComponentRequest creq = {
.ctx = ctx,
.computer = computer,
.state = c->state,
.classState = c->classState,
.compAddress = c->address,
.action = NN_COMP_USERDATA,
.methodIdx = 0,
.user = &ureq,
};
char *compAddr = nn_strdup(ctx, compAddress);
if(compAddr == NULL) return NN_ENOMEM;
// errors in here are catastrophic
nn_Exit e = c->handler(&creq);
if(e) {
nn_strfree(ctx, compAddr);
return e;
}
user->state = ureq.state;
user->compAddress = compAddr;
return NN_OK;
}
static void nn_retainValue(nn_Value val) {
@@ -3906,7 +4146,7 @@ typedef enum nn_CompNum {
static nn_Exit nn_computerHandler(nn_ComponentRequest *req) {
if(req->action == NN_COMP_DROP) return NN_OK;
if(req->action == NN_COMP_SIGNAL) return NN_OK;
if(req->action == NN_COMP_USERDATA) return NN_OK;
nn_Computer *src = req->computer;
if(src) nn_setError(src, "computer: not implemented yet");
return NN_EBADCALL;
@@ -3964,7 +4204,7 @@ typedef struct nn_EEState {
} nn_EEState;
static nn_Exit nn_eepromHandler(nn_ComponentRequest *req) {
if(req->action == NN_COMP_SIGNAL) return NN_OK;
if(req->action == NN_COMP_USERDATA) return NN_OK;
if(req->action == NN_COMP_CHECKMETHOD) return NN_OK;
nn_EEState *state = req->classState;
nn_EEPROMRequest ereq;
@@ -4230,7 +4470,7 @@ static nn_Exit nn_fsPathCheck(nn_Computer *C, char buf[NN_MAX_PATH], const char
}
static nn_Exit nn_fsHandler(nn_ComponentRequest *req) {
if(req->action == NN_COMP_SIGNAL) return NN_OK;
if(req->action == NN_COMP_USERDATA) return NN_OK;
if(req->action == NN_COMP_CHECKMETHOD) return NN_OK;
nn_Context *ctx = req->ctx;
nn_FSState *state = req->classState;
@@ -4650,7 +4890,7 @@ static nn_Exit nn_drvHandler(nn_ComponentRequest *request) {
dreq.drv = &state->drive;
nn_Exit e;
if(request->action == NN_COMP_SIGNAL) return NN_OK;
if(request->action == NN_COMP_USERDATA) return NN_OK;
if(request->action == NN_COMP_CHECKMETHOD) return NN_OK;
if(request->action == NN_COMP_DROP) {
@@ -4850,7 +5090,7 @@ static nn_Exit nn_flashHandler(nn_ComponentRequest *request) {
freq.flash = &state->flash;
nn_Exit e;
if(request->action == NN_COMP_SIGNAL) return NN_OK;
if(request->action == NN_COMP_USERDATA) return NN_OK;
if(request->action == NN_COMP_CHECKMETHOD) return NN_OK;
if(request->action == NN_COMP_DROP) {
@@ -5069,7 +5309,7 @@ typedef struct nn_ScreenClassState {
} nn_ScreenClassState;
static nn_Exit nn_screenHandler(nn_ComponentRequest *req) {
if(req->action == NN_COMP_SIGNAL) return NN_OK;
if(req->action == NN_COMP_USERDATA) return NN_OK;
nn_Context *ctx = req->ctx;
nn_ScreenClassState *cls = req->classState;
nn_Computer *C = req->computer;
@@ -5335,7 +5575,7 @@ typedef struct nn_GPUClassState {
static nn_Exit nn_gpuHandler(nn_ComponentRequest *req) {
if(req->action == NN_COMP_CHECKMETHOD) return NN_OK;
if(req->action == NN_COMP_SIGNAL) return NN_OK;
if(req->action == NN_COMP_USERDATA) return NN_OK;
nn_Context *ctx = req->ctx;
nn_GPUClassState *cls = req->classState;
nn_Computer *C = req->computer;
@@ -6125,15 +6365,22 @@ nn_DataCard nn_defaultDataCards[3] = {
.assymetricCost = 10.0,
},
};
typedef struct nn_DataKey {
bool isPublic;
unsigned short bitlen;
size_t bytelen;
char bytes[];
} nn_DataKey;
static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
if(req->action == NN_COMP_SIGNAL) return NN_OK;
nn_Context *ctx = req->ctx;
nn_DataState *state = req->classState;
nn_Computer *C = req->computer;
nn_DataCard dataCard = state->dataCard;
nn_DataNum method = req->methodIdx;
if(req->action == NN_COMP_CHECKMETHOD) {
if(method == NN_DATANUM_SHA256 || method == NN_DATANUM_MD5) {
req->methodEnabled = dataCard.canHash;
@@ -6149,6 +6396,84 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
}
return NN_OK;
}
if(req->action == NN_COMP_USERDATA) {
nn_UserdataRequest *user = req->user;
nn_DataKey *key = user->state;
if(user->action == NN_USER_DROP) {
nn_free(ctx, key, sizeof(*key) + key->bytelen);
return NN_OK;
}
if(user->action == NN_USER_SERIALIZE) {
// its assumed bytelen is not ridiculous
size_t serlen = 2 + key->bytelen;
NN_VLA(unsigned char, ser, serlen);
unsigned short bitsAndPub = (key->bitlen * 2) + (key->isPublic ? 1 : 0);
ser[0] = (bitsAndPub >> 0) & 0xFF;
ser[1] = (bitsAndPub >> 8) & 0xFF;
nn_memcpy(ser + 2, key->bytes, key->bytelen);
return nn_pushlstring(C, (const char *)ser, serlen);
}
if(user->action == NN_USER_DESERIALIZE) {
size_t serlen = user->deserialize.len;
const unsigned char *ser = (const unsigned char *)user->deserialize.data;
size_t bytelen = serlen - 2;
unsigned short bitsAndPub = ((unsigned short)ser[0]) + (((unsigned short)ser[1]) << 8);
key = nn_alloc(ctx, sizeof(*key) + bytelen);
if(key == NULL) return NN_ENOMEM;
key->isPublic = (bitsAndPub&1) != 0;
key->bitlen = bitsAndPub/2;
key->bytelen = bytelen;
nn_memcpy(key->bytes, ser + 2, key->bytelen);
user->state = key;
return NN_OK;
}
if(user->action == NN_USER_GETMETHOD) {
size_t idx = user->getmethod.idx;
nn_Method *m = user->getmethod.method;
if(idx == 0) {
m->name = "serialize";
m->doc = "function(): string - Serializes the key to its array of bytes";
m->flags = NN_DIRECT;
} else if(idx == 1) {
m->name = "keyType";
m->doc = "function(): string - Gets the type of the key (ec-public or ec-private)";
m->flags = NN_DIRECT;
} else if(idx == 2) {
m->name = "isPublic";
m->doc = "function(): boolean - Returns whether this key is public or not";
m->flags = NN_DIRECT;
} else {
user->getmethod.method = NULL;
}
return NN_OK;
}
if(user->action == NN_USER_INVOKE) {
const char *method = user->invoke.method;
if(nn_strcmp(method, "isPublic") == 0) {
user->invoke.returnCount = 1;
return nn_pushbool(C, key->isPublic);
}
if(nn_strcmp(method, "keyType") == 0) {
user->invoke.returnCount = 1;
return nn_pushstring(C, key->isPublic ? "ec-public" : "ec-private");
}
if(nn_strcmp(method, "serialize") == 0) {
user->invoke.returnCount = 1;
return nn_pushlstring(C, key->bytes, key->bytelen);
}
nn_setError(C, "no such method");
return NN_EBADCALL;
}
return NN_OK;
}
nn_DataCardRequest dreq;
dreq.ctx = ctx;
@@ -6332,6 +6657,26 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
return NN_OK;
}
if(method == NN_DATANUM_GENKEYPAIR) {
e = nn_defaultinteger(C, 0, 256);
if(e) return e;
if(nn_checkinteger(C, 0, "bad argument #1 (integer expected)")) return NN_EBADCALL;
size_t bitLen = nn_tointeger(C, 0);
if(bitLen != 256 && bitLen != 384) {
nn_setError(C, "invalid bit length (only 256-bit and 384-bit are supported)");
return NN_EBADCALL;
}
// TODO: this is test code, no OOM check. Implement the correct version and make sure it handles OOMs correctly
size_t keylen = bitLen / 8;
nn_DataKey *key = nn_alloc(ctx, sizeof(*key) + keylen);
key->isPublic = true;
key->bitlen = bitLen;
key->bytelen = keylen;
nn_memset(key->bytes, 'A', key->bytelen);
req->returnCount = 1;
return nn_pushuserdata(C, nn_allocUserdata(C, key, req->compAddress));
}
if(C) nn_setError(C, "data: not implemented yet");
return NN_EBADCALL;
}
@@ -6415,7 +6760,7 @@ typedef struct nn_ModemState {
} nn_ModemState;
static nn_Exit nn_modemHandler(nn_ComponentRequest *req) {
if(req->action == NN_COMP_SIGNAL) return NN_OK;
if(req->action == NN_COMP_USERDATA) return NN_OK;
nn_Context *ctx = req->ctx;
nn_ModemState *state = req->classState;
nn_Computer *C = req->computer;

View File

@@ -659,13 +659,6 @@ typedef struct nn_Method {
nn_MethodFlags flags;
} nn_Method;
// component signals
// mounted
#define NN_CSIGMOUNTED "mounted"
// unmounted
#define NN_CSIGUNMOUNTED "unmounted"
typedef enum nn_ComponentAction {
// component dropped
NN_COMP_DROP,
@@ -674,10 +667,38 @@ typedef enum nn_ComponentAction {
// checking if component method is enabled
// (may be locked by tier)
NN_COMP_CHECKMETHOD,
// signal sent to the machine
NN_COMP_SIGNAL,
// userdata request
NN_COMP_USERDATA,
} nn_ComponentAction;
typedef enum nn_UserdataAction {
NN_USER_DROP,
NN_USER_SERIALIZE,
NN_USER_DESERIALIZE,
NN_USER_GETMETHOD,
NN_USER_INVOKE,
} nn_UserdataAction;
typedef struct nn_UserdataRequest {
void *state;
nn_UserdataAction action;
union {
struct {
const char *data;
size_t len;
} deserialize;
struct {
size_t idx;
// set to NULL if idx is out of bounds
nn_Method *method;
} getmethod;
struct {
const char *method;
size_t returnCount;
} invoke;
};
} nn_UserdataRequest;
typedef struct nn_ComponentRequest {
nn_Context *ctx;
nn_Computer *computer;
@@ -692,8 +713,7 @@ typedef struct nn_ComponentRequest {
size_t returnCount;
// method enabled
bool methodEnabled;
// signal invocation
const char *signal;
nn_UserdataRequest *user;
};
} nn_ComponentRequest;