179 lines
4.2 KiB
C++
179 lines
4.2 KiB
C++
// No copyright
|
|
#pragma once
|
|
|
|
#include <cassert>
|
|
#include <concepts>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include <lua.hpp>
|
|
|
|
#include "iface/common/task.hh"
|
|
#include "iface/common/value.hh"
|
|
#include "iface/subsys/interface.hh"
|
|
#include "iface/env.hh"
|
|
|
|
|
|
namespace nf7::core::luajit {
|
|
|
|
class Value;
|
|
class TaskContext;
|
|
class Context;
|
|
|
|
using Task = nf7::Task<TaskContext&>;
|
|
using TaskQueue = nf7::TaskQueue<Task>;
|
|
|
|
class Value final {
|
|
public:
|
|
Value() = delete;
|
|
Value(const std::shared_ptr<Context>& ctx, int index) noexcept
|
|
: ctx_(ctx), index_(index) {
|
|
assert(nullptr != ctx_);
|
|
}
|
|
~Value() noexcept;
|
|
|
|
Value(const Value&) = delete;
|
|
Value(Value&&) = delete;
|
|
Value& operator=(const Value&) = delete;
|
|
Value& operator=(Value&&) = delete;
|
|
|
|
const std::shared_ptr<Context>& context() const noexcept { return ctx_; }
|
|
int index() const noexcept { return index_; }
|
|
|
|
private:
|
|
std::shared_ptr<Context> ctx_;
|
|
int index_;
|
|
};
|
|
|
|
class TaskContext final {
|
|
public:
|
|
friend class Context;
|
|
|
|
class Nil {};
|
|
|
|
TaskContext() = delete;
|
|
TaskContext(const std::shared_ptr<Context>& ctx, lua_State* state) noexcept
|
|
: ctx_(std::move(ctx)), state_(state) {
|
|
assert(nullptr != state_);
|
|
}
|
|
|
|
TaskContext(const TaskContext&) = delete;
|
|
TaskContext(TaskContext&&) = delete;
|
|
TaskContext& operator=(const TaskContext&) = delete;
|
|
TaskContext& operator=(TaskContext&&) = delete;
|
|
|
|
lua_State* operator*() const noexcept { return state_; }
|
|
|
|
std::shared_ptr<Value> Register() noexcept;
|
|
void Query(const Value&) noexcept;
|
|
|
|
template <typename T, typename... Args>
|
|
uint32_t PushAll(T&& v, Args&&... args) noexcept {
|
|
Push(v);
|
|
return 1 + PushAll(std::forward<Args>(args)...);
|
|
}
|
|
uint32_t PushAll() noexcept { return 0; }
|
|
|
|
void Push(Nil) noexcept {
|
|
lua_pushnil(state_);
|
|
}
|
|
void Push(bool v) noexcept {
|
|
lua_pushboolean(state_, v);
|
|
}
|
|
void Push(lua_Integer v) noexcept {
|
|
lua_pushinteger(state_, v);
|
|
}
|
|
void Push(lua_Number v) noexcept {
|
|
lua_pushnumber(state_, v);
|
|
}
|
|
void Push(std::string_view str) noexcept {
|
|
lua_pushlstring(state_, str.data(), str.size());
|
|
}
|
|
void Push(std::span<const uint8_t> ptr) noexcept {
|
|
lua_pushlstring(
|
|
state_, reinterpret_cast<const char*>(ptr.data()), ptr.size());
|
|
}
|
|
void Push(const std::shared_ptr<luajit::Value>& v) noexcept {
|
|
Query(*v);
|
|
}
|
|
void Push(const luajit::Value& v) noexcept {
|
|
Query(v);
|
|
}
|
|
|
|
template <std::move_constructible T>
|
|
T& NewUserData(T&& v) {
|
|
return *(new (lua_newuserdata(state_, sizeof(T))) T {std::move(v)});
|
|
}
|
|
template <std::copy_constructible T>
|
|
T& NewUserData(const T& v) {
|
|
return *(new (lua_newuserdata(state_, sizeof(T))) T {v});
|
|
}
|
|
|
|
template <typename T>
|
|
T& CheckUserData(int index, const char* name) {
|
|
return CheckUserData<T>(state_, index, name);
|
|
}
|
|
template <typename T>
|
|
static T& CheckUserData(lua_State* L, int index, const char* name) {
|
|
return *reinterpret_cast<T*>(luaL_checkudata(L, index, name));
|
|
}
|
|
|
|
void Push(const nf7::Value&) noexcept;
|
|
const nf7::Value& CheckValue(int index) noexcept {
|
|
return CheckValue(state_, index);
|
|
}
|
|
static const nf7::Value& CheckValue(lua_State* L, int index) {
|
|
return CheckUserData<nf7::Value>(L, index, "nf7::Value");
|
|
}
|
|
|
|
const std::shared_ptr<Context>& context() const noexcept { return ctx_; }
|
|
lua_State* state() const noexcept { return state_; }
|
|
|
|
private:
|
|
std::shared_ptr<Context> ctx_;
|
|
lua_State* state_;
|
|
};
|
|
|
|
class Context :
|
|
public subsys::Interface,
|
|
public TaskQueue {
|
|
public:
|
|
static constexpr auto kGlobalTableName = "nf7::Context::GlobalTable";
|
|
|
|
using Item = Task;
|
|
|
|
enum Kind {
|
|
kSync,
|
|
kAsync,
|
|
};
|
|
static std::shared_ptr<Context> Create(Env&, Kind);
|
|
|
|
explicit Context(const char* name, Kind kind)
|
|
: subsys::Interface(name), kind_(kind), state_(nullptr) {
|
|
state_ = luaL_newstate();
|
|
if (nullptr == state_) {
|
|
throw Exception {"lua_State allocation failure"};
|
|
}
|
|
}
|
|
~Context() noexcept {
|
|
lua_close(state_);
|
|
}
|
|
|
|
using TaskQueue::Push;
|
|
using TaskQueue::Wrap;
|
|
using TaskQueue::Exec;
|
|
using TaskQueue::ExecAnd;
|
|
|
|
Kind kind() const noexcept { return kind_; }
|
|
|
|
protected:
|
|
lua_State* state() const noexcept { return state_; }
|
|
|
|
private:
|
|
Kind kind_;
|
|
lua_State* state_;
|
|
};
|
|
|
|
} // namespace nf7::core::luajit
|