diff --git a/fairmq/sdk/Topology.h b/fairmq/sdk/Topology.h index b881ef28..0068f006 100644 --- a/fairmq/sdk/Topology.h +++ b/fairmq/sdk/Topology.h @@ -198,7 +198,82 @@ class BasicTopology : public AsioBase /// @param token Asio completion token /// @tparam CompletionToken Asio completion token type /// @throws std::system_error - /// TODO usage examples + /// + /// @par Usage examples + /// With lambda: + /// @code + /// topo.AsyncChangeState( + /// fair::mq::sdk::TopologyTransition::InitDevice, + /// std::chrono::milliseconds(500), + /// [](std::error_code ec, TopologyState state) { + /// if (!ec) { + /// // success + /// } else if (ec.category().name() == "fairmq") { + /// switch (static_cast(ec.value())) { + /// case fair::mq::ErrorCode::OperationTimeout: + /// // async operation timed out + /// case fair::mq::ErrorCode::OperationCanceled: + /// // async operation canceled + /// case fair::mq::ErrorCode::DeviceChangeStateFailed: + /// // failed to change state of a fairmq device + /// case fair::mq::ErrorCode::OperationInProgress: + /// // async operation already in progress + /// default: + /// } + /// } + /// } + /// ); + /// @endcode + /// With future: + /// @code + /// auto fut = topo.AsyncChangeState(fair::mq::sdk::TopologyTransition::InitDevice, + /// std::chrono::milliseconds(500), + /// asio::use_future); + /// try { + /// fair::mq::sdk::TopologyState state = fut.get(); + /// // success + /// } catch (const std::system_error& ex) { + /// auto ec(ex.code()); + /// if (ec.category().name() == "fairmq") { + /// switch (static_cast(ec.value())) { + /// case fair::mq::ErrorCode::OperationTimeout: + /// // async operation timed out + /// case fair::mq::ErrorCode::OperationCanceled: + /// // async operation canceled + /// case fair::mq::ErrorCode::DeviceChangeStateFailed: + /// // failed to change state of a fairmq device + /// case fair::mq::ErrorCode::OperationInProgress: + /// // async operation already in progress + /// default: + /// } + /// } + /// } + /// @endcode + /// With coroutine (C++20, see https://en.cppreference.com/w/cpp/language/coroutines): + /// @code + /// try { + /// fair::mq::sdk::TopologyState state = co_await + /// topo.AsyncChangeState(fair::mq::sdk::TopologyTransition::InitDevice, + /// std::chrono::milliseconds(500), + /// asio::use_awaitable); + /// // success + /// } catch (const std::system_error& ex) { + /// auto ec(ex.code()); + /// if (ec.category().name() == "fairmq") { + /// switch (static_cast(ec.value())) { + /// case fair::mq::ErrorCode::OperationTimeout: + /// // async operation timed out + /// case fair::mq::ErrorCode::OperationCanceled: + /// // async operation canceled + /// case fair::mq::ErrorCode::DeviceChangeStateFailed: + /// // failed to change state of a fairmq device + /// case fair::mq::ErrorCode::OperationInProgress: + /// // async operation already in progress + /// default: + /// } + /// } + /// } + /// @endcode template auto AsyncChangeState(TopologyTransition transition, Duration timeout, @@ -254,7 +329,7 @@ class BasicTopology : public AsioBase return AsyncChangeState(transition, Duration(0), std::move(token)); } - /// @brief Initiate state transition on all FairMQ devices in this topology + /// @brief Perform state transition on all FairMQ devices in this topology /// @param transition FairMQ device state machine transition /// @param timeout Timeout in milliseconds, 0 means no timeout /// @tparam CompletionToken Asio completion token type diff --git a/test/sdk/_topology.cxx b/test/sdk/_topology.cxx index 9a3abbe4..efb55c31 100644 --- a/test/sdk/_topology.cxx +++ b/test/sdk/_topology.cxx @@ -8,6 +8,7 @@ #include "Fixtures.h" +#include #include #include #include @@ -76,6 +77,54 @@ TEST_F(Topology, AsyncChangeStateWithCustomExecutor) mIoContext.run(); } +TEST_F(Topology, AsyncChangeStateFuture) +{ + using namespace fair::mq; + + sdk::Topology topo(mIoContext.get_executor(), mDDSTopo, mDDSSession); + auto fut(topo.AsyncChangeState( + sdk::TopologyTransition::InitDevice, + asio::use_future)); + std::thread t([&]() { mIoContext.run(); }); + bool success(false); + + try { + sdk::TopologyState state = fut.get(); + success = true; + } catch (const std::system_error& ex) { + LOG(error) << ex.what(); + } + + EXPECT_TRUE(success); + t.join(); +} + +#if defined(ASIO_HAS_CO_AWAIT) +TEST_F(Topology, AsyncChangeStateCoroutine) +{ + using namespace fair::mq; + + bool success(false); + asio::co_spawn( + mIoContext.get_executor(), + [&]() mutable -> asio::awaitable { + auto executor = co_await asio::this_coro::executor; + sdk::Topology topo(executor, mDDSTopo, mDDSSession); + try { + sdk::TopologyState state = co_await topo.AsyncChangeState( + sdk::TopologyTransition::InitDevice, asio::use_awaitable); + success = true; + } catch (const std::system_error& ex) { + LOG(error) << ex.what(); + } + }, + asio::detached); + + mIoContext.run(); + EXPECT_TRUE(success); +} +#endif + TEST_F(Topology, ChangeState) { using namespace fair::mq;