summaryrefslogtreecommitdiff
path: root/src/tangara/lua/property.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tangara/lua/property.hpp')
-rw-r--r--src/tangara/lua/property.hpp107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/tangara/lua/property.hpp b/src/tangara/lua/property.hpp
new file mode 100644
index 00000000..724261be
--- /dev/null
+++ b/src/tangara/lua/property.hpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+
+#include "audio_events.hpp"
+#include "bluetooth_types.hpp"
+#include "lua.hpp"
+#include "lvgl.h"
+#include "service_locator.hpp"
+
+namespace lua {
+
+// FIXME: We should use some kind of interface for this instead.
+using LuaValue = std::variant<std::monostate,
+ int,
+ bool,
+ std::string,
+ audio::TrackInfo,
+ drivers::bluetooth::Device,
+ std::vector<drivers::bluetooth::Device>>;
+
+using LuaFunction = std::function<int(lua_State*)>;
+
+class Property {
+ public:
+ Property() : Property(std::monostate{}) {}
+ Property(const LuaValue&);
+ Property(const LuaValue&, std::function<bool(const LuaValue&)> filter);
+
+ auto get() -> const LuaValue& { return *value_; }
+
+ /*
+ * Assigns a new value to this property, bypassing the filter fn. All
+ * bindings will be marked as dirty, and if active, will be reapplied.
+ */
+ auto setDirect(const LuaValue&) -> void;
+ /*
+ * Invokes the filter fn, and if successful, assigns the new value to this
+ * property. All bindings will be marked as dirty, and if active, will be
+ * reapplied.
+ */
+ auto set(const LuaValue&) -> bool;
+
+ /* Returns whether or not this Property can be written from Lua. */
+ auto isTwoWay() -> bool { return cb_.has_value(); }
+
+ auto pushValue(lua_State& s) -> int;
+ auto popValue(lua_State& s) -> bool;
+
+ /* Reapplies all active, dirty bindings associated with this Property. */
+ auto reapplyAll() -> void;
+
+ auto addLuaBinding(lua_State*, int ref) -> void;
+ auto applySingle(lua_State*, int ref, bool mark_dirty) -> bool;
+
+ private:
+ std::unique_ptr<LuaValue> value_;
+ std::optional<std::function<bool(const LuaValue&)>> cb_;
+ std::pmr::vector<std::pair<lua_State*, int>> bindings_;
+};
+
+/*
+ * Container for a Lua function that should be invoked whenever a Property's
+ * value changes, as well as some extra accounting metadata.
+ */
+struct Binding {
+ /* Checks the value at idx is a Binding, returning a pointer to it if so. */
+ static auto get(lua_State*, int idx) -> Binding*;
+ /*
+ * If the value at idx is a dirty, active Binding, applies the current value
+ * from its Property. Returns false if the binding was active and dirty, but
+ * invoking the Lua callback failed.
+ */
+ static auto apply(lua_State*, int idx) -> bool;
+
+ Property* property;
+ bool active;
+ bool dirty;
+};
+
+static_assert(std::is_trivially_destructible<Binding>());
+static_assert(std::is_trivially_copy_assignable<Binding>());
+
+class PropertyBindings {
+ public:
+ PropertyBindings();
+
+ auto install(lua_State*) -> void;
+
+ auto Register(lua_State*, Property*) -> void;
+ auto Register(lua_State*, LuaFunction) -> void;
+
+ auto GetFunction(size_t i) -> const LuaFunction&;
+
+ private:
+ std::pmr::vector<LuaFunction> functions_;
+};
+
+} // namespace lua