77 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			77 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#pragma once
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace ts::server::file {
							 | 
						||
| 
								 | 
							
								    enum struct ExecuteStatus {
							 | 
						||
| 
								 | 
							
								        UNKNOWN,
							 | 
						||
| 
								 | 
							
								        WAITING,
							 | 
						||
| 
								 | 
							
								        SUCCESS,
							 | 
						||
| 
								 | 
							
								        ERROR
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    template<typename VariantType, typename T, std::size_t index = 0>
							 | 
						||
| 
								 | 
							
								    constexpr std::size_t variant_index() {
							 | 
						||
| 
								 | 
							
								        if constexpr (index == std::variant_size_v<VariantType>) {
							 | 
						||
| 
								 | 
							
								            return index;
							 | 
						||
| 
								 | 
							
								        } else if constexpr (std::is_same_v<std::variant_alternative_t<index, VariantType>, T>) {
							 | 
						||
| 
								 | 
							
								            return index;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            return variant_index<VariantType, T, index + 1>();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    struct EmptyExecuteResponse { };
							 | 
						||
| 
								 | 
							
								    template <class error_t, class response_t = EmptyExecuteResponse>
							 | 
						||
| 
								 | 
							
								    class ExecuteResponse {
							 | 
						||
| 
								 | 
							
								            typedef std::variant<EmptyExecuteResponse, error_t, response_t> variant_t;
							 | 
						||
| 
								 | 
							
								        public:
							 | 
						||
| 
								 | 
							
								            ExecuteStatus status{ExecuteStatus::WAITING};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            [[nodiscard]] inline auto response() const -> const response_t& { return std::get<response_t>(this->response_); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            template <typename = std::enable_if_t<!std::is_void<error_t>::value>>
							 | 
						||
| 
								 | 
							
								            [[nodiscard]] inline const error_t& error() const { return std::get<error_t>(this->response_); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            inline void wait() const {
							 | 
						||
| 
								 | 
							
								                std::unique_lock nlock{this->notify_mutex};
							 | 
						||
| 
								 | 
							
								                this->notify_cv.wait(nlock, [&]{ return this->status != ExecuteStatus::WAITING; });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            template<typename _Rep, typename _Period>
							 | 
						||
| 
								 | 
							
								            [[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 <typename... Args>
							 | 
						||
| 
								 | 
							
								            inline void emplace_success(Args&&... args) {
							 | 
						||
| 
								 | 
							
								                constexpr auto success_index = variant_index<variant_t, response_t>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                std::lock_guard rlock{this->notify_mutex};
							 | 
						||
| 
								 | 
							
								                this->response_.template emplace<success_index, Args...>(std::forward<Args>(args)...);
							 | 
						||
| 
								 | 
							
								                this->status = ExecuteStatus::SUCCESS;
							 | 
						||
| 
								 | 
							
								                this->notify_cv.notify_all();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            template <typename... Args>
							 | 
						||
| 
								 | 
							
								            inline void emplace_fail(Args&&... args) {
							 | 
						||
| 
								 | 
							
								                constexpr auto error_index = variant_index<variant_t, error_t>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                std::lock_guard rlock{this->notify_mutex};
							 | 
						||
| 
								 | 
							
								                this->response_.template emplace<error_index, Args...>(std::forward<Args>(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;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								}
							 |