5#include <tracy/Tracy.hpp>
9template<
typename... Args>
11 requires(std::is_invocable_r_v<void, F, Args...> || std::is_invocable_r_v<void, F>)
12inline void Signal<Args...>::connect(toast::Node& node, F&& cb) {
13 callback_t wrapper = [f = std::forward<F>(cb)](Args... args)
mutable {
14 if constexpr (std::is_invocable_r_v<void, F, Args...>) {
16 }
else if constexpr (std::is_invocable_r_v<void, F>) {
20 modify([&](ConnectionList& list) {
23 .identifier =
"Unnamed",
24 .source = ConnectionSource::cpp,
25 .node = toast::Box<toast::Node>(node),
26 .cb = std::move(wrapper)}
31template<
typename... Args>
33 Signal<Args...>::connect(toast::Node& node, std::string_view identifier, ConnectionSource source,
bool forwards_args) {
35 if constexpr (std::is_same_v<std::tuple<Args...>, std::tuple<DynamicArgs>>) {
37 [iden = std::string(identifier), box = toast::Box<toast::Node>(node), forwards_args](
const DynamicArgs& args)
mutable {
38 if (forwards_args && !args.values.empty()) {
39 toast::_detail::callNodeScripts(&*box, iden, args.values);
44 }
else if (forwards_args) {
45 wrapper = [iden = std::string(identifier), box = toast::Box<toast::Node>(node)](
const Args&... args)
mutable {
46 box->call(iden, args...);
49 wrapper = [iden = std::string(identifier), box = toast::Box<toast::Node>(node)](
const Args&...) mutable { box->call(iden); };
51 modify([&](ConnectionList& list) {
54 .identifier = std::string(identifier),
56 .forwards_args = forwards_args,
57 .node = toast::Box<toast::Node>(node),
58 .cb = std::move(wrapper)}
63template<
typename... Args>
64inline void Signal<Args...>::disconnect(toast::Node& node, std::string_view identifier, ConnectionSource source) {
65 modify([&](ConnectionList& list) {
66 std::erase_if(list, [&](
const Connection& listener) {
67 return listener.node == toast::Box<toast::Node>(node) && listener.identifier == identifier && listener.source == source;
72template<
typename... Args>
73inline void Signal<Args...>::clear(ConnectionSource source) {
74 modify([source](ConnectionList& list) {
75 std::erase_if(list, [source](
const Connection& listener) {
return listener.source == source; });
79template<
typename... Args>
80inline auto Signal<Args...>::connections() const -> std::vector<
ConnectionInfo> {
81 const auto current = snapshot();
82 std::vector<ConnectionInfo> result;
83 result.reserve(current->size());
84 for (
const auto& listener : *current) {
85 result.push_back({listener.uid, listener.identifier, listener.source, listener.forwards_args});
90template<
typename... Args>
91inline void Signal<Args...>::fire(
const Args&... args) {
94 const auto current = snapshot();
95 bool has_dead =
false;
96 for (
const auto& listener : *current) {
101 listener.cb(args...);
104 modify([](ConnectionList& list) { std::erase_if(list, [](
const Connection& listener) {
return !listener.node; }); });
108template<
typename... Args>
109template<
typename NodeType, auto MemberPtr>
110inline auto Signal<Args...>::get(
void* signal) -> std::vector<ConnectionInfo> {
114 auto* node =
static_cast<NodeType*
>(signal);
115 const auto& target_signal = node->*MemberPtr;
116 return target_signal.connections();
119template<
typename... Args>
120template<
typename NodeType, auto MemberPtr>
121inline void Signal<Args...>::connect(
122 void* signal, toast::Node& target, std::string_view identifier, ConnectionSource source,
bool forwards_args
127 auto& target_signal =
static_cast<NodeType*
>(signal)->*MemberPtr;
128 const auto connections = target_signal.connections();
129 const bool exists = std::ranges::any_of(connections, [&](
const ConnectionInfo& connection) {
130 return connection.target == target.
uid() && connection.function == identifier && connection.source == source;
133 target_signal.connect(target, identifier, source, forwards_args);
137template<
typename... Args>
138template<
typename NodeType, auto MemberPtr>
139inline void Signal<Args...>::disconnect(
void* signal, toast::Node& target, std::string_view identifier, ConnectionSource source) {
143 auto& target_signal =
static_cast<NodeType*
>(signal)->*MemberPtr;
144 target_signal.disconnect(target, identifier, source);
147template<
typename... Args>
148template<
typename NodeType, auto MemberPtr>
149inline void Signal<Args...>::clear(
void* signal, ConnectionSource source) {
153 auto& target_signal =
static_cast<NodeType*
>(signal)->*MemberPtr;
154 target_signal.clear(source);
157template<
typename... Args>
158template<
typename NodeType, auto MemberPtr>
159inline auto Signal<Args...>::fire(
void* signal, std::span<const std::any> args) ->
bool {
161 if (!signal || args.size() !=
sizeof...(Args)) {
164 return [&]<
size_t... I>(std::index_sequence<I...>) {
165 if ((std::any_cast<std::decay_t<Args>>(&args[I]) && ...)) {
166 (
static_cast<NodeType*
>(signal)->*MemberPtr).fire(*std::any_cast<std::decay_t<Args>>(&args[I])...);
170 }(std::index_sequence_for<Args...> {});
auto uid() const noexcept -> const UID &
Stable unique identifier, assigned at construction or deserialization. Never changes.
Definition node.cpp:37
Base object type for the scene graph.
NodeType
Definition node.hpp:62
Definition signal_types.hpp:22
Definition signal_types.hpp:18