#pragma once #include "allocator.hpp" #include "context.hpp" #include "packluau.h" #include #include #include #include #include struct lua_State; namespace packluau { /// Why a call did not produce a result. `status` is never `PL_OK`. struct Failure { pl_status status = PL_INTERNAL; std::string message; std::string chunk; std::uint32_t line = 0; /// Set with `PL_FAILED` only. pl_fail_kind kind = PL_FAIL_NONE; }; struct RunOutput { std::string plan; std::string report; }; /// One warm, sandboxed Luau state for the life of the process (SPEC.md section 4). Each `run` /// gets its own thread with a proxy global table, so scripts never see each other's globals. /// Not thread-safe: the host serializes calls. class Runtime { struct Key {}; public: [[nodiscard]] static std::expected, Failure> create(const pl_host &host); Runtime(Key key, const pl_host &host); ~Runtime(); Runtime(const Runtime &) = delete; Runtime &operator=(const Runtime &) = delete; Runtime(Runtime &&) = delete; Runtime &operator=(Runtime &&) = delete; [[nodiscard]] std::expected run(const pl_run_request &request); /// Keeps what the C ABI's documents point into, until the next call or the free call. const RunOutput &keep(RunOutput output) noexcept { last_output_ = std::move(output); return last_output_; } const Failure &keep(Failure failure) noexcept { last_failure_ = std::move(failure); return last_failure_; } void clear_output() noexcept { last_output_ = RunOutput{}; } void clear_failure() noexcept { last_failure_ = Failure{}; } /// The running script's context, or null between runs. [[nodiscard]] static RunContext *active(lua_State *state) noexcept; private: struct StateCloser { void operator()(lua_State *state) const noexcept; }; static Runtime &from(lua_State *state) noexcept; static void on_interrupt(lua_State *state, int gc); void install_globals(); [[nodiscard]] std::expected finish(lua_State *thread, int status, const RunContext &run, const std::string &chunk); pl_host host_; Allocator allocator_; std::unique_ptr state_; RunContext *active_ = nullptr; std::uint64_t generation_ = 0; RunOutput last_output_; Failure last_failure_; }; } // namespace packluau