Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions strings/base_coroutine_foundation.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,14 +467,14 @@ namespace winrt::impl
}

template <typename Expression>
Expression&& await_transform(Expression&& expression)
auto await_transform(Expression&& expression)
{
if (Status() == AsyncStatus::Canceled)
{
throw winrt::hresult_canceled();
}

return std::forward<Expression>(expression);
return notify_awaiter<Expression>{ static_cast<Expression&&>(expression) };
}

cancellation_token<Derived> await_transform(get_cancellation_token_t) noexcept
Expand Down
154 changes: 154 additions & 0 deletions strings/base_coroutine_threadpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,154 @@ namespace winrt::impl
}
}
}

template <typename T>
class has_awaitable_member
{
template <typename U, typename = decltype(std::declval<U>().await_ready())> static constexpr bool get_value(int) { return true; }
template <typename> static constexpr bool get_value(...) { return false; }

public:

static constexpr bool value = get_value<T>(0);
};

template <typename T>
class has_awaitable_free
{
template <typename U, typename = decltype(await_ready(std::declval<U>()))> static constexpr bool get_value(int) { return true; }
template <typename> static constexpr bool get_value(...) { return false; }

public:

static constexpr bool value = get_value<T>(0);
};

template <typename T>
struct free_await_adapter_impl
{
T&& awaitable;

bool ready()
{
return await_ready(awaitable);
}

template <typename U>
auto suspend(std::experimental::coroutine_handle<U> handle)
{
return await_suspend(awaitable, handle);
}

auto resume()
{
return await_resume(awaitable);
}
};

template <typename T>
struct free_await_adapter
{
T&& awaitable;

bool await_ready()
{
return free_await_adapter_impl<T>{ static_cast<T&&>(awaitable) }.ready();
}

template <typename U>
auto await_suspend(std::experimental::coroutine_handle<U> handle)
{
return free_await_adapter_impl<T>{ static_cast<T&&>(awaitable) }.suspend(handle);
}

auto await_resume()
{
return free_await_adapter_impl<T>{ static_cast<T&&>(awaitable) }.resume();
}
};

template <typename T>
struct member_await_adapter
{
T&& awaitable;

bool await_ready()
{
return awaitable.await_ready();
}

template <typename U>
auto await_suspend(std::experimental::coroutine_handle<U> handle)
{
return awaitable.await_suspend(handle);
}

auto await_resume()
{
return awaitable.await_resume();
}
};

template <typename T>
auto get_awaiter(T&& value) noexcept -> decltype(static_cast<T&&>(value).operator co_await())
{
return static_cast<T&&>(value).operator co_await();
}

template <typename T>
auto get_awaiter(T&& value) noexcept -> decltype(operator co_await(static_cast<T&&>(value)))
{
return operator co_await(static_cast<T&&>(value));
}

template <typename T, std::enable_if_t<has_awaitable_member<T>::value, int> = 0>
auto get_awaiter(T&& value) noexcept
{
return member_await_adapter<T>{ static_cast<T&&>(value) };
}

template <typename T, std::enable_if_t<has_awaitable_free<T>::value, int> = 0>
auto get_awaiter(T&& value) noexcept
{
return free_await_adapter<T>{ static_cast<T&&>(value) };
}

template <typename T>
struct notify_awaiter
{
decltype(get_awaiter(std::declval<T&&>())) awaitable;

notify_awaiter(T&& awaitable) : awaitable(get_awaiter(static_cast<T&&>(awaitable)))
{
}

bool await_ready()
{
if (winrt_suspend_handler)
{
winrt_suspend_handler(this);
}

return awaitable.await_ready();
}

template <typename U>
auto await_suspend(std::experimental::coroutine_handle<U> handle)
{
return awaitable.await_suspend(handle);
}

auto await_resume()
{
if (winrt_resume_handler)
{
winrt_resume_handler(this);
}

return awaitable.await_resume();
}
};
}

WINRT_EXPORT namespace winrt
Expand Down Expand Up @@ -378,6 +526,12 @@ namespace std::experimental
{
winrt::terminate();
}

template <typename Expression>
auto await_transform(Expression&& expression)
{
return winrt::impl::notify_awaiter<Expression>{ static_cast<Expression&&>(expression) };
}
};
};
}
2 changes: 0 additions & 2 deletions strings/base_error.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@

__declspec(selectany) int32_t (__stdcall *winrt_to_hresult_handler)(void* address) noexcept{};

namespace winrt::impl
{
struct heap_traits
Expand Down
4 changes: 4 additions & 0 deletions strings/base_extern.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@

__declspec(selectany) int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {};
__declspec(selectany) void(__stdcall* winrt_suspend_handler)(void const* token) noexcept {};
__declspec(selectany) void(__stdcall* winrt_resume_handler)(void const* token) noexcept {};

extern "C"
{
int32_t __stdcall WINRT_GetRestrictedErrorInfo(void** info) noexcept;
Expand Down
12 changes: 10 additions & 2 deletions test/test/disconnected.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,20 @@ TEST_CASE("disconnected")

{
auto async = ActionProgress();
handle signal{ CreateEventW(nullptr, true, false, nullptr) };

async.Progress([](auto&&...)
{
throw hresult_error(RPC_E_DISCONNECTED);
});

async.Completed([](auto&&...)
async.Completed([&](auto&&...)
{
SetEvent(signal.get());
throw hresult_error(RPC_E_DISCONNECTED);
});

WaitForSingleObject(signal.get(), INFINITE);
}

{
Expand All @@ -102,15 +106,19 @@ TEST_CASE("disconnected")

{
auto async = OperationProgress();
handle signal{ CreateEventW(nullptr, true, false, nullptr) };

async.Progress([](auto&&...)
{
throw hresult_error(RPC_E_DISCONNECTED);
});

async.Completed([](auto&&...)
async.Completed([&](auto&&...)
{
SetEvent(signal.get());
throw hresult_error(RPC_E_DISCONNECTED);
});

WaitForSingleObject(signal.get(), INFINITE);
}
}
4 changes: 4 additions & 0 deletions test/test/generic_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@ TEST_CASE("generic_types")
REQUIRE_EQUAL_NAME(L"Windows.Foundation.Uri", Uri);
REQUIRE_EQUAL_NAME(L"Windows.Foundation.PropertyType", PropertyType);
REQUIRE_EQUAL_NAME(L"Windows.Foundation.Point", Point);

// Clang 9 doesn't think this is a constant expression.
#ifndef __clang__
REQUIRE_EQUAL_NAME(L"{96369f54-8eb6-48f0-abce-c1b211e627c3}", IStringable);
#endif
}
Loading