nf7/core/luajit/context.hh

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