feat(signal): added signal holder to automatically disconnect signals + instance AncestryChanged

This commit is contained in:
maelstrom 2025-05-16 09:43:15 +02:00
parent 0acc2d8857
commit 3b60b3b0ec
4 changed files with 41 additions and 0 deletions

View file

@ -72,6 +72,19 @@ void CSignalConnection::Call(std::vector<Data::Variant> args) {
// //
SignalConnectionHolder::SignalConnectionHolder() : heldConnection() {}
SignalConnectionHolder::SignalConnectionHolder(std::shared_ptr<SignalConnection> connection) : heldConnection(connection) {}
SignalConnectionHolder::SignalConnectionHolder(Data::SignalConnectionRef other) : heldConnection(other) {}
SignalConnectionHolder::~SignalConnectionHolder() {
// printf("Prediscon!\n");
// if (!heldConnection.expired()) printf("Disconnected!\n");
if (!heldConnection.expired())
heldConnection.lock()->Disconnect();
}
//
SignalConnectionRef Signal::Connect(std::function<void(std::vector<Data::Variant>)> callback) { SignalConnectionRef Signal::Connect(std::function<void(std::vector<Data::Variant>)> callback) {
auto conn = std::dynamic_pointer_cast<SignalConnection>(std::make_shared<CSignalConnection>(callback, weak_from_this())); auto conn = std::dynamic_pointer_cast<SignalConnection>(std::make_shared<CSignalConnection>(callback, weak_from_this()));
connections.push_back(conn); connections.push_back(conn);
@ -96,6 +109,8 @@ SignalConnectionRef Signal::Once(lua_State* state) {
return SignalConnectionRef(conn); return SignalConnectionRef(conn);
} }
//
int __waitingThreads = 0; int __waitingThreads = 0;
int Signal::Wait(lua_State* thread) { int Signal::Wait(lua_State* thread) {
// If the table hasn't been constructed yet, make it // If the table hasn't been constructed yet, make it

View file

@ -56,6 +56,27 @@ public:
~LuaSignalConnection(); ~LuaSignalConnection();
}; };
// Holds a signal connection such that when the holder is deleted (either via its parent object being deleted, or being overwritten),
// the connection is disconnected. Useful to prevent lingering connections that no longer contain valid objects
class SignalConnectionHolder {
std::weak_ptr<SignalConnection> heldConnection;
public:
SignalConnectionHolder();
SignalConnectionHolder(std::shared_ptr<SignalConnection>);
SignalConnectionHolder(Data::SignalConnectionRef other);
~SignalConnectionHolder();
// Prevent SignalConnectionHolder being accidentally copied, making it useless
// https://stackoverflow.com/a/10473009/16255372
SignalConnectionHolder(const SignalConnectionHolder&) = delete;
SignalConnectionHolder& operator=(const SignalConnectionHolder&) = delete;
SignalConnectionHolder(SignalConnectionHolder&&) = default;
SignalConnectionHolder& operator=(SignalConnectionHolder&&) = default;
inline bool Connected() { return !heldConnection.expired() && heldConnection.lock()->Connected(); }
inline void Disconnect() { if (!heldConnection.expired()) heldConnection.lock()->Disconnect(); }
};
class Signal : public std::enable_shared_from_this<Signal> { class Signal : public std::enable_shared_from_this<Signal> {
std::vector<std::shared_ptr<SignalConnection>> connections; std::vector<std::shared_ptr<SignalConnection>> connections;
std::vector<std::shared_ptr<SignalConnection>> onceConnections; std::vector<std::shared_ptr<SignalConnection>> onceConnections;

View file

@ -96,6 +96,7 @@ void Instance::updateAncestry(std::optional<std::shared_ptr<Instance>> updatedCh
} }
OnAncestryChanged(updatedChild, newParent); OnAncestryChanged(updatedChild, newParent);
AncestryChanged->Fire({updatedChild.has_value() ? Data::InstanceRef(updatedChild.value()) : Data::InstanceRef(), newParent.has_value() ? Data::InstanceRef(newParent.value()) : Data::InstanceRef()});
// Old workspace used to exist, and workspaces differ // Old workspace used to exist, and workspaces differ
if (!oldWorkspace.expired() && oldWorkspace != _workspace) { if (!oldWorkspace.expired() && oldWorkspace != _workspace) {

View file

@ -11,6 +11,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "datatypes/signal.h"
#include "error/instance.h" #include "error/instance.h"
#include "error/result.h" #include "error/result.h"
#include "member.h" #include "member.h"
@ -93,6 +94,9 @@ public:
const static InstanceType TYPE; const static InstanceType TYPE;
std::string name; std::string name;
// Signals
SignalSource AncestryChanged;
// Instance is abstract, so it should not implement GetClass directly // Instance is abstract, so it should not implement GetClass directly
virtual const InstanceType* GetClass() = 0; virtual const InstanceType* GetClass() = 0;
bool SetParent(std::optional<std::shared_ptr<Instance>> newParent); bool SetParent(std::optional<std::shared_ptr<Instance>> newParent);