| // Copyright 2020 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef SRC_DEVELOPER_FORENSICS_UTILS_FIT_BRIDGE_MAP_H_ | |
| #define SRC_DEVELOPER_FORENSICS_UTILS_FIT_BRIDGE_MAP_H_ | |
| #include <lib/async/dispatcher.h> | |
| #include <lib/fit/promise.h> | |
| #include <cstdint> | |
| #include <map> | |
| #include "src/developer/forensics/utils/errors.h" | |
| #include "src/developer/forensics/utils/fit/bridge.h" | |
| #include "src/developer/forensics/utils/fit/timeout.h" | |
| namespace forensics { | |
| namespace fit { | |
| // Manages access to multiple Bridge objects, allowing access through an id. | |
| template <typename V = void> | |
| class BridgeMap { | |
| public: | |
| BridgeMap(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher) {} | |
| uint64_t NewBridgeForTask(const std::string& task_name) { | |
| bridges_.emplace(std::piecewise_construct, std::forward_as_tuple(next_id_), | |
| std::forward_as_tuple(dispatcher_, task_name)); | |
| return next_id_++; | |
| } | |
| void Delete(uint64_t id) { bridges_.erase(id); } | |
| bool Contains(uint64_t id) const { return bridges_.find(id) != bridges_.end(); } | |
| bool IsEmpty() const { return bridges_.empty(); } | |
| template <typename VV = V, typename = std::enable_if_t<std::is_void_v<VV>>> | |
| void CompleteOk(uint64_t id) { | |
| if (Contains(id)) { | |
| bridges_.at(id).CompleteOk(); | |
| } | |
| } | |
| template <typename VV = V, typename = std::enable_if_t<!std::is_void_v<VV>>> | |
| void CompleteOk(uint64_t id, VV value) { | |
| if (Contains(id)) { | |
| bridges_.at(id).CompleteOk(std::move(value)); | |
| } | |
| } | |
| template <typename VV = V, typename = std::enable_if_t<std::is_void_v<VV>>> | |
| void CompleteAllOk() { | |
| for (auto& [_, bridge] : bridges_) { | |
| bridge.CompleteOk(); | |
| } | |
| } | |
| template <typename VV = V, typename = std::enable_if_t<!std::is_void_v<VV>>> | |
| void CompleteAllOk(VV value) { | |
| for (auto& [_, bridge] : bridges_) { | |
| bridge.CompleteOk(value); | |
| } | |
| } | |
| void CompleteError(uint64_t id, Error error) { | |
| if (Contains(id)) { | |
| bridges_.at(id).CompleteError(error); | |
| } | |
| } | |
| void CompleteAllError(Error error) { | |
| for (auto& [_, bridge] : bridges_) { | |
| bridge.CompleteError(error); | |
| } | |
| } | |
| bool IsAlreadyDone(uint64_t id) const { | |
| if (Contains(id)) { | |
| return bridges_.at(id).IsAlreadyDone(); | |
| } | |
| // A bridge that isn't in the map is considered done. | |
| return true; | |
| } | |
| // Get the promise that will be ungated when the bridge at |id| is completed. An error is returned | |
| // if the bridge doesn't exist. | |
| ::fit::promise<V, Error> WaitForDone(uint64_t id) { | |
| if (Contains(id)) { | |
| return bridges_.at(id).WaitForDone(); | |
| } | |
| return ::fit::make_result_promise<V>(::fit::error(Error::kDefault)); | |
| } | |
| // Start the timeout and get the promise that will be ungated when the bridge at |id| is | |
| // completed. An error if returned if the bridge doesn't exist. | |
| ::fit::promise<V, Error> WaitForDone(uint64_t id, Timeout timeout) { | |
| if (Contains(id)) { | |
| return bridges_.at(id).WaitForDone(std::move(timeout)); | |
| } | |
| return ::fit::make_result_promise<V>(::fit::error(Error::kDefault)); | |
| } | |
| private: | |
| async_dispatcher_t* dispatcher_; | |
| std::map<uint64_t, Bridge<V>> bridges_; | |
| uint64_t next_id_ = 1; | |
| }; | |
| } // namespace fit | |
| } // namespace forensics | |
| #endif // SRC_DEVELOPER_FORENSICS_UTILS_FIT_BRIDGE_MAP_H_ |