/work/testing/support/public/tox_runner.hh
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2026 The TokTok team. |
3 | | */ |
4 | | |
5 | | #ifndef C_TOXCORE_TESTING_SUPPORT_TOX_RUNNER_H |
6 | | #define C_TOXCORE_TESTING_SUPPORT_TOX_RUNNER_H |
7 | | |
8 | | #include <atomic> |
9 | | #include <functional> |
10 | | #include <future> |
11 | | #include <thread> |
12 | | #include <type_traits> |
13 | | #include <utility> |
14 | | #include <vector> |
15 | | |
16 | | #include "../../../toxcore/attributes.h" |
17 | | #include "../../../toxcore/tox_events.h" |
18 | | #include "mpsc_queue.hh" |
19 | | #include "simulation.hh" |
20 | | |
21 | | namespace tox::test { |
22 | | |
23 | | class ToxRunner { |
24 | | public: |
25 | | explicit ToxRunner(SimulatedNode &node, const Tox_Options *_Nullable options = nullptr); |
26 | | ~ToxRunner(); |
27 | | |
28 | | ToxRunner(const ToxRunner &) = delete; |
29 | | ToxRunner &operator=(const ToxRunner &) = delete; |
30 | | |
31 | | struct ToxEventsDeleter { |
32 | 0 | void operator()(Tox_Events *_Nonnull e) const { tox_events_free(e); } |
33 | | }; |
34 | | using ToxEventsPtr = std::unique_ptr<Tox_Events, ToxEventsDeleter>; |
35 | | |
36 | | /** |
37 | | * @brief Schedules a task for execution on the runner's thread. |
38 | | * |
39 | | * This method is thread-safe and non-blocking. The task is queued and will |
40 | | * be executed during the runner's event loop cycle. |
41 | | * |
42 | | * @param task The function to execute, taking a raw Tox pointer. |
43 | | */ |
44 | | void execute(std::function<void(Tox *_Nonnull)> task); |
45 | | |
46 | | /** |
47 | | * @brief Executes a task on the runner's thread and waits for the result. |
48 | | * |
49 | | * This method blocks the calling thread until the task has been executed |
50 | | * by the runner. It automatically handles return value propagation and |
51 | | * exception safety (though exceptions are not currently propagated). |
52 | | * |
53 | | * @tparam Func The type of the callable object. |
54 | | * @param func The callable to execute, taking a raw Tox pointer. |
55 | | * @return The result of the callable execution. |
56 | | */ |
57 | | template <typename Func> |
58 | | auto invoke(Func &&func) -> std::invoke_result_t<Func, Tox *_Nonnull> |
59 | 0 | { |
60 | 0 | using R = std::invoke_result_t<Func, Tox *_Nonnull>; |
61 | 0 | auto promise = std::make_shared<std::promise<R>>(); |
62 | 0 | auto future = promise->get_future(); |
63 | |
|
64 | 0 | execute([p = promise, f = std::forward<Func>(func)](Tox *_Nonnull tox) { |
65 | 0 | if constexpr (std::is_void_v<R>) { |
66 | 0 | f(tox); |
67 | 0 | p->set_value(); |
68 | 0 | } else { |
69 | 0 | p->set_value(f(tox)); |
70 | 0 | } |
71 | 0 | }); Unexecuted instantiation: unity_1_cxx.cxx:_ZZN3tox4test9ToxRunner6invokeIZNS0_23setup_connected_friendsERNS0_10SimulationEP3ToxRNS0_13SimulatedNodeEiPK11Tox_OptionsbE3$_0EENSt13invoke_resultIT_JS6_EE4typeEOSE_ENKUlS6_E_clES6_ Unexecuted instantiation: unity_1_cxx.cxx:_ZZN3tox4test9ToxRunner6invokeIZNS0_23setup_connected_friendsERNS0_10SimulationEP3ToxRNS0_13SimulatedNodeEiPK11Tox_OptionsbE3$_2EENSt13invoke_resultIT_JS6_EE4typeEOSE_ENKUlS6_E_clES6_ |
72 | |
|
73 | 0 | return future.get(); |
74 | 0 | } Unexecuted instantiation: unity_1_cxx.cxx:_ZN3tox4test9ToxRunner6invokeIZNS0_23setup_connected_friendsERNS0_10SimulationEP3ToxRNS0_13SimulatedNodeEiPK11Tox_OptionsbE3$_0EENSt13invoke_resultIT_JS6_EE4typeEOSE_ Unexecuted instantiation: unity_1_cxx.cxx:_ZN3tox4test9ToxRunner6invokeIZNS0_23setup_connected_friendsERNS0_10SimulationEP3ToxRNS0_13SimulatedNodeEiPK11Tox_OptionsbE3$_2EENSt13invoke_resultIT_JS6_EE4typeEOSE_ |
75 | | |
76 | | /** |
77 | | * @brief Retrieves all accumulated Tox event batches. |
78 | | * |
79 | | * Returns a vector of unique pointers to Tox_Events structures that have |
80 | | * been collected by the runner since the last call. Ownership is transferred |
81 | | * to the caller. This method is thread-safe. |
82 | | * |
83 | | * @return A vector of Tox_Events pointers. |
84 | | */ |
85 | | std::vector<ToxEventsPtr> poll_events(); |
86 | | |
87 | | /** |
88 | | * @brief Accesses the underlying Tox instance directly. |
89 | | * |
90 | | * @warning Thread-Safety Violation: This method provides unsafe access to the |
91 | | * Tox instance. It should ONLY be used when the runner thread is known to be |
92 | | * idle (e.g., before the loop starts) or for accessing constant/read-only properties. |
93 | | * For all other operations, use `execute` or `invoke`. |
94 | | */ |
95 | 0 | Tox *_Nullable unsafe_tox() { return tox_.get(); } |
96 | | |
97 | | /** |
98 | | * @brief Temporarily stops the runner from participating in the simulation. |
99 | | * |
100 | | * Unregisters the runner and its tick listener from the simulation. |
101 | | * While paused, the runner will not call tox_iterate. |
102 | | */ |
103 | | void pause(); |
104 | | |
105 | | /** |
106 | | * @brief Resumes the runner's participation in the simulation. |
107 | | */ |
108 | | void resume(); |
109 | | |
110 | | /** |
111 | | * @brief Returns true if the runner is currently active. |
112 | | */ |
113 | 0 | bool is_active() const { return active_; } |
114 | | |
115 | | private: |
116 | | void loop(); |
117 | | |
118 | | SimulatedNode::ToxPtr tox_; |
119 | | std::thread thread_; |
120 | | std::atomic<bool> active_{true}; |
121 | | |
122 | | struct Message { |
123 | | enum Type { Task, Tick, Stop } type; |
124 | | std::function<void(Tox *_Nonnull)> task; |
125 | | uint64_t generation = 0; |
126 | | }; |
127 | | |
128 | | MpscQueue<Message> queue_; |
129 | | MpscQueue<ToxEventsPtr> events_queue_; |
130 | | |
131 | | Simulation::TickListenerId tick_listener_id_ = -1; |
132 | | SimulatedNode &node_; |
133 | | }; |
134 | | |
135 | | } // namespace tox::test |
136 | | |
137 | | #endif // C_TOXCORE_TESTING_SUPPORT_TOX_RUNNER_H |