Finale PDK Framework 0.77
Power Up Your Finale Music Software
Loading...
Searching...
No Matches
fflua_lua.h
1//
2// fflua_lua.h
3// RGPLua
4//
5// Created by Robert Patterson on 4/3/23.
6//
7
8#ifndef fflua_luabridge_h
9#define fflua_luabridge_h
10
11#ifndef DOXYGEN_SHOULD_IGNORE_THIS
12
13#include "lua.hpp"
14
15//#ifndef __OBJC__
16
17// LuaBridge 2 headers do not compile in objective-c++, so this directive was used
18// to mask them. But it is much safer to compile all code with the same headers,
19// so now that we are using LuaBridge 3, this is effectively the same as PDK_FRAMEWORK_LUAFRIENDLY
20#define PDK_FRAMEWORK_LUAFRIENDLY_CPP
21
22#if defined(__GNUC__)
23#pragma GCC diagnostic push
24#pragma GCC diagnostic ignored "-Wdocumentation"
25#endif
26
27#include "LuaBridge/LuaBridge.h"
28#include "LuaBridge/Vector.h"
29#include "LuaBridge/Map.h"
30
31#if LUABRIDGE_MAJOR_VERSION >= 3
32namespace luabridge
33{
34template<class T>
35using RefCountedPtr = std::shared_ptr<T>;
36}
37template<class T>
38static std::shared_ptr<T> makeLuaSharedPtr(T *p) { return std::shared_ptr<T>(p, [](T* p){ delete p; }); }
39#else
40#include "LuaBridge/RefCountedPtr.h"
41template<class T>
42static luabridge::RefCountedPtr<T> makeLuaSharedPtr(T *p) { return luabridge::RefCountedPtr<T>(p); }
43#endif
44
45#if LUABRIDGE_MAJOR_VERSION >= 3
46#define LB3(C) C
47#define LB3_PARM(C) , C
48#define LB2(C)
49#else
50#define LB3(C)
51#define LB3_PARM(C)
52#define LB2(C) C
53#endif
54
55#if defined(__GNUC__)
56#pragma GCC diagnostic pop
57#endif
58
59#if LUABRIDGE_MAJOR_VERSION < 3
60namespace luabridge
61{
62template <typename T>
63struct Enum {
64 static inline
65 typename std::enable_if<std::is_enum<T>::value, void>::type
66 push(lua_State* L, T value) {
67 lua_pushnumber(L, static_cast<std::size_t>(value));
68 }
69
70 static inline
71 typename std::enable_if<std::is_enum<T>::value, T>::type
72 get(lua_State* L, int index) {
73 return static_cast<T>(lua_tointeger(L, index));
74 }
75};
76}
77#endif // LUABRIDGE_MAJOR_VERSION < 3
78
79// Lua coroutines use a different state than the main execution path,
80// so the Lua connector should insert the base state at this key:
81constexpr char LUARUN_BASE_STATE_KEY[] = "___LuaRun_BaseStateKey$$$___";
82
84inline lua_State* _GetBaseLuaState(lua_State *L)
85{
86 lua_pushstring(L, LUARUN_BASE_STATE_KEY);
87 lua_gettable(L, LUA_REGISTRYINDEX);
88 lua_State* baseState = lua_tothread(L, -1);
89 lua_pop(L, 1);
90 assert(baseState); // assert should never fail if _CreateLuaState is used to create the state
91 return baseState;
92}
93
97inline lua_State* _CreateLuaState()
98{
99 lua_State* L = luaL_newstate();
100 // push the base-state key into the registry, so we can retrieve it in coroutines
101 lua_pushstring(L, LUARUN_BASE_STATE_KEY);
102 lua_pushthread(L);
103 lua_settable(L, LUA_REGISTRYINDEX);
104 return L;
105}
106
119template<class FC, typename OPT>
120FC* _OneOptionalParamLuaConstructor(void* ptr, lua_State *L)
121{
122 const int numArgs = lua_gettop(L);
123 if (numArgs <= 2) return new(ptr) FC();
124 OPT optParam = luabridge::Stack<OPT>::get(L, 2) LB3(.value());
125 return new(ptr) FC(optParam);
126}
127
138template <class C, typename RT, RT (C::*func)() const>
139int _CFunctionProxyGetter(lua_State* L)
140{
141 const C* instance = luabridge::Stack<const C*>::get(L, 1) LB3(.value());
142 RT result = (instance->*func)();
143 luabridge::Stack<RT>::push(L, result) LB3(.throw_on_error());
144 return 1;
145}
146
155template <class C, typename RT, void (C::*func)(RT)>
156int _CFunctionProxySetter(lua_State* L)
157{
158 C* instance = luabridge::Stack<C*>::get(L, 1) LB3(.value());
159 luabridge::LuaRef ref = luabridge::Stack<luabridge::LuaRef>::get(L, 2) LB3(.value());
160 if constexpr(std::is_same<RT, const char *>::value)
161 {
162 // if the input is a string:
163 // - nil is converted to ""
164 // - luaL_checkstring automatically converts numbers to decimal strings
165 // - other types throw type errors
166 if (! ref.isString())
167 {
168 (instance->*func)(lua_isnil(L, 2) ? "" : luaL_checkstring(L, 2));
169 return 0;
170 }
171 }
172 (instance->*func)(ref.cast<RT>() LB3(.value()));
173 return 0;
174}
175
176template <class C, typename RT, typename PT, typename F, typename I>
177int _CFunctionOneOptionalParameterImpl(lua_State *L, F func, I instance, PT default_value)
178{
179 const int numArgs = lua_gettop(L);
180 // argument 1 is `this`
181 int retval = 0;
182 PT param = (numArgs < 2) ? default_value : luabridge::Stack<PT>::get(L, 2) LB3(.value());
183 if constexpr(std::is_void<RT>::value)
184 ((*instance).*func)(param);
185 else
186 {
187 luabridge::Stack<RT>::push(L, ((*instance).*func)(param)) LB3(.throw_on_error());
188 retval++;
189 }
190 return retval;
191}
192
193template <class C, typename RT, typename PT, RT (C::*func)(PT)>
194int _CFunctionOneOptionalParameter(lua_State *L, PT default_value)
195{
196 C* instance = luabridge::Stack<C*>::get(L, 1) LB3(.value());
197 return _CFunctionOneOptionalParameterImpl<C, RT, PT, decltype(func), C*>(L, func, instance, default_value);
198}
199
200template <class C, typename RT, typename PT, RT (C::*func)(PT) const>
201int _CFunctionOneOptionalParameter(lua_State *L, PT default_value)
202{
203 const C* instance = luabridge::Stack<const C*>::get(L, 1) LB3(.value());
204 return _CFunctionOneOptionalParameterImpl<C, RT, PT, decltype(func), const C*>(L, func, instance, default_value);
205}
206
207template <class C, typename RT, typename PT, RT (C::*func)(PT, lua_State*)>
208int _CFunctionOneOptionalParameterWithState(lua_State* L, PT default_value)
209{
210 const int numArgs = lua_gettop(L);
211 assert(numArgs >= 1);
212 C* instance = luabridge::Stack<C*>::get(L, 1) LB3(.value());
213 PT param = (numArgs < 2) ? default_value : luabridge::Stack<PT>::get(L, 2) LB3(.value());
214 luabridge::Stack<RT>::push(L, ((*instance).*func)(param, L)) LB3(.throw_on_error());
215 return 1;
216}
217
218
221extern lua_CFunction LuaRun_ErrorFunction;
222
223//#endif // #ifndef __OBJC__
224
225#endif // DOXYGEN_SHOULD_IGNORE_THIS
226
227
228#endif /* fflua_luabridge_h */