#pragma once namespace ts::server::file { enum struct ExecuteStatus { UNKNOWN, WAITING, SUCCESS, ERROR }; template constexpr std::size_t variant_index() { if constexpr (index == std::variant_size_v) { return index; } else if constexpr (std::is_same_v, T>) { return index; } else { return variant_index(); } } struct EmptyExecuteResponse { }; template class ExecuteResponse { typedef std::variant variant_t; public: ExecuteStatus status{ExecuteStatus::WAITING}; [[nodiscard]] inline auto response() const -> const response_t& { return std::get(this->response_); } template ::value>> [[nodiscard]] inline const error_t& error() const { return std::get(this->response_); } inline void wait() const { std::unique_lock nlock{this->notify_mutex}; this->notify_cv.wait(nlock, [&]{ return this->status != ExecuteStatus::WAITING; }); } template [[nodiscard]] inline bool wait_for(const std::chrono::duration<_Rep, _Period>& time) const { std::unique_lock nlock{this->notify_mutex}; return this->notify_cv.wait_for(nlock, time, [&]{ return this->status != ExecuteStatus::WAITING; }); } template inline void emplace_success(Args&&... args) { constexpr auto success_index = variant_index(); std::lock_guard rlock{this->notify_mutex}; this->response_.template emplace(std::forward(args)...); this->status = ExecuteStatus::SUCCESS; this->notify_cv.notify_all(); } template inline void emplace_fail(Args&&... args) { constexpr auto error_index = variant_index(); std::lock_guard rlock{this->notify_mutex}; this->response_.template emplace(std::forward(args)...); this->status = ExecuteStatus::ERROR; this->notify_cv.notify_all(); } [[nodiscard]] inline bool succeeded() const { return this->status == ExecuteStatus::SUCCESS; } ExecuteResponse(std::mutex& notify_mutex, std::condition_variable& notify_cv) : notify_mutex{notify_mutex}, notify_cv{notify_cv} {} private: variant_t response_{}; /* void* as default value so we don't initialize error_t or response_t */ std::mutex& notify_mutex; std::condition_variable& notify_cv; }; }