nngn
Loading...
Searching...
No Matches
push.h
Go to the documentation of this file.
1
18#ifndef NNGN_LUA_PUSH_H
19#define NNGN_LUA_PUSH_H
20
21#include <string_view>
22#include <tuple>
23#include <utility>
24#include <variant>
25
27
28#include "lua.h"
29#include "user.h"
30
31namespace nngn::lua {
32
34template<typename T>
35struct stack_push<std::optional<T>> {
36 static int push(lua_State *L, std::optional<T> &&o) {
37 return o ? stack_push<T>::push(L, FWD(o).value()) : 0;
38 }
39};
40
42template<typename ...Ts>
43struct stack_push<std::variant<Ts...>> {
44 static int push(lua_State *L, std::variant<Ts...> &&v) {
45 return std::visit(
46 [L](auto &&x) { return stack_push<>::push(L, FWD(x)); },
47 FWD(v));
48 }
49};
50
56template<typename T>
57struct stack_push<error<T>> {
58 static int push(lua_State *L, const error<T> &e) {
59 return stack_push::push(L, error<T>{e});
60 }
61 static int push(lua_State *L, error<T> &&e) {
63 return lua_error(L);
64 }
65};
66
68template<>
70 static int push(lua_State *L, nil_type) {
71 lua_pushnil(L);
72 return 1;
73 }
74};
75
77template<>
79 static int push(lua_State *L, bool b) {
80 lua_pushboolean(L, b);
81 return 1;
82 }
83};
84
86template<std::convertible_to<const void> T>
87struct stack_push<T*> {
88 static int push(lua_State *L, T *p) {
89 // `const`ness is lost when a value is later retrieved.
90 lua_pushlightuserdata(L, const_cast<void*>(p));
91 return 1;
92 }
93};
94
101template<detail::integer T>
102struct stack_push<T> {
103 static int push(lua_State *L, lua_Integer i) {
104 lua_pushinteger(L, i);
105 return 1;
106 }
107};
108
114template<detail::number T>
115struct stack_push<T> {
116 static int push(lua_State *L, lua_Number n) {
117 lua_pushnumber(L, n);
118 return 1;
119 }
120};
121
123template<scoped_enum T>
124requires(detail::can_push<std::underlying_type_t<T>>)
125struct stack_push<T> {
126 static int push(lua_State *L, T t) {
127 return stack_push<>::push(L, to_underlying(t));
128 }
129};
130
132template<>
133struct stack_push<const char*> {
134 static int push(lua_State *L, const char *s) {
135 lua_pushstring(L, s);
136 return 1;
137 }
138};
139
141template<>
142struct stack_push<std::string_view> {
143 static int push(lua_State *L, std::string_view s) {
144 lua_pushlstring(L, s.data(), s.size());
145 return 1;
146 }
147};
148
150template<>
152 static int push(lua_State *L, const std::string &s) {
154 return 1;
155 }
156};
157
159template<>
160struct stack_push<lua_CFunction> {
161 static int push(lua_State *L, lua_CFunction f) {
162 lua_pushcfunction(L, f);
163 return 1;
164 }
165};
166
171template<typename T>
172requires(std::is_convertible_v<std::decay_t<T>, lua_CFunction>)
173struct stack_push<T> {
174 static int push(lua_State *L, T f) {
176 }
177};
178
180template<stateless_lambda T>
181requires(!std::convertible_to<T, lua_CFunction>)
182struct stack_push<T> {
183 static int push(lua_State *L, const T&) {
184 constexpr auto *f = +T{};
185 return stack_push<>::push(L, f);
186 }
187};
188
189namespace detail {
190
191template<typename R, typename T>
192int push_fn_wrapper(lua_State *L, T f) {
193 *static_cast<T*>(lua_newuserdatauv(L, sizeof(f), 0)) = f;
194 lua_pushcclosure(L, [](lua_State *L_) {
195 constexpr auto i = lua_upvalueindex(1);
196 auto f_ = *static_cast<T*>(lua_touserdata(L_, i));
197 if constexpr(!std::is_void_v<R>)
198 return stack_push<>::push(L_, call(L_, f_));
199 call(L_, f_);
200 return 0;
201 }, 1);
202 return 1;
203}
204
205}
206
212template<typename R, typename ...Args>
213struct stack_push<R(*)(Args...)> {
214 static int push(lua_State *L, R(*f)(Args...)) {
215 return detail::push_fn_wrapper<R>(L, f);
216 }
217};
218
220template<typename R, typename T, typename ...Args>
221struct stack_push<R(T::*)(Args...)> {
222 static int push(lua_State *L, R(T::*f)(Args...)) {
223 return detail::push_fn_wrapper<R>(L, f);
224 }
225};
226
228template<typename R, typename T, typename ...Args>
229struct stack_push<R(T::*)(Args...) const> {
230 static int push(lua_State *L, R(T::*f)(Args...) const) {
231 return detail::push_fn_wrapper<R>(L, f);
232 }
233};
234
236template<detail::stack_type T>
237struct stack_push<T> {
238 static int push([[maybe_unused]] lua_State *L, const T &t) {
239 assert(t.state() == L);
240 return t.push();
241 }
242};
243
251template<user_type T>
252struct stack_push<T> {
253 static int push(lua_State *L, T t) {
254 return user_data<T>::push(L, std::move(t));
255 }
256};
257
262template<user_type T>
263struct stack_push<T*> {
264 static int push(lua_State *L, T *t) {
265 return user_data<T>::push(L, t);
266 }
267};
268
273template<user_type T>
274struct stack_push<T&> {
275 static int push(lua_State *L, T &t) {
276 return user_data<T>::push(L, &t);
277 }
278};
279
284template<typename ...Ts>
285requires(... && detail::can_push<Ts>)
286struct stack_push<std::tuple<Ts...>> {
287 template<typename T>
288 requires(std::same_as<std::decay_t<T>, std::tuple<Ts...>>)
289 static int push(lua_State *L, T &&t) {
290 constexpr auto n = sizeof...(Ts);
291 return [L, &t]<std::size_t ...Is>(std::index_sequence<Is...>) {
292 return (0 + ... + stack_push<Ts>::push(L, std::get<Is>(FWD(t))));
293 }(std::make_index_sequence<n>{});
294 }
295};
296
302template<member_pointer auto p>
303int accessor(lua_State *L) {
304 assert(lua_gettop(L) || !"called without an object");
305 return [L]<typename T, typename M>(M T::*) {
306 return stack_push<>::push(L, &(user_data<T>::get(L, 1)->*p));
307 }(p);
308}
309
311template<member_pointer auto p>
312int value_accessor(lua_State *L) {
313 assert(lua_gettop(L) || !"called without an object");
314 return [L]<typename T, typename M>(M T::*) {
315 return stack_push<>::push(L, user_data<T>::get(L, 1)->*p);
316 }(p);
317}
318
319}
320
321#endif
Data block allocated for user data objects.
Definition: user.h:73
static int push(state_view lua, R &&r)
Pushes a value on the stack as a user data of type T.
assert
Definition: debug.lua:3
function bool(title, init, text)
int push_fn_wrapper(lua_State *L, T f)
Definition: push.h:192
Definition: alloc.cpp:100
int value_accessor(lua_State *L)
Similar to nngn::lua::accessor, but returns the member by value.
Definition: push.h:312
int accessor(lua_State *L)
Lua function template which pushes an object's member.
Definition: push.h:303
R call(lua_State *L, R(*f)(Args...), int i)
Calls the regular function f with arguments taken from the stack.
Definition: function.h:125
constexpr auto to_underlying(T t)
Definition: utils.h:136
Definition: debug.h:13
function f()) end
v[1]
Definition: math.lua:19
"Pushing" this value causes lua_error to be called.
Definition: lua.h:86
Used to push nil values onto the stack.
Definition: lua.h:83
static int push(lua_State *L, R(T::*f)(Args...) const)
Definition: push.h:230
static int push(lua_State *L, R(T::*f)(Args...))
Definition: push.h:222
static int push(lua_State *L, R(*f)(Args...))
Definition: push.h:214
static int push(lua_State *L, lua_Integer i)
Definition: push.h:103
static int push(lua_State *L, T f)
Definition: push.h:174
static int push(lua_State *L, const T &)
Definition: push.h:183
static int push(lua_State *L, T t)
Definition: push.h:126
static int push(lua_State *L, const T &t)
Definition: push.h:238
static int push(lua_State *L, lua_Number n)
Definition: push.h:116
static int push(lua_State *L, T *p)
Definition: push.h:88
static int push(lua_State *L, T *t)
Definition: push.h:264
static int push(lua_State *L, T &t)
Definition: push.h:275
static int push(lua_State *L, bool b)
Definition: push.h:79
static int push(lua_State *L, const char *s)
Definition: push.h:134
static int push(lua_State *L, error< T > &&e)
Definition: push.h:61
static int push(lua_State *L, const error< T > &e)
Definition: push.h:58
static int push(lua_State *L, lua_CFunction f)
Definition: push.h:161
static int push(lua_State *L, nil_type)
Definition: push.h:70
static int push(lua_State *L, std::optional< T > &&o)
Definition: push.h:36
static int push(lua_State *L, const std::string &s)
Definition: push.h:152
static int push(lua_State *L, std::string_view s)
Definition: push.h:143
static int push(lua_State *L, T &&t)
Definition: push.h:289
static int push(lua_State *L, std::variant< Ts... > &&v)
Definition: push.h:44
Pushes a value onto the Lua stack.
Definition: lua.h:119
Owning stack value reference.
Definition: value.h:48
e
Definition: math.lua:4
std::chrono::seconds s
Definition: timing.cpp:6
Operations on light/full user data values.
#define FWD(...)
Definition: utils.h:18