Skip to content

Commit 22e0b7d

Browse files
committed
Support range-like non-awaitable coroutines
1 parent eaeb89c commit 22e0b7d

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

include/trompeloeil/coro.hpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@
1414
#ifndef TROMPELOEIL_CORO_HPP
1515
#define TROMPELOEIL_CORO_HPP
1616

17+
#if __cplusplus < 202002L
18+
# error "C++20 is required"
19+
#endif
20+
1721
#if defined(__cpp_impl_coroutine)
1822
# define TROMPELOEIL_COROUTINES_SUPPORTED 1
1923
#else
2024
# error "Coroutines are not supported by this compiler"
2125
#endif
2226

2327
#ifdef TROMPELOEIL_COROUTINES_SUPPORTED
28+
#include <ranges>
2429

2530
#ifndef TROMPELOEIL_MOCK_HPP_
2631
#include "mock.hpp"
@@ -45,14 +50,22 @@ namespace trompeloeil
4550
{
4651
static auto func()
4752
{
48-
if constexpr (requires {std::declval<T>().operator co_await();})
53+
if constexpr (requires(T coro){ coro.operator co_await(); })
4954
{
5055
return type_wrapper<decltype(std::declval<T>().operator co_await().await_resume())>{};
5156
}
5257
else
58+
if constexpr (requires(T coro){ coro.await_resume(); })
5359
{
5460
return type_wrapper<decltype(std::declval<T>().await_resume())>{};
5561
}
62+
else
63+
{
64+
static_assert(
65+
std::ranges::input_range<T>,
66+
"non-awaitable coroutine shall be a range");
67+
return type_wrapper<std::ranges::range_value_t<T>>{};
68+
}
5669
}
5770
using type = typename decltype(func())::type;
5871
};

test/test_co_mock.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
#include "test_reporter.hpp"
2626
#include <optional>
2727

28+
#include <version>
29+
#ifdef __cpp_lib_generator
30+
#include <generator>
31+
#endif
32+
2833
using trompeloeil::_;
2934

3035
namespace {
@@ -35,6 +40,10 @@ namespace {
3540
MAKE_MOCK0 (voidret, coro::task<void>());
3641
MAKE_MOCK1 (unique, coro::task<iptr>(iptr));
3742
MAKE_MOCK0 (gen, coro::generator<int>());
43+
44+
#ifdef __cpp_lib_generator
45+
MAKE_MOCK0 (stdgen, std::generator<int>());
46+
#endif // __cpp_lib_generator
3847
};
3948
}
4049

@@ -198,4 +207,46 @@ TEST_CASE_METHOD(
198207
REQUIRE(v == 3);
199208
REQUIRE(reports.empty());
200209
}
210+
211+
#ifdef __cpp_lib_generator
212+
TEST_CASE_METHOD(
213+
Fixture,
214+
"CO_YIELD with std::generator",
215+
"[coro]")
216+
{
217+
co_mock m;
218+
REQUIRE_CALL(m, stdgen())
219+
.CO_YIELD(5)
220+
.CO_YIELD(8)
221+
.CO_YIELD(3)
222+
.CO_YIELD(0)
223+
.CO_RETURN();
224+
225+
auto gen = m.stdgen();
226+
227+
SECTION("as iterator")
228+
{
229+
auto it = std::ranges::begin(gen);
230+
REQUIRE(*it == 5);
231+
++it;
232+
REQUIRE(it != std::ranges::end(gen));
233+
REQUIRE(*it == 8);
234+
++it;
235+
REQUIRE(it != std::ranges::end(gen));
236+
REQUIRE(*it == 3);
237+
++it;
238+
REQUIRE(it != std::ranges::end(gen));
239+
REQUIRE(*it == 0);
240+
++it;
241+
REQUIRE(it == std::ranges::end(gen));
242+
}
243+
244+
SECTION("as range")
245+
{
246+
REQUIRE(std::ranges::equal(gen, std::array{5, 8, 3, 0}));
247+
}
248+
249+
REQUIRE(reports.empty());
250+
}
251+
#endif // __cpp_lib_generator
201252
#endif

0 commit comments

Comments
 (0)