[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Nested userdata
- From: Luis Carvalho <lexcarvalho@...>
- Date: Mon, 16 Feb 2009 15:07:15 -0500
Hi Jonathan,
On Mon, Feb 16, 2009 at 10:10:06AM -0800, Jonathan wrote:
> I would like to access the following C++ types from lua:
>
> struct A { int x, y; };
> struct B { A a; }
>
> and then in lua do:
>
> b = B:new()
> var = b.a.x
>
> So the best way I can explain this is that I want to have "nested" userdata. Here's what I have so far:
>
> static int B_new (lua_State *L)
> {
> B *b = (B*)lua_newuserdata(L, sizeof(B));
> luaL_getmetatable(L, "B");
> lua_setmetatable(L, -2);
> return 1;
> }
>
> static int A_index (lua_State *L)
> {
> // push 'x' or 'y' depending on key
> }
>
> static int B_index (lua_State *L)
> {
> // what do I push if the key is 'a'? I don't want to allocate new userdata, but I also don't want light user data because I need the metatable.
>
> if (lua_tostring(L, 2) == "a")
> // .. ? ..
> }
Try something like this:
#include <lua.h>
#include <lauxlib.h>
typedef struct { int x, y; } A;
typedef struct { A a; } B;
static A** A_push (lua_State *L, A* a) {
A **p = (A**) lua_newuserdata(L, sizeof(A*));
*p = a;
luaL_getmetatable(L, "A");
lua_setmetatable(L, -2);
return p;
}
static int B_new (lua_State *L) {
B *b = (B*) lua_newuserdata(L, sizeof(B));
luaL_getmetatable(L, "B");
lua_pushvalue(L, -2); /* b */
A_push(L, &(b->a)); /* a */
lua_rawset(L, -3); /* mt[b] = a */
lua_setmetatable(L, -2);
return 1;
}
static int A_index (lua_State *L) {
A **a = (A**) lua_touserdata(L, 1);
const char *k = luaL_checkstring(L, 2);
if (*k == 'x') lua_pushinteger(L, (*a)->x);
else if (*k == 'y') lua_pushinteger(L, (*a)->y);
else luaL_error(L, "unknown key: %s", k);
return 1;
}
static int A_newindex (lua_State *L) {
A **a = (A**) lua_touserdata(L, 1);
const char *k = luaL_checkstring(L, 2);
int v = luaL_checkinteger(L, 3);
if (*k == 'x') (*a)->x = v;
else if (*k == 'y') (*a)->y = v;
else luaL_error(L, "unknown key: %s", k);
return 0;
}
static int B_index (lua_State *L) {
const char *k = luaL_checkstring(L, 2);
if (*k == 'a') {
luaL_getmetatable(L, "B");
lua_pushvalue(L, 1); /* b */
lua_rawget(L, -2);
}
else luaL_error(L, "unknown key: %s", k);
return 1;
}
int luaopen_nestedudata (lua_State *L) {
/* A */
luaL_newmetatable(L, "A");
lua_pushcfunction(L, A_index);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, A_newindex);
lua_setfield(L, -2, "__newindex");
/* B */
luaL_newmetatable(L, "B");
lua_newtable(L);
lua_pushliteral(L, "k");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2); /* B's MT is now weak-keyed */
lua_pushcfunction(L, B_index);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, B_new);
return 1;
}
Test:
$ lua
Lua 5.1.3 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> new = require"nestedudata"
> b = new()
> b.a.x, b.a.y = 1, -1
> print(b, b.a, b.a.x, b.a.y)
userdata: 0x9a4da74 userdata: 0x9a4db54 1 -1
Cheers,
Luis
--
Computers are useless. They can only give you answers.
-- Pablo Picasso
--
Luis Carvalho (Kozure)
lua -e 'print((("lexcarvalho@NO.gmail.SPAM.com"):gsub("(%u+%.)","")))'