| 1109 | } |
| 1110 | |
| 1111 | LuaFunction LuaEngine::createWrappedFunction(LuaDetail::LuaWrappedFunction function) { |
| 1112 | lua_checkstack(m_state, 2); |
| 1113 | |
| 1114 | auto funcUserdata = (LuaDetail::LuaWrappedFunction*)lua_newuserdata(m_state, sizeof(LuaDetail::LuaWrappedFunction)); |
| 1115 | new (funcUserdata) LuaDetail::LuaWrappedFunction(std::move(function)); |
| 1116 | |
| 1117 | lua_rawgeti(m_state, LUA_REGISTRYINDEX, m_wrappedFunctionMetatableRegistryId); |
| 1118 | lua_setmetatable(m_state, -2); |
| 1119 | |
| 1120 | auto invokeFunction = [](lua_State* state) { |
| 1121 | auto func = (LuaDetail::LuaWrappedFunction*)lua_touserdata(state, lua_upvalueindex(1)); |
| 1122 | auto self = luaEnginePtr(state); |
| 1123 | |
| 1124 | int argumentCount = lua_gettop(state); |
| 1125 | try { |
| 1126 | // For speed, if the argument count is less than some pre-defined |
| 1127 | // value, use a stack array. |
| 1128 | int const MaxArrayArgs = 8; |
| 1129 | LuaDetail::LuaFunctionReturn res; |
| 1130 | if (argumentCount <= MaxArrayArgs) { |
| 1131 | Array<LuaValue, MaxArrayArgs> args; |
| 1132 | for (int i = argumentCount - 1; i >= 0; --i) |
| 1133 | args[i] = self->popLuaValue(state); |
| 1134 | res = (*func)(*self, argumentCount, args.ptr()); |
| 1135 | } else { |
| 1136 | List<LuaValue> args(argumentCount); |
| 1137 | for (int i = argumentCount - 1; i >= 0; --i) |
| 1138 | args[i] = self->popLuaValue(state); |
| 1139 | res = (*func)(*self, argumentCount, args.ptr()); |
| 1140 | } |
| 1141 | |
| 1142 | if (auto val = res.ptr<LuaValue>()) { |
| 1143 | self->pushLuaValue(state, *val); |
| 1144 | return 1; |
| 1145 | } else if (auto vec = res.ptr<LuaVariadic<LuaValue>>()) { |
| 1146 | for (auto const& r : *vec) |
| 1147 | self->pushLuaValue(state, r); |
| 1148 | return (int)vec->size(); |
| 1149 | } else { |
| 1150 | return 0; |
| 1151 | } |
| 1152 | } catch (LuaInstructionLimitReached const&) { |
| 1153 | lua_pushlightuserdata(state, &s_luaInstructionLimitExceptionKey); |
| 1154 | return lua_error(state); |
| 1155 | } catch (LuaRecursionLimitReached const&) { |
| 1156 | lua_pushlightuserdata(state, &s_luaRecursionLimitExceptionKey); |
| 1157 | return lua_error(state); |
| 1158 | } catch (std::exception const& e) { |
| 1159 | luaL_where(state, 1); |
| 1160 | lua_pushstring(state, printException(e, true).c_str()); |
| 1161 | lua_concat(state, 2); |
| 1162 | return lua_error(state); |
| 1163 | } |
| 1164 | }; |
| 1165 | |
| 1166 | lua_pushcclosure(m_state, invokeFunction, 1); |
| 1167 | |
| 1168 | return LuaFunction(LuaDetail::LuaHandle(RefPtr<LuaEngine>(this), popHandle(m_state))); |
no test coverage detected