|
QLua
Lua-Qt bindings
|
00001 #pragma once 00002 // QLua - Copyright (c) 2012, Ugo Varetto 00003 // All rights reserved. 00004 // 00005 // Redistribution and use in source and binary forms, with or without 00006 // modification, are permitted provided that the following conditions are met: 00007 // * Redistributions of source code must retain the above copyright 00008 // notice, this list of conditions and the following disclaimer. 00009 // * Redistributions in binary form must reproduce the above copyright 00010 // notice, this list of conditions and the following disclaimer in the 00011 // documentation and/or other materials provided with the distribution. 00012 // * Neither the name of the <organization> nor the 00013 // names of its contributors may be used to endorse or promote products 00014 // derived from this software without specific prior written permission. 00015 // 00016 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00017 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00018 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00019 // DISCLAIMED. IN NO EVENT SHALL UGO VARETTO BE LIABLE FOR ANY 00020 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00021 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00022 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00023 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00024 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00025 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 00029 00030 extern "C" { 00031 #include "lua.h" 00032 #include "lauxlib.h" 00033 #include "lualib.h" 00034 } 00035 00036 #include <iostream> 00037 #include <string> 00038 00039 #include <QString> 00040 #include <QVariant> 00041 #include <QVariantMap> 00042 #include <QGenericArgument> 00043 #include <QList> 00044 #include <QVector> 00045 00046 #define QLUA_LIST_FLOAT64 "QList<double>" 00047 #define QLUA_LIST_FLOAT32 "QList<float>" 00048 #define QLUA_LIST_INT "QList<int>" 00049 #define QLUA_LIST_SHORT "QList<short>" 00050 #define QLUA_VECTOR_FLOAT64 "QVector<double>" 00051 #define QLUA_VECTOR_FLOAT32 "QVector<float>" 00052 #define QLUA_VECTOR_INT "QVector<int>" 00053 #define QLUA_VECTOR_SHORT "QVector<short>" 00054 #define QLUA_STRING_LIST "QList<QString>" 00055 00057 namespace qlua { 00058 00059 //------------------------------------------------------------------------------ 00060 template < typename T > const char* TypeName(); 00061 00062 template <> inline const char* TypeName< QList< double > >() { return QLUA_LIST_FLOAT64; } 00063 template <> inline const char* TypeName< QList< float > >() { return QLUA_LIST_FLOAT32; } 00064 template <> inline const char* TypeName< QList< int > >() { return QLUA_LIST_INT; } 00065 template <> inline const char* TypeName< QList< short > >() { return QLUA_LIST_SHORT; } 00066 template <> inline const char* TypeName< QVector< double > >() { return QLUA_VECTOR_FLOAT64; } 00067 template <> inline const char* TypeName< QVector< float > >() { return QLUA_VECTOR_FLOAT32; } 00068 template <> inline const char* TypeName< QVector< int > >() { return QLUA_VECTOR_INT; } 00069 template <> inline const char* TypeName< QVector< short > >() { return QLUA_VECTOR_SHORT; } 00070 template <> inline const char* TypeName< QList< QString > >() { return QLUA_STRING_LIST; } 00071 00072 //------------------------------------------------------------------------------ 00073 inline 00074 QString LuaKeyToQString( lua_State* L, int idx ) { 00075 if( lua_isnumber( L, idx ) ) { 00076 return QString( "%1" ).arg( lua_tointeger( L, idx ) ); 00077 } else if( lua_isstring( L, idx ) ) { 00078 return lua_tostring( L, idx ); 00079 } else return ""; 00080 } 00081 00082 //------------------------------------------------------------------------------ 00083 template < typename ToT, typename FromT > 00084 bool ConvertibleTo( FromT v ) { 00085 return FromT( ToT( v ) ) == v; 00086 } 00087 00088 //============================================================================== 00089 // Lua -> C++ 00090 00091 //------------------------------------------------------------------------------ 00095 inline 00096 QVariant LuaValueToQVariant( lua_State* L, int idx ) { 00097 if( lua_isboolean( L, idx ) ) { 00098 return bool( lua_toboolean( L, idx ) ); 00099 } else if( lua_isnumber( L, idx ) ) { 00100 #ifdef QLUA_CONVERT_NUMBER 00101 const double N = lua_tonumber( L, idx ); 00102 if( ConvertibleTo< int >( N ) ) return int( N ); 00103 else if( ConvertibleTo< unsigned int >( N ) ) return (unsigned int)( N ); 00104 else if( ConvertibleTo< long long >( N ) ) return long( N ); 00105 else if( ConvertibleTo< unsigned long long >( N ) ) return (unsigned long long)( N ); 00106 else if( ConvertibleTo< float >( N ) ) return float( N ); 00107 else return N; 00108 #else 00109 return lua_tonumber( L, idx ); 00110 #endif 00111 } else if( lua_islightuserdata( L, idx ) ) { 00112 return lua_topointer( L, idx ); 00113 } else if( lua_isstring( L, idx ) ) { 00114 return lua_tostring( L, idx ); 00115 } else return QVariant(); 00116 } 00117 00118 //------------------------------------------------------------------------------ 00123 template < typename T > 00124 QList< T > ParseLuaTableAsNumberList( lua_State* L, int stackTableIndex ) { 00125 luaL_checktype( L, stackTableIndex, LUA_TTABLE ); 00126 #if LUA_VERSION_NUM > 501 00127 int tableSize = int( lua_rawlen( L, stackTableIndex ) ); 00128 #else 00129 int tableSize = int( lua_objlen( L, stackTableIndex ) ); 00130 #endif 00131 QList< T > list; 00132 list.reserve( int( tableSize ) ); 00133 ++tableSize; 00134 for( int i = 1; i != tableSize; ++i ) { 00135 lua_rawgeti( L, stackTableIndex, i ); 00136 list.push_back( T( lua_tonumber( L, -1 ) ) ); 00137 lua_pop( L, 1 ); 00138 } 00139 return list; 00140 } 00141 //------------------------------------------------------------------------------ 00146 inline 00147 QStringList ParseLuaTableAsStringList( lua_State* L, int stackTableIndex ) { 00148 luaL_checktype( L, stackTableIndex, LUA_TTABLE ); 00149 #if LUA_VERSION_NUM > 501 00150 int tableSize = int( lua_rawlen( L, stackTableIndex ) ); 00151 #else 00152 int tableSize = int( lua_objlen( L, stackTableIndex ) ); 00153 #endif 00154 QStringList list; 00155 list.reserve( int( tableSize ) ); 00156 ++tableSize; 00157 for( int i = 1; i != tableSize; ++i ) { 00158 lua_rawgeti( L, stackTableIndex, i ); 00159 list.push_back( QString( lua_tostring( L, -1 ) ) ); 00160 lua_pop( L, 1 ); 00161 } 00162 return list; 00163 } 00164 //------------------------------------------------------------------------------ 00169 template < typename T > 00170 QVector< T > ParseLuaTableAsNumberVector( lua_State* L, int stackTableIndex ) { 00171 #if LUA_VERSION_NUM > 501 00172 int tableSize = int( lua_rawlen( L, stackTableIndex ) ); 00173 #else 00174 int tableSize = int( lua_objlen( L, stackTableIndex ) ); 00175 #endif 00176 QVector< T > v; 00177 v.resize( int( tableSize ) ); 00178 ++tableSize; 00179 typename QVector< T >::iterator vi = v.begin(); 00180 for( int i = 1; i != tableSize; ++i, ++vi ) { 00181 lua_rawgeti( L, stackTableIndex, i ); 00182 *vi = T( lua_tonumber( L, -1 ) ); 00183 lua_pop( L, 1 ); 00184 } 00185 return v; 00186 } 00187 00188 //------------------------------------------------------------------------------ 00196 inline 00197 QVariantMap ParseLuaTable( lua_State* L, int stackTableIndex, bool removeTable = true ) { 00198 luaL_checktype( L, stackTableIndex, LUA_TTABLE ); 00199 QVariantMap m; 00200 lua_pushnil(L); // first key 00201 stackTableIndex = stackTableIndex < 0 ? stackTableIndex - 1 : stackTableIndex; 00202 while( lua_next( L, stackTableIndex ) != 0 ) { 00203 /* uses 'key' (at index -2) and 'value' (at index -1) */ 00204 QString key = LuaKeyToQString( L, -2 ); 00205 QVariant value = lua_istable( L, -1 ) ? ParseLuaTable( L, -1, false ) : 00206 LuaValueToQVariant( L, -1 ); 00207 m[ key ] = value; 00208 lua_pop(L, 1); 00209 } 00210 if( removeTable ) lua_pop( L, 1 ); // remvove table 00211 return m; 00212 } 00213 //------------------------------------------------------------------------------ 00218 inline 00219 QVariantList ParseLuaTableAsVariantList( lua_State* L, int stackTableIndex ) { 00220 luaL_checktype( L, stackTableIndex, LUA_TTABLE ); 00221 QVariantList l; 00222 lua_pushnil(L); // first key 00223 stackTableIndex = stackTableIndex < 0 ? stackTableIndex - 1 : stackTableIndex; 00224 while( lua_next( L, stackTableIndex ) != 0 ) { 00225 /* uses 'key' (at index -2) and 'value' (at index -1) */ 00226 QVariant value = lua_istable( L, -1 ) ? ParseLuaTable( L, -1, false ) : 00227 LuaValueToQVariant( L, -1 ); 00228 l.push_back( value ); 00229 lua_pop(L, 1); 00230 } 00231 return l; 00232 } 00233 00234 00235 //============================================================================= 00236 // C++ -> Lua 00237 00238 void VariantMapToLuaTable( const QVariantMap&, lua_State* ); 00239 void VariantListToLuaTable( const QVariantList&, lua_State* ); 00240 00241 //------------------------------------------------------------------------------ 00246 inline 00247 void VariantToLuaValue( const QVariant& v, lua_State* L ) { 00248 00249 switch( v.type() ) { 00250 case QVariant::Map: VariantMapToLuaTable( v.toMap(), L ); 00251 break; 00252 case QVariant::List: VariantListToLuaTable( v.toList(), L ); 00253 break; 00254 case QVariant::String: lua_pushstring( L, v.toString().toAscii().constData() ); 00255 break; 00256 case QVariant::Int: lua_pushinteger( L, v.toInt() ); 00257 break; 00258 case QVariant::UInt: lua_pushnumber( L, v.toUInt() ); 00259 break; 00260 case QVariant::LongLong: lua_pushnumber( L, v.toLongLong() ); 00261 break; 00262 case QVariant::ULongLong: lua_pushnumber( L, v.toULongLong() ); 00263 break; 00264 case QVariant::Bool: lua_pushboolean( L, v.toBool() ); 00265 break; 00266 case QVariant::Double: lua_pushnumber( L, v.toDouble() ); 00267 break; 00268 default: break; 00269 } 00270 } 00271 00272 //------------------------------------------------------------------------------ 00277 inline 00278 void VariantMapToLuaTable( const QVariantMap& vm, lua_State* L ) { 00279 lua_newtable( L ); 00280 for( QVariantMap::const_iterator i = vm.begin(); i != vm.end(); ++i ) { 00281 lua_pushstring( L, i.key().toAscii().constData() ); 00282 VariantToLuaValue( i.value(), L ); 00283 lua_rawset( L, -3 ); 00284 } 00285 } 00286 //------------------------------------------------------------------------------ 00291 inline 00292 void VariantListToLuaTable( const QVariantList& vl, lua_State* L ) { 00293 lua_newtable( L ); 00294 int i = 1; 00295 for( QVariantList::const_iterator v = vl.begin(); v != vl.end(); ++v, ++i ) { 00296 lua_pushinteger( L, i ); 00297 VariantToLuaValue( *v, L ); 00298 lua_rawset( L, -3 ); 00299 } 00300 } 00301 //------------------------------------------------------------------------------ 00306 template < typename T > 00307 void NumberListToLuaTable( const QList< T >& l, lua_State* L ) { 00308 lua_newtable( L ); 00309 int i = 1; 00310 for( typename QList< T >::const_iterator v = l.begin(); v != l.end(); ++v, ++i ) { 00311 lua_pushnumber( L, *v ); 00312 lua_rawseti( L, -2, i ); 00313 } 00314 } 00315 //------------------------------------------------------------------------------ 00320 template < typename T > 00321 void NumberVectorToLuaTable( const QVector< T >& v, lua_State* L ) { 00322 lua_newtable( L ); 00323 int i = 1; 00324 for( typename QVector< T >::const_iterator vi = v.begin(); vi != v.end(); ++vi, ++i ) { 00325 lua_pushnumber( L, *vi ); 00326 lua_rawseti( L, -2, i ); 00327 } 00328 } 00329 //------------------------------------------------------------------------------ 00334 inline 00335 void StringListToLuaTable( const QStringList& sl, lua_State* L ) { 00336 lua_newtable( L ); 00337 int i = 1; 00338 for( QStringList::const_iterator v = sl.begin(); v != sl.end(); ++v, ++i ) { 00339 lua_pushinteger( L, i ); 00340 lua_pushstring( L, v->toAscii().constData() ); 00341 lua_rawset( L, -3 ); 00342 } 00343 } 00344 }
1.7.4