improve an NodeRootLambda interface on LuaJIT
This commit is contained in:
		| @@ -341,15 +341,59 @@ void PushMutableVector(lua_State* L, std::vector<uint8_t>&& v) noexcept { | ||||
|  | ||||
| void PushNodeRootLambda( | ||||
|     lua_State* L, const std::shared_ptr<nf7::NodeRootLambda>& la) noexcept { | ||||
|   constexpr const char* kTypeName = "nf7::NodeRootLambda"; | ||||
|   assert(la); | ||||
|  | ||||
|   using T = std::shared_ptr<nf7::NodeRootLambda>; | ||||
|   new (lua_newuserdata(L, sizeof(T))) T {la}; | ||||
|  | ||||
|   if (luaL_newmetatable(L, kTypeName)) { | ||||
|   if (luaL_newmetatable(L, "nf7::NodeRootLambda")) { | ||||
|     lua_createtable(L, 0, 0); | ||||
|     { | ||||
|       // la:send(nf7, key, value) | ||||
|       lua_pushcfunction(L, [](auto L) { | ||||
|         auto la = CheckNodeRootLambda(L, 1); | ||||
|         la->ExecSend(luaL_checkstring(L, 2), luajit::CheckValue(L, 3)); | ||||
|         return 0; | ||||
|       }); | ||||
|       lua_setfield(L, -2, "send"); | ||||
|  | ||||
|       // la:recv(nf7, {name1, name2, ...}) | ||||
|       lua_pushcfunction(L, [](auto L) { | ||||
|         auto la = CheckNodeRootLambda(L, 1); | ||||
|         auto th = luajit::Thread::GetPtr(L, 2); | ||||
|  | ||||
|         std::vector<std::string> names; | ||||
|         ToStringList(L, 3, names); | ||||
|         if (names.size() == 0) { | ||||
|           return 0; | ||||
|         } | ||||
|  | ||||
|         auto fu = la->Select( | ||||
|             std::unordered_set<std::string>(names.begin(), names.end())); | ||||
|         if (fu.done()) { | ||||
|           try { | ||||
|             const auto& p = fu.value(); | ||||
|             lua_pushstring(L, p.first.c_str()); | ||||
|             luajit::PushValue(L, p.second); | ||||
|             return 2; | ||||
|           } catch (nf7::Exception&) { | ||||
|             return 0; | ||||
|           } | ||||
|         } else { | ||||
|           fu.ThenIf([L, th](auto& p) { | ||||
|             th->ExecResume(L, p.first, p.second); | ||||
|           }).template Catch<nf7::Exception>(nullptr, [L, th](nf7::Exception&) { | ||||
|             th->ExecResume(L); | ||||
|           }); | ||||
|           return th->Yield(L); | ||||
|         } | ||||
|       }); | ||||
|       lua_setfield(L, -2, "recv"); | ||||
|     } | ||||
|     lua_setfield(L, -2, "__index"); | ||||
|  | ||||
|     lua_pushcfunction(L, [](auto L) { | ||||
|       CheckRef<T>(L, 1, kTypeName).~T(); | ||||
|       CheckNodeRootLambda(L, 1).~T(); | ||||
|       return 0; | ||||
|     }); | ||||
|     lua_setfield(L, -2, "__gc"); | ||||
|   | ||||
| @@ -73,8 +73,15 @@ inline const std::shared_ptr<nf7::NodeRootLambda>& CheckNodeRootLambda(lua_State | ||||
| } | ||||
|  | ||||
| inline void ToStringList(lua_State* L, int idx, std::vector<std::string>& v) noexcept { | ||||
|   const size_t n = lua_objlen(L, idx); | ||||
|   v.clear(); | ||||
|   if (!lua_istable(L, idx)) { | ||||
|     if (auto str = lua_tostring(L, idx)) { | ||||
|       v.emplace_back(str); | ||||
|     } | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   const size_t n = lua_objlen(L, idx); | ||||
|   v.reserve(n); | ||||
|   for (int i = 1; i <= static_cast<int>(n); ++i) { | ||||
|     lua_rawgeti(L, idx, i); | ||||
|   | ||||
| @@ -141,7 +141,7 @@ static void PushMeta(lua_State* L) noexcept { | ||||
|             th->ExecResume(L, 0); | ||||
|           } | ||||
|         }); | ||||
|         return th->Yield(L, 0); | ||||
|         return th->Yield(L); | ||||
|       }); | ||||
|       lua_setfield(L, -2, "resolve"); | ||||
|  | ||||
| @@ -176,7 +176,7 @@ static void PushMeta(lua_State* L) noexcept { | ||||
|             th->ExecResume(L, nullptr, e.msg()); | ||||
|           } | ||||
|         }); | ||||
|         return th->Yield(L, 0); | ||||
|         return th->Yield(L); | ||||
|       }); | ||||
|       lua_setfield(L, -2, "query"); | ||||
|  | ||||
| @@ -189,62 +189,10 @@ static void PushMeta(lua_State* L) noexcept { | ||||
|             std::chrono::milliseconds(static_cast<uint64_t>(sec*1000)); | ||||
|         th->ljq()->Push(th->ctx(), [th, L](auto) { th->ExecResume(L); }, time); | ||||
|  | ||||
|         return th->Yield(L, 0); | ||||
|         return th->Yield(L); | ||||
|       }); | ||||
|       lua_setfield(L, -2, "sleep"); | ||||
|  | ||||
|       // nf7:send(obj, params...) | ||||
|       lua_pushcfunction(L, [](auto L) { | ||||
|         auto th = Thread::GetPtr(L, 1); | ||||
|         auto la = luajit::CheckNodeRootLambda(L, 2); | ||||
|         la->ExecSend(luaL_checkstring(L, 3), luajit::CheckValue(L, 4)); | ||||
|         return 0; | ||||
|       }); | ||||
|       lua_setfield(L, -2, "send"); | ||||
|  | ||||
|       // nf7:recv(obj, params...) | ||||
|       lua_pushcfunction(L, [](auto L) { | ||||
|         auto th = Thread::GetPtr(L, 1); | ||||
|         auto la = luajit::CheckNodeRootLambda(L, 2); | ||||
|  | ||||
|         std::unordered_set<std::string> names; | ||||
|         if (lua_istable(L, 3)) { | ||||
|           lua_pushnil(L); | ||||
|           while (lua_next(L, 3)) { | ||||
|             if (lua_isstring(L, -1)) { | ||||
|               names.insert(lua_tostring(L, -1)); | ||||
|             } else { | ||||
|               return luaL_error(L, "table contains non-string value"); | ||||
|             } | ||||
|             lua_pop(L, 1); | ||||
|           } | ||||
|         } else { | ||||
|           for (int i = 3; i <= lua_gettop(L); ++i) { | ||||
|             names.insert(luaL_checkstring(L, i)); | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         auto fu = la->Select(std::move(names)); | ||||
|         if (fu.done()) { | ||||
|           try { | ||||
|             const auto& p = fu.value(); | ||||
|             lua_pushstring(L, p.first.c_str()); | ||||
|             luajit::PushValue(L, p.second); | ||||
|             return 2; | ||||
|           } catch (nf7::Exception& e) { | ||||
|             return 0; | ||||
|           } | ||||
|         } else { | ||||
|           fu.ThenIf([L, th](auto& p) { | ||||
|             th->ExecResume(L, p.first, p.second); | ||||
|           }).template Catch<nf7::Exception>(nullptr, [L, th](nf7::Exception&) { | ||||
|             th->ExecResume(L); | ||||
|           }); | ||||
|           return th->Yield(L, 0); | ||||
|         } | ||||
|       }); | ||||
|       lua_setfield(L, -2, "recv"); | ||||
|  | ||||
|       // nf7:yield(results...) | ||||
|       lua_pushcfunction(L, [](auto L) { | ||||
|         return lua_yield(L, lua_gettop(L)-1); | ||||
|   | ||||
| @@ -84,9 +84,9 @@ class Thread final : public std::enable_shared_from_this<Thread> { | ||||
|  | ||||
|   // must be called on luajit thread | ||||
|   // handler_ won't be called on this yielding | ||||
|   int Yield(lua_State* L, int narg) { | ||||
|   int Yield(lua_State* L) { | ||||
|     skip_handle_ = true; | ||||
|     return lua_yield(L, narg); | ||||
|     return lua_yield(L, 0); | ||||
|   } | ||||
|  | ||||
|   // must be called on luajit thread | ||||
|   | ||||
		Reference in New Issue
	
	Block a user