From 48c08f0f1e0209dda00f1bcf5651450c792574c6 Mon Sep 17 00:00:00 2001 From: Xu Xingliang Date: Mon, 22 Jul 2024 00:35:37 +0800 Subject: [PATCH] feat(rotable): add metatable support to rotable Use userdata's uservalue as a place to store metatable. Signed-off-by: Xu Xingliang --- src/rotable.c | 30 ++++++++++++++++++++++++++---- src/rotable.h | 8 ++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/rotable.c b/src/rotable.c index 38545eb..a86fc45 100644 --- a/src/rotable.c +++ b/src/rotable.c @@ -134,8 +134,26 @@ static int rotable_udata_index( lua_State* L ) { p = find_key( p, t->n, s ); if( p ) rotable_pushvalue( L, p ); - else + else { + int type = lua_getuservalue( L, 1 ); + if( type == LUA_TTABLE ) { + type = lua_getfield( L, -1, "__index" ); + if( type == LUA_TTABLE ) { + lua_pushvalue( L, 2 ); + lua_gettable( L, -2 ); + return 1; + } + else if( type == LUA_TFUNCTION ){ + lua_pushvalue( L, -2 ); + lua_pushvalue( L, 2 ); + lua_call( L, 2, 1 ); + return 1; + } + } + + /* Otherwise, not found.*/ lua_pushnil( L ); + } return 1; } @@ -185,7 +203,7 @@ static int rotable_udata_pairs( lua_State* L ) { ROTABLE_EXPORT void rotable_newlib( lua_State* L, void const* v ) { rotable_Reg const* reg = (rotable_Reg const*)v; - rotable* t = (rotable*)lua_newuserdata( L, sizeof( *t ) ); + rotable* t = (rotable*)lua_newuserdata( L, sizeof( *t )); lua_pushlightuserdata( L, (void*)unique_address ); lua_rawget( L, LUA_REGISTRYINDEX ); if( !lua_istable( L, -1 ) ) { @@ -218,12 +236,16 @@ ROTABLE_EXPORT void rotable_newlib( lua_State* L, void const* v ) { } } +ROTABLE_EXPORT void rotable_setmetatable( lua_State* L, int idx) { + /* Store a table to uservalue as rotable's "metatable" */ + lua_setuservalue( L, idx ); +} ROTABLE_EXPORT void rotable_newidx( lua_State* L, void const* v ) { rotable_Reg const* reg = (rotable_Reg const*)v; - int i = 0; + int i = 1; lua_pushlightuserdata( L, (void*)v); - for( ; reg[ i ].func; ++i ) { + for( ; reg[ i ].name; ++i ) { if( lv_strcmp( reg[ i-1 ].name, reg[ i ].name ) >= 0 ) { i = 0; break; diff --git a/src/rotable.h b/src/rotable.h index 1b7a9e7..bd1f300 100644 --- a/src/rotable.h +++ b/src/rotable.h @@ -55,4 +55,12 @@ ROTABLE_EXPORT void rotable_newlib( lua_State* L, void const* reg ); * `rotable_Reg` array. */ ROTABLE_EXPORT void rotable_newidx( lua_State* L, void const* reg ); +/** + * Since the rodata's metatable is used to simulate the table itself, + * we use userdata's uservalue to store an optional table as a + * metatable. It's used in the __index method when no match is found + * in the rotable. + */ +ROTABLE_EXPORT void rotable_setmetatable( lua_State* L, int idx); + #endif /* ROTABLE_H_ */