Add a generic lua function binding, alongside properties

custom
jacqueline 1 year ago
parent b3b512f10e
commit b7f37f6426
  1. 22
      src/lua/bridge.cpp
  2. 5
      src/lua/include/bridge.hpp
  3. 7
      src/lua/include/property.hpp
  4. 52
      src/lua/property.cpp

@ -110,16 +110,32 @@ static auto new_property_module(lua_State* state) -> int {
return 1; return 1;
} }
template <class... Ts>
inline constexpr bool always_false_v = false;
auto Bridge::AddPropertyModule( auto Bridge::AddPropertyModule(
const std::string& name, const std::string& name,
std::vector<std::pair<std::string, std::shared_ptr<Property>>> props) std::vector<std::pair<std::string,
-> void { std::variant<LuaFunction, std::shared_ptr<Property>>>>
props) -> void {
// Create the module (or retrieve it if one with this name already exists) // Create the module (or retrieve it if one with this name already exists)
luaL_requiref(&state_, name.c_str(), new_property_module, true); luaL_requiref(&state_, name.c_str(), new_property_module, true);
for (const auto& prop : props) { for (const auto& prop : props) {
lua_pushstring(&state_, prop.first.c_str()); lua_pushstring(&state_, prop.first.c_str());
bindings_.Register(&state_, prop.second.get()); std::visit(
[&](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, LuaFunction>) {
bindings_.Register(&state_, arg);
} else if constexpr (std::is_same_v<T, std::shared_ptr<Property>>) {
bindings_.Register(&state_, arg.get());
} else {
static_assert(always_false_v<T>, "missing case");
}
},
prop.second);
lua_settable(&state_, -3); // metatable.propname = property lua_settable(&state_, -3); // metatable.propname = property
} }

@ -24,7 +24,10 @@ class Bridge {
auto AddPropertyModule( auto AddPropertyModule(
const std::string&, const std::string&,
std::vector<std::pair<std::string, std::shared_ptr<Property>>>) -> void; std::vector<
std::pair<std::string,
std::variant<LuaFunction, std::shared_ptr<Property>>>>)
-> void;
system_fsm::ServiceLocator& services() { return services_; } system_fsm::ServiceLocator& services() { return services_; }
PropertyBindings& bindings() { return bindings_; } PropertyBindings& bindings() { return bindings_; }

@ -16,6 +16,7 @@
namespace lua { namespace lua {
using LuaValue = std::variant<std::monostate, int, float, bool, std::string>; using LuaValue = std::variant<std::monostate, int, float, bool, std::string>;
using LuaFunction = std::function<int(lua_State*)>;
class Property { class Property {
public: public:
@ -42,6 +43,12 @@ class PropertyBindings {
PropertyBindings(lua_State&); PropertyBindings(lua_State&);
auto Register(lua_State*, Property*) -> void; auto Register(lua_State*, Property*) -> void;
auto Register(lua_State*, LuaFunction) -> void;
auto GetFunction(size_t i) -> const LuaFunction&;
private:
std::vector<LuaFunction> functions_;
}; };
} // namespace lua } // namespace lua

@ -5,10 +5,12 @@
*/ */
#include "property.hpp" #include "property.hpp"
#include <sys/_stdint.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include "lauxlib.h"
#include "lua.h" #include "lua.h"
#include "lua.hpp" #include "lua.hpp"
#include "lvgl.h" #include "lvgl.h"
@ -16,11 +18,13 @@
namespace lua { namespace lua {
static const char kMetatableName[] = "property"; static const char kPropertyMetatable[] = "property";
static const char kFunctionMetatable[] = "function";
static const char kBindingsTable[] = "bindings"; static const char kBindingsTable[] = "bindings";
static const char kBinderKey[] = "binder";
static auto check_property(lua_State* state) -> Property* { static auto check_property(lua_State* state) -> Property* {
void* data = luaL_checkudata(state, 1, kMetatableName); void* data = luaL_checkudata(state, 1, kPropertyMetatable);
luaL_argcheck(state, data != NULL, 1, "`property` expected"); luaL_argcheck(state, data != NULL, 1, "`property` expected");
return *reinterpret_cast<Property**>(data); return *reinterpret_cast<Property**>(data);
} }
@ -71,9 +75,25 @@ static const struct luaL_Reg kPropertyBindingFuncs[] = {{"get", property_get},
{"bind", property_bind}, {"bind", property_bind},
{NULL, NULL}}; {NULL, NULL}};
static auto generic_function_cb(lua_State* state) -> int {
lua_pushstring(state, kBinderKey);
lua_gettable(state, LUA_REGISTRYINDEX);
PropertyBindings* binder =
reinterpret_cast<PropertyBindings*>(lua_touserdata(state, -1));
size_t* index =
reinterpret_cast<size_t*>(luaL_checkudata(state, 1, kFunctionMetatable));
const LuaFunction& fn = binder->GetFunction(*index);
return std::invoke(fn, state);
}
PropertyBindings::PropertyBindings(lua_State& s) { PropertyBindings::PropertyBindings(lua_State& s) {
lua_pushstring(&s, kBinderKey);
lua_pushlightuserdata(&s, this);
lua_settable(&s, LUA_REGISTRYINDEX);
// Create the metatable responsible for the Property API. // Create the metatable responsible for the Property API.
luaL_newmetatable(&s, kMetatableName); luaL_newmetatable(&s, kPropertyMetatable);
lua_pushliteral(&s, "__index"); lua_pushliteral(&s, "__index");
lua_pushvalue(&s, -2); lua_pushvalue(&s, -2);
@ -94,16 +114,38 @@ PropertyBindings::PropertyBindings(lua_State& s) {
lua_setmetatable(&s, -2); // setmetatable(bindings, meta) lua_setmetatable(&s, -2); // setmetatable(bindings, meta)
lua_settable(&s, LUA_REGISTRYINDEX); // REGISTRY[kBindingsTable] = bindings lua_settable(&s, LUA_REGISTRYINDEX); // REGISTRY[kBindingsTable] = bindings
// Create the metatable for C++ functions.
luaL_newmetatable(&s, kFunctionMetatable);
lua_pushliteral(&s, "__call");
lua_pushcfunction(&s, generic_function_cb);
lua_settable(&s, -3); // metatable.__call = metatable
lua_pop(&s, 1); // Clean up the function metatable
} }
auto PropertyBindings::Register(lua_State* s, Property* prop) -> void { auto PropertyBindings::Register(lua_State* s, Property* prop) -> void {
Property** data = Property** data =
reinterpret_cast<Property**>(lua_newuserdata(s, sizeof(Property*))); reinterpret_cast<Property**>(lua_newuserdata(s, sizeof(uintptr_t)));
*data = prop; *data = prop;
luaL_setmetatable(s, kMetatableName); luaL_setmetatable(s, kPropertyMetatable);
} }
auto PropertyBindings::Register(lua_State* s, LuaFunction fn) -> void {
size_t* index = reinterpret_cast<size_t*>(lua_newuserdata(s, sizeof(size_t)));
*index = functions_.size();
functions_.push_back(fn);
luaL_setmetatable(s, kFunctionMetatable);
}
auto PropertyBindings::GetFunction(size_t i) -> const LuaFunction& {
assert(i < functions_.size());
return functions_[i];
};
template <class... Ts> template <class... Ts>
inline constexpr bool always_false_v = false; inline constexpr bool always_false_v = false;

Loading…
Cancel
Save