degesch: begin work on direct introspection
This commit is contained in:
parent
7e64fd9886
commit
fed8b06aff
200
degesch.c
200
degesch.c
|
@ -1241,6 +1241,49 @@ weak_unref (struct weak_ref_link **list, struct weak_ref_link **link)
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
// Simple introspection framework to simplify exporting stuff to Lua, since
|
||||||
|
// there is a lot of it. While not fully automated, at least we have control
|
||||||
|
// over which fields are exported.
|
||||||
|
|
||||||
|
enum ispect_type
|
||||||
|
{
|
||||||
|
ISPECT_BOOL,
|
||||||
|
ISPECT_INT,
|
||||||
|
ISPECT_UINT,
|
||||||
|
ISPECT_SIZE,
|
||||||
|
ISPECT_STRING,
|
||||||
|
#if 0
|
||||||
|
// TODO: also str_map, str_vector
|
||||||
|
ISPECT_REF, ///< Weakly referenced
|
||||||
|
ISPECT_LIST, ///< Typically copied, depending on type
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: once this finalizes, turn instatiations into macros
|
||||||
|
struct ispect
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
// - "list" flag?
|
||||||
|
// - weak_ref/weak_unref methods?
|
||||||
|
struct ispect_field *fields; ///< Fields
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ispect_field
|
||||||
|
{
|
||||||
|
const char *name; ///< Name of the field
|
||||||
|
size_t offset; ///< Offset in the structure
|
||||||
|
enum ispect_type type; ///< Type of the field
|
||||||
|
struct ispect *subtype; ///< Subtype information
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ISPECT(object, field, type) \
|
||||||
|
{ #field, offsetof (struct object, field), ISPECT_ ## type, NULL },
|
||||||
|
#define ISPECT_(object, field, type, subtype) \
|
||||||
|
{ #field, offsetof (struct object, field), ISPECT_ ## type, \
|
||||||
|
&g_ ## subtype ## _type },
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
struct user_channel
|
struct user_channel
|
||||||
{
|
{
|
||||||
LIST_HEADER (struct user_channel)
|
LIST_HEADER (struct user_channel)
|
||||||
|
@ -1279,6 +1322,18 @@ struct user
|
||||||
struct user_channel *channels; ///< Channels the user is on
|
struct user_channel *channels; ///< Channels the user is on
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ispect_field g_user_ispect_fields[] =
|
||||||
|
{
|
||||||
|
ISPECT( user, nickname, STRING )
|
||||||
|
ISPECT( user, away, BOOL )
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ispect g_user_ispect =
|
||||||
|
{
|
||||||
|
.fields = g_user_ispect_fields,
|
||||||
|
};
|
||||||
|
|
||||||
static struct user *
|
static struct user *
|
||||||
user_new (void)
|
user_new (void)
|
||||||
{
|
{
|
||||||
|
@ -1347,6 +1402,20 @@ struct channel
|
||||||
bool left_manually; ///< Don't rejoin on reconnect
|
bool left_manually; ///< Don't rejoin on reconnect
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ispect_field g_channel_ispect_fields[] =
|
||||||
|
{
|
||||||
|
ISPECT( channel, name, STRING )
|
||||||
|
ISPECT( channel, topic, STRING )
|
||||||
|
ISPECT( channel, users_len, SIZE )
|
||||||
|
ISPECT( channel, left_manually, BOOL )
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ispect g_channel_ispect =
|
||||||
|
{
|
||||||
|
.fields = g_channel_ispect_fields,
|
||||||
|
};
|
||||||
|
|
||||||
static struct channel *
|
static struct channel *
|
||||||
channel_new (void)
|
channel_new (void)
|
||||||
{
|
{
|
||||||
|
@ -1519,6 +1588,21 @@ struct buffer
|
||||||
struct user *user; ///< Reference to user
|
struct user *user; ///< Reference to user
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ispect_field g_buffer_ispect_fields[] =
|
||||||
|
{
|
||||||
|
ISPECT( buffer, name, STRING )
|
||||||
|
ISPECT( buffer, new_messages_count, UINT )
|
||||||
|
ISPECT( buffer, new_unimportant_count, UINT )
|
||||||
|
ISPECT( buffer, highlighted, BOOL )
|
||||||
|
ISPECT( buffer, hide_unimportant, BOOL )
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ispect g_buffer_ispect =
|
||||||
|
{
|
||||||
|
.fields = g_buffer_ispect_fields,
|
||||||
|
};
|
||||||
|
|
||||||
static struct buffer *
|
static struct buffer *
|
||||||
buffer_new (struct input *input)
|
buffer_new (struct input *input)
|
||||||
{
|
{
|
||||||
|
@ -1667,6 +1751,23 @@ struct server
|
||||||
unsigned irc_max_modes; ///< Max parametrized modes per command
|
unsigned irc_max_modes; ///< Max parametrized modes per command
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ispect_field g_server_ispect_fields[] =
|
||||||
|
{
|
||||||
|
ISPECT( server, name, STRING )
|
||||||
|
ISPECT( server, state, INT )
|
||||||
|
ISPECT( server, reconnect_attempt, UINT )
|
||||||
|
ISPECT( server, manual_disconnect, BOOL )
|
||||||
|
ISPECT( server, irc_user_host, STRING )
|
||||||
|
ISPECT( server, autoaway_active, BOOL )
|
||||||
|
ISPECT( server, cap_echo_message, BOOL )
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ispect g_server_ispect =
|
||||||
|
{
|
||||||
|
.fields = g_server_ispect_fields,
|
||||||
|
};
|
||||||
|
|
||||||
static void on_irc_timeout (void *user_data);
|
static void on_irc_timeout (void *user_data);
|
||||||
static void on_irc_ping_timeout (void *user_data);
|
static void on_irc_ping_timeout (void *user_data);
|
||||||
static void on_irc_autojoin_timeout (void *user_data);
|
static void on_irc_autojoin_timeout (void *user_data);
|
||||||
|
@ -8418,6 +8519,10 @@ typedef void (*lua_weak_unref_fn) (void *object, struct weak_ref_link **link);
|
||||||
struct lua_weak_info
|
struct lua_weak_info
|
||||||
{
|
{
|
||||||
const char *name; ///< Metatable name
|
const char *name; ///< Metatable name
|
||||||
|
struct ispect *ispect; ///< Introspection data
|
||||||
|
|
||||||
|
// XXX: not sure if these should be _here_ and not in "struct ispect"
|
||||||
|
|
||||||
lua_weak_ref_fn ref; ///< Weak link invalidator
|
lua_weak_ref_fn ref; ///< Weak link invalidator
|
||||||
lua_weak_unref_fn unref; ///< Weak link generator
|
lua_weak_unref_fn unref; ///< Weak link generator
|
||||||
};
|
};
|
||||||
|
@ -8425,6 +8530,7 @@ struct lua_weak_info
|
||||||
struct lua_weak
|
struct lua_weak
|
||||||
{
|
{
|
||||||
struct lua_plugin *plugin; ///< The plugin we belong to
|
struct lua_plugin *plugin; ///< The plugin we belong to
|
||||||
|
struct lua_weak_info *info; ///< Introspection data
|
||||||
void *object; ///< The object
|
void *object; ///< The object
|
||||||
struct weak_ref_link *weak_ref; ///< A weak reference link
|
struct weak_ref_link *weak_ref; ///< A weak reference link
|
||||||
};
|
};
|
||||||
|
@ -8455,6 +8561,7 @@ lua_weak_push (struct lua_plugin *plugin, void *object,
|
||||||
struct lua_weak *wrapper = lua_newuserdata (L, sizeof *wrapper);
|
struct lua_weak *wrapper = lua_newuserdata (L, sizeof *wrapper);
|
||||||
luaL_setmetatable (L, info->name);
|
luaL_setmetatable (L, info->name);
|
||||||
wrapper->plugin = plugin;
|
wrapper->plugin = plugin;
|
||||||
|
wrapper->info = info;
|
||||||
wrapper->object = object;
|
wrapper->object = object;
|
||||||
wrapper->weak_ref = info->ref (object, lua_weak_invalidate, wrapper);
|
wrapper->weak_ref = info->ref (object, lua_weak_invalidate, wrapper);
|
||||||
lua_cache_store (L, object, -1);
|
lua_cache_store (L, object, -1);
|
||||||
|
@ -8487,6 +8594,7 @@ lua_weak_deref (lua_State *L, const struct lua_weak_info *info)
|
||||||
static struct lua_weak_info lua_ ## id ## _info = \
|
static struct lua_weak_info lua_ ## id ## _info = \
|
||||||
{ \
|
{ \
|
||||||
.name = metatable_id, \
|
.name = metatable_id, \
|
||||||
|
.ispect = &g_ ## id ## _ispect, \
|
||||||
.ref = (lua_weak_ref_fn) id ## _weak_ref, \
|
.ref = (lua_weak_ref_fn) id ## _weak_ref, \
|
||||||
.unref = (lua_weak_unref_fn) id ## _weak_unref, \
|
.unref = (lua_weak_unref_fn) id ## _weak_unref, \
|
||||||
};
|
};
|
||||||
|
@ -8509,15 +8617,6 @@ lua_user_gc (lua_State *L)
|
||||||
return lua_weak_gc (L, &lua_user_info);
|
return lua_weak_gc (L, &lua_user_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
lua_user_get_nickname (lua_State *L)
|
|
||||||
{
|
|
||||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_user_info);
|
|
||||||
struct user *user = wrapper->object;
|
|
||||||
lua_pushstring (L, user->nickname);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lua_user_get_channels (lua_State *L)
|
lua_user_get_channels (lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -8537,7 +8636,6 @@ lua_user_get_channels (lua_State *L)
|
||||||
static luaL_Reg lua_user_table[] =
|
static luaL_Reg lua_user_table[] =
|
||||||
{
|
{
|
||||||
{ "__gc", lua_user_gc },
|
{ "__gc", lua_user_gc },
|
||||||
{ "get_nickname", lua_user_get_nickname },
|
|
||||||
{ "get_channels", lua_user_get_channels },
|
{ "get_channels", lua_user_get_channels },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
@ -8550,15 +8648,6 @@ lua_channel_gc (lua_State *L)
|
||||||
return lua_weak_gc (L, &lua_channel_info);
|
return lua_weak_gc (L, &lua_channel_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
lua_channel_get_name (lua_State *L)
|
|
||||||
{
|
|
||||||
struct lua_weak *wrapper = lua_weak_deref (L, &lua_channel_info);
|
|
||||||
struct channel *channel = wrapper->object;
|
|
||||||
lua_pushstring (L, channel->name);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lua_channel_get_users (lua_State *L)
|
lua_channel_get_users (lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -8582,7 +8671,6 @@ lua_channel_get_users (lua_State *L)
|
||||||
static luaL_Reg lua_channel_table[] =
|
static luaL_Reg lua_channel_table[] =
|
||||||
{
|
{
|
||||||
{ "__gc", lua_channel_gc },
|
{ "__gc", lua_channel_gc },
|
||||||
{ "get_name", lua_channel_get_name },
|
|
||||||
{ "get_users", lua_channel_get_users },
|
{ "get_users", lua_channel_get_users },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
@ -8645,7 +8733,6 @@ lua_buffer_execute (lua_State *L)
|
||||||
|
|
||||||
static luaL_Reg lua_buffer_table[] =
|
static luaL_Reg lua_buffer_table[] =
|
||||||
{
|
{
|
||||||
// TODO: some useful methods or values
|
|
||||||
{ "__gc", lua_buffer_gc },
|
{ "__gc", lua_buffer_gc },
|
||||||
{ "get_user", lua_buffer_get_user },
|
{ "get_user", lua_buffer_get_user },
|
||||||
{ "get_channel", lua_buffer_get_channel },
|
{ "get_channel", lua_buffer_get_channel },
|
||||||
|
@ -8692,7 +8779,6 @@ lua_server_send (lua_State *L)
|
||||||
|
|
||||||
static luaL_Reg lua_server_table[] =
|
static luaL_Reg lua_server_table[] =
|
||||||
{
|
{
|
||||||
// TODO: some useful methods or values
|
|
||||||
{ "__gc", lua_server_gc },
|
{ "__gc", lua_server_gc },
|
||||||
{ "get_user", lua_server_get_user },
|
{ "get_user", lua_server_get_user },
|
||||||
{ "get_buffer", lua_server_get_buffer },
|
{ "get_buffer", lua_server_get_buffer },
|
||||||
|
@ -9701,6 +9787,16 @@ static luaL_Reg lua_plugin_library[] =
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
static struct lua_ispect_mapping
|
||||||
|
{
|
||||||
|
struct ispect *ispect; ///< Type info
|
||||||
|
struct lua_weak_info *info; ///< Lua-specific additions
|
||||||
|
}
|
||||||
|
lua_types[] =
|
||||||
|
{
|
||||||
|
{ &g_buffer_ispect, &lua_buffer_info },
|
||||||
|
};
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
lua_plugin_alloc (void *ud, void *ptr, size_t o_size, size_t n_size)
|
lua_plugin_alloc (void *ud, void *ptr, size_t o_size, size_t n_size)
|
||||||
{
|
{
|
||||||
|
@ -9724,6 +9820,35 @@ lua_plugin_panic (lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
lua_plugin_property_get_ispect (lua_State *L, const char *property_name)
|
||||||
|
{
|
||||||
|
struct lua_weak_info *info = lua_touserdata (L, lua_upvalueindex (1));
|
||||||
|
if (!info || !info->ispect)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct lua_weak *weak = luaL_checkudata (L, 1, info->name);
|
||||||
|
// TODO: I think we can do better than this, maybe binary search at least?
|
||||||
|
struct ispect_field *iter;
|
||||||
|
for (iter = info->ispect->fields; iter->name; iter++)
|
||||||
|
if (!strcmp (property_name, iter->name))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (iter->name)
|
||||||
|
{
|
||||||
|
void *p = (uint8_t *) weak->object + iter->offset;
|
||||||
|
switch (iter->type)
|
||||||
|
{
|
||||||
|
case ISPECT_BOOL: lua_pushboolean (L, *(bool *) p); return true;
|
||||||
|
case ISPECT_INT: lua_pushinteger (L, *(int *) p); return true;
|
||||||
|
case ISPECT_UINT: lua_pushinteger (L, *(unsigned *) p); return true;
|
||||||
|
case ISPECT_SIZE: lua_pushinteger (L, *(size_t *) p); return true;
|
||||||
|
case ISPECT_STRING: lua_pushstring (L, *(char **) p); return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lua_plugin_property_get (lua_State *L)
|
lua_plugin_property_get (lua_State *L)
|
||||||
{
|
{
|
||||||
|
@ -9746,6 +9871,10 @@ lua_plugin_property_get (lua_State *L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maybe we can find it via introspection
|
||||||
|
if (lua_plugin_property_get_ispect (L, property_name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
// Or we look for a property set by the user (__gc cannot be overriden)
|
// Or we look for a property set by the user (__gc cannot be overriden)
|
||||||
if (lua_getuservalue (L, 1) != LUA_TTABLE)
|
if (lua_getuservalue (L, 1) != LUA_TTABLE)
|
||||||
lua_pushnil (L);
|
lua_pushnil (L);
|
||||||
|
@ -9787,7 +9916,24 @@ lua_plugin_create_meta (lua_State *L, const char *name, luaL_Reg *fns)
|
||||||
luaL_setfuncs (L, fns, 0);
|
luaL_setfuncs (L, fns, 0);
|
||||||
|
|
||||||
// Emulate properties for convenience
|
// Emulate properties for convenience
|
||||||
lua_pushcfunction (L, lua_plugin_property_get);
|
lua_pushlightuserdata (L, NULL);
|
||||||
|
lua_pushcclosure (L, lua_plugin_property_get, 1);
|
||||||
|
lua_setfield (L, -2, "__index");
|
||||||
|
lua_pushcfunction (L, lua_plugin_property_set);
|
||||||
|
lua_setfield (L, -2, "__newindex");
|
||||||
|
|
||||||
|
lua_pop (L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_plugin_create_weak (lua_State *L, struct lua_weak_info *info, luaL_Reg *fns)
|
||||||
|
{
|
||||||
|
luaL_newmetatable (L, info->name);
|
||||||
|
luaL_setfuncs (L, fns, 0);
|
||||||
|
|
||||||
|
// Emulate properties for convenience
|
||||||
|
lua_pushlightuserdata (L, info);
|
||||||
|
lua_pushcclosure (L, lua_plugin_property_get, 1);
|
||||||
lua_setfield (L, -2, "__index");
|
lua_setfield (L, -2, "__index");
|
||||||
lua_pushcfunction (L, lua_plugin_property_set);
|
lua_pushcfunction (L, lua_plugin_property_set);
|
||||||
lua_setfield (L, -2, "__newindex");
|
lua_setfield (L, -2, "__newindex");
|
||||||
|
@ -9824,10 +9970,10 @@ lua_plugin_load (struct app_context *ctx, const char *filename,
|
||||||
|
|
||||||
// Create metatables for our objects
|
// Create metatables for our objects
|
||||||
lua_plugin_create_meta (L, XLUA_HOOK_METATABLE, lua_hook_table);
|
lua_plugin_create_meta (L, XLUA_HOOK_METATABLE, lua_hook_table);
|
||||||
lua_plugin_create_meta (L, XLUA_USER_METATABLE, lua_user_table);
|
lua_plugin_create_weak (L, &lua_user_info, lua_user_table);
|
||||||
lua_plugin_create_meta (L, XLUA_CHANNEL_METATABLE, lua_channel_table);
|
lua_plugin_create_weak (L, &lua_channel_info, lua_channel_table);
|
||||||
lua_plugin_create_meta (L, XLUA_BUFFER_METATABLE, lua_buffer_table);
|
lua_plugin_create_weak (L, &lua_buffer_info, lua_buffer_table);
|
||||||
lua_plugin_create_meta (L, XLUA_SERVER_METATABLE, lua_server_table);
|
lua_plugin_create_weak (L, &lua_server_info, lua_server_table);
|
||||||
lua_plugin_create_meta (L, XLUA_SCHEMA_METATABLE, lua_schema_table);
|
lua_plugin_create_meta (L, XLUA_SCHEMA_METATABLE, lua_schema_table);
|
||||||
lua_plugin_create_meta (L, XLUA_CONNECTION_METATABLE, lua_connection_table);
|
lua_plugin_create_meta (L, XLUA_CONNECTION_METATABLE, lua_connection_table);
|
||||||
lua_plugin_create_meta (L, XLUA_CONNECTOR_METATABLE, lua_connector_table);
|
lua_plugin_create_meta (L, XLUA_CONNECTOR_METATABLE, lua_connector_table);
|
||||||
|
|
Loading…
Reference in New Issue