unify LuaJIT/Node and LuaJIT/InlineNode into LuaJIT/Node
add std.import to LuaJIT std lib
This commit is contained in:
@@ -10,13 +10,18 @@
|
||||
|
||||
namespace nf7 {
|
||||
|
||||
class GenericContext : public Context {
|
||||
class GenericContext : public nf7::Context {
|
||||
public:
|
||||
GenericContext(Env& env, File::Id id, std::string_view desc = "") noexcept :
|
||||
Context(env, id), desc_(desc) {
|
||||
GenericContext(nf7::Env& env,
|
||||
nf7::File::Id id,
|
||||
std::string_view desc = "",
|
||||
const std::shared_ptr<nf7::Context>& parent = nullptr) noexcept :
|
||||
nf7::Context(env, id, parent), desc_(desc) {
|
||||
}
|
||||
GenericContext(File& f, std::string_view desc = "") noexcept :
|
||||
GenericContext(f.env(), f.id(), desc) {
|
||||
GenericContext(nf7::File& f,
|
||||
std::string_view desc = "",
|
||||
const std::shared_ptr<nf7::Context>& parent = nullptr) noexcept :
|
||||
GenericContext(f.env(), f.id(), desc, parent) {
|
||||
}
|
||||
|
||||
void CleanUp() noexcept override {
|
||||
|
||||
107
common/luajit_nfile_importer.hh
Normal file
107
common/luajit_nfile_importer.hh
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <lua.hpp>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/future.hh"
|
||||
#include "common/generic_context.hh"
|
||||
#include "common/luajit_ref.hh"
|
||||
#include "common/luajit_thread.hh"
|
||||
|
||||
|
||||
namespace nf7::luajit {
|
||||
|
||||
class NFileImporter :
|
||||
public nf7::luajit::Thread::Importer,
|
||||
public std::enable_shared_from_this<NFileImporter> {
|
||||
public:
|
||||
NFileImporter(const std::filesystem::path& base) noexcept : base_(base) {
|
||||
}
|
||||
|
||||
nf7::Future<std::shared_ptr<luajit::Ref>> Import(
|
||||
const luajit::Thread& th, std::string_view name) noexcept {
|
||||
auto self = shared_from_this();
|
||||
|
||||
const auto path = base_ / std::string {name};
|
||||
|
||||
auto ljq = th.ljq();
|
||||
auto ctx = std::make_shared<
|
||||
nf7::GenericContext>(th.env(), th.ctx()->initiator(),
|
||||
"LuaJIT imported script (nfile)", th.ctx());
|
||||
nf7::Future<std::shared_ptr<luajit::Ref>>::Promise pro {ctx};
|
||||
|
||||
// create new thread
|
||||
auto handler = luajit::Thread::CreatePromiseHandler<std::shared_ptr<luajit::Ref>>(
|
||||
pro, [self, this, path, ljq, ctx](auto L) {
|
||||
if (lua_gettop(L) <= 1) {
|
||||
AddImport(path);
|
||||
return std::make_shared<nf7::luajit::Ref>(ctx, ljq, L);
|
||||
} else {
|
||||
throw nf7::Exception {"imported script can return 1 or less results"};
|
||||
}
|
||||
});
|
||||
auto th_sub = std::make_shared<
|
||||
nf7::luajit::Thread>(ctx, ljq, std::move(handler));
|
||||
th_sub->Install(th);
|
||||
|
||||
// install new importer for sub thread
|
||||
auto dir = path;
|
||||
dir.remove_filename();
|
||||
th_sub->Install(std::make_shared<NFileImporter>(dir));
|
||||
|
||||
// start the thread
|
||||
ljq->Push(ctx, [pro, path, th_sub](auto L) mutable {
|
||||
L = th_sub->Init(L);
|
||||
if (0 == luaL_loadfile(L, path.string().c_str())) {
|
||||
th_sub->Resume(L, 0);
|
||||
} else {
|
||||
pro.Throw<nf7::Exception>(std::string {"import failed: "}+lua_tostring(L, -1));
|
||||
}
|
||||
});
|
||||
return pro.future();
|
||||
}
|
||||
|
||||
void ClearImports() noexcept {
|
||||
std::unique_lock<std::mutex> _ {mtx_};
|
||||
imports_.clear();
|
||||
}
|
||||
|
||||
std::filesystem::file_time_type GetLatestMod() const noexcept {
|
||||
std::unique_lock<std::mutex> _ {mtx_};
|
||||
|
||||
std::filesystem::file_time_type ret = {};
|
||||
for (const auto& p : imports_) {
|
||||
try {
|
||||
ret = std::max(ret, std::filesystem::last_write_time(p));
|
||||
} catch (std::filesystem::filesystem_error&) {
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::filesystem::path base_;
|
||||
|
||||
mutable std::mutex mtx_;
|
||||
std::vector<std::string> imports_;
|
||||
|
||||
|
||||
void AddImport(const std::filesystem::path& p) noexcept {
|
||||
auto str = p.string();
|
||||
|
||||
std::unique_lock<std::mutex> _ {mtx_};
|
||||
if (imports_.end() == std::find(imports_.begin(), imports_.end(), str)) {
|
||||
imports_.emplace_back(std::move(str));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nf7::luajit
|
||||
@@ -44,4 +44,8 @@ class Ref final : public nf7::Value::Data {
|
||||
int idx_;
|
||||
};
|
||||
|
||||
inline void Push(lua_State* L, const std::shared_ptr<Ref>& ref) noexcept {
|
||||
ref->PushSelf(L);
|
||||
}
|
||||
|
||||
} // namespace nf7::luajit
|
||||
|
||||
@@ -128,6 +128,31 @@ static void PushMeta(lua_State* L) noexcept {
|
||||
|
||||
lua_createtable(L, 0, 0);
|
||||
{
|
||||
// nf7:import(npath)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
auto th = Thread::GetPtr(L, 1);
|
||||
auto im = th->importer();
|
||||
if (!im) {
|
||||
return luaL_error(L, "import is not available in the current thread");
|
||||
}
|
||||
if (const auto name = lua_tostring(L, 2)) {
|
||||
auto fu = im->Import(*th, name);
|
||||
fu.ThenIf([L, th](auto& obj) {
|
||||
th->ExecResume(L, obj);
|
||||
}).
|
||||
template Catch<nf7::Exception>([L, th](auto&) {
|
||||
if (auto log = th->logger()) {
|
||||
log->Warn("import failed, returning nil");
|
||||
}
|
||||
th->ExecResume(L);
|
||||
});
|
||||
return th->Yield(L);
|
||||
} else {
|
||||
return luaL_error(L, "path should be a string");
|
||||
}
|
||||
});
|
||||
lua_setfield(L, -2, "import");
|
||||
|
||||
// nf7:resolve(path)
|
||||
lua_pushcfunction(L, [](auto L) {
|
||||
auto th = Thread::GetPtr(L, 1);
|
||||
|
||||
@@ -30,7 +30,7 @@ class Thread final : public std::enable_shared_from_this<Thread> {
|
||||
enum State { kInitial, kRunning, kPaused, kFinished, kAborted, };
|
||||
using Handler = std::function<void(Thread&, lua_State*)>;
|
||||
|
||||
class Lambda;
|
||||
class Importer;
|
||||
|
||||
class Exception final : public nf7::Exception {
|
||||
public:
|
||||
@@ -74,6 +74,15 @@ class Thread final : public std::enable_shared_from_this<Thread> {
|
||||
assert(state_ == kInitial);
|
||||
logger_ = logger;
|
||||
}
|
||||
void Install(const std::shared_ptr<Importer>& importer) noexcept {
|
||||
assert(state_ == kInitial);
|
||||
importer_ = importer;
|
||||
}
|
||||
void Install(const Thread& th) noexcept {
|
||||
assert(state_ == kInitial);
|
||||
logger_ = th.logger_;
|
||||
importer_ = th.importer_;
|
||||
}
|
||||
|
||||
// must be called on luajit thread
|
||||
lua_State* Init(lua_State* L) noexcept;
|
||||
@@ -109,10 +118,11 @@ class Thread final : public std::enable_shared_from_this<Thread> {
|
||||
});
|
||||
}
|
||||
|
||||
nf7::Env& env() noexcept { return ctx_->env(); }
|
||||
nf7::Env& env() const noexcept { return ctx_->env(); }
|
||||
const std::shared_ptr<nf7::Context>& ctx() const noexcept { return ctx_; }
|
||||
const std::shared_ptr<nf7::luajit::Queue>& ljq() const noexcept { return ljq_; }
|
||||
const std::shared_ptr<nf7::LoggerRef>& logger() const noexcept { return logger_; }
|
||||
const std::shared_ptr<Importer>& importer() const noexcept { return importer_; }
|
||||
State state() const noexcept { return state_; }
|
||||
|
||||
private:
|
||||
@@ -133,6 +143,7 @@ class Thread final : public std::enable_shared_from_this<Thread> {
|
||||
|
||||
// installed features
|
||||
std::shared_ptr<nf7::LoggerRef> logger_;
|
||||
std::shared_ptr<Importer> importer_;
|
||||
|
||||
|
||||
// mutable params
|
||||
@@ -141,6 +152,21 @@ class Thread final : public std::enable_shared_from_this<Thread> {
|
||||
};
|
||||
|
||||
|
||||
class Thread::Importer {
|
||||
public:
|
||||
Importer() = default;
|
||||
virtual ~Importer() = default;
|
||||
Importer(const Importer&) = delete;
|
||||
Importer(Importer&&) = delete;
|
||||
Importer& operator=(const Importer&) = delete;
|
||||
Importer& operator=(Importer&&) = delete;
|
||||
|
||||
// be called on luajit thread
|
||||
virtual nf7::Future<std::shared_ptr<luajit::Ref>> Import(
|
||||
const luajit::Thread&, std::string_view) noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
Thread::Handler Thread::CreatePromiseHandler(
|
||||
nf7::Future<T>::Promise& pro, std::function<T(lua_State*)>&& f) noexcept {
|
||||
|
||||
Reference in New Issue
Block a user