summaryrefslogtreecommitdiff
path: root/src/lua
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-11-20 13:02:29 +1100
committerjacqueline <me@jacqueline.id.au>2023-11-20 13:02:29 +1100
commitb7f37f6426c78132d338b032962209bd93771039 (patch)
treefd9e097ed55167616e630c257a28724b0f1ddc63 /src/lua
parentb3b512f10e0570f7dc8a04e1613f1234e5532728 (diff)
downloadtangara-fw-b7f37f6426c78132d338b032962209bd93771039.tar.gz
Add a generic lua function binding, alongside properties
Diffstat (limited to 'src/lua')
-rw-r--r--src/lua/bridge.cpp22
-rw-r--r--src/lua/include/bridge.hpp5
-rw-r--r--src/lua/include/property.hpp7
-rw-r--r--src/lua/property.cpp52
4 files changed, 77 insertions, 9 deletions
diff --git a/src/lua/bridge.cpp b/src/lua/bridge.cpp
index ba6f50b4..a45f2b27 100644
--- a/src/lua/bridge.cpp
+++ b/src/lua/bridge.cpp
@@ -110,16 +110,32 @@ static auto new_property_module(lua_State* state) -> int {
return 1;
}
+template <class... Ts>
+inline constexpr bool always_false_v = false;
+
auto Bridge::AddPropertyModule(
const std::string& name,
- std::vector<std::pair<std::string, std::shared_ptr<Property>>> props)
- -> void {
+ std::vector<std::pair<std::string,
+ std::variant<LuaFunction, std::shared_ptr<Property>>>>
+ props) -> void {
// Create the module (or retrieve it if one with this name already exists)
luaL_requiref(&state_, name.c_str(), new_property_module, true);
for (const auto& prop : props) {
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
}
diff --git a/src/lua/include/bridge.hpp b/src/lua/include/bridge.hpp
index 26401d14..91153d67 100644
--- a/src/lua/include/bridge.hpp
+++ b/src/lua/include/bridge.hpp
@@ -24,7 +24,10 @@ class Bridge {
auto AddPropertyModule(
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_; }
PropertyBindings& bindings() { return bindings_; }
diff --git a/src/lua/include/property.hpp b/src/lua/include/property.hpp
index b6b4718f..60f9906a 100644
--- a/src/lua/include/property.hpp
+++ b/src/lua/include/property.hpp
@@ -16,6 +16,7 @@
namespace lua {
using LuaValue = std::variant<std::monostate, int, float, bool, std::string>;
+using LuaFunction = std::function<int(lua_State*)>;
class Property {
public:
@@ -42,6 +43,12 @@ class PropertyBindings {
PropertyBindings(lua_State&);
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
diff --git a/src/lua/property.cpp b/src/lua/property.cpp
index 3130077b..353e01ae 100644
--- a/src/lua/property.cpp
+++ b/src/lua/property.cpp
@@ -5,10 +5,12 @@
*/
#include "property.hpp"
+#include <sys/_stdint.h>
#include <memory>
#include <string>
+#include "lauxlib.h"
#include "lua.h"
#include "lua.hpp"
#include "lvgl.h"
@@ -16,11 +18,13 @@
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 kBinderKey[] = "binder";
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");
return *reinterpret_cast<Property**>(data);
}
@@ -71,9 +75,25 @@ static const struct luaL_Reg kPropertyBindingFuncs[] = {{"get", property_get},
{"bind", property_bind},
{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) {
+ lua_pushstring(&s, kBinderKey);
+ lua_pushlightuserdata(&s, this);
+ lua_settable(&s, LUA_REGISTRYINDEX);
+
// Create the metatable responsible for the Property API.
- luaL_newmetatable(&s, kMetatableName);
+ luaL_newmetatable(&s, kPropertyMetatable);
lua_pushliteral(&s, "__index");
lua_pushvalue(&s, -2);
@@ -94,16 +114,38 @@ PropertyBindings::PropertyBindings(lua_State& s) {
lua_setmetatable(&s, -2); // setmetatable(bindings, meta)
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 {
Property** data =
- reinterpret_cast<Property**>(lua_newuserdata(s, sizeof(Property*)));
+ reinterpret_cast<Property**>(lua_newuserdata(s, sizeof(uintptr_t)));
*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>
inline constexpr bool always_false_v = false;