Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package qcoro for openSUSE:Factory checked 
in at 2023-02-09 16:23:24
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/qcoro (Old)
 and      /work/SRC/openSUSE:Factory/.qcoro.new.4462 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "qcoro"

Thu Feb  9 16:23:24 2023 rev:7 rq:1063962 version:0.8.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/qcoro/qcoro.changes      2022-11-24 
12:23:25.877374583 +0100
+++ /work/SRC/openSUSE:Factory/.qcoro.new.4462/qcoro.changes    2023-02-09 
16:23:25.174778676 +0100
@@ -1,0 +2,13 @@
+Thu Feb  9 08:26:04 UTC 2023 - Christophe Marin <[email protected]>
+
+- Update to 0.8.0
+  * test: use offscreen QPA for QCoroQuick tests
+  * Update pymdown-extensions requirement from ~=9.8 to ~=9.9
+  * cmake: make sure we explicitly find_package Qt private modules
+  * Update pygments requirement from ~=2.13 to ~=2.14
+  * Implement moveToThread() awaitable
+  * Implement sleepFor() and sleepUntil() coroutines
+  * Make QCoro::waitFor() usable with any awaitable
+  * Fix QCoro::waitFor() for Awaitable with operator co_await
+
+-------------------------------------------------------------------

Old:
----
  qcoro-0.7.0.tar.gz

New:
----
  qcoro-0.8.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ qcoro.spec ++++++
--- /var/tmp/diff_new_pack.MfAXuq/_old  2023-02-09 16:23:28.794797325 +0100
+++ /var/tmp/diff_new_pack.MfAXuq/_new  2023-02-09 16:23:28.798797345 +0100
@@ -36,7 +36,7 @@
 %endif
 #
 Name:           qcoro%{?_pkg_name_suffix}
-Version:        0.7.0
+Version:        0.8.0
 Release:        0
 Summary:        Coroutines for Qt
 License:        MIT

++++++ qcoro-0.7.0.tar.gz -> qcoro-0.8.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/.github/workflows/build-linux.yml 
new/qcoro-0.8.0/.github/workflows/build-linux.yml
--- old/qcoro-0.7.0/.github/workflows/build-linux.yml   2022-11-19 
23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/.github/workflows/build-linux.yml   2023-01-31 
20:50:01.000000000 +0100
@@ -4,6 +4,8 @@
   push:
     branches:
       - main
+    paths-ignore:
+      - 'docs/**'
   pull_request:
     types: [opened, synchronize, reopened, edited]
 
@@ -75,7 +77,7 @@
       shell: bash
       run: |
         cd build
-        QT_LOGGING_TO_CONSOLE=1 QT_QPA_PLATFORM=offscreen ctest -C $BUILD_TYPE 
\
+        QT_LOGGING_TO_CONSOLE=1 ctest -C $BUILD_TYPE \
           --output-on-failure \
           --verbose \
           --output-junit ${{ matrix.platform }}-${{ matrix.compiler_full 
}}-qt-${{ matrix.qt_version }}.xml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/.github/workflows/build-macos.yml 
new/qcoro-0.8.0/.github/workflows/build-macos.yml
--- old/qcoro-0.7.0/.github/workflows/build-macos.yml   2022-11-19 
23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/.github/workflows/build-macos.yml   2023-01-31 
20:50:01.000000000 +0100
@@ -4,6 +4,8 @@
   push:
     branches:
       - main
+    paths-ignore:
+      - 'docs/**'
   pull_request:
     types: [opened, synchronize, reopened, edited]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/.github/workflows/build-windows.yml 
new/qcoro-0.8.0/.github/workflows/build-windows.yml
--- old/qcoro-0.7.0/.github/workflows/build-windows.yml 2022-11-19 
23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/.github/workflows/build-windows.yml 2023-01-31 
20:50:01.000000000 +0100
@@ -4,6 +4,8 @@
   push:
     branches:
       - main
+    paths-ignore:
+      - 'docs/**'
   pull_request:
     types: [opened, synchronize, reopened, edited]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/.github/workflows/update-docs.yml 
new/qcoro-0.8.0/.github/workflows/update-docs.yml
--- old/qcoro-0.7.0/.github/workflows/update-docs.yml   2022-11-19 
23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/.github/workflows/update-docs.yml   2023-01-31 
20:50:01.000000000 +0100
@@ -1,4 +1,4 @@
-name: Generate documentation
+name: Build and Deploy Documentation
 
 on:
   push:
@@ -7,12 +7,17 @@
     paths:
       - 'mkdocs.yml'
       - 'docs/**'
+      - '.github/workflows/update_docs.yml'
 
   workflow_dispatch:
 
 jobs:
-  update-docs:
+  build-and-deploy:
+    name: Build and Deploy
     runs-on: ubuntu-latest
+    environment:
+      name: cloudflare-pages
+      url: ${{ steps.deploy.outputs.url }}
     steps:
       - uses: actions/checkout@v2
       - name: Setup Python
@@ -37,11 +42,15 @@
                 g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; 
s.parentNode.insertBefore(g,s);
               })();</script><!-- End Matomo Code -->{% endblock %}" > 
docs/overrides/main.html
           mkdocs build --verbose
-      - name: Deploy Github Pages
-        uses: peaceiris/actions-gh-pages@v3
+      - name: Deploy to Cloudflare Pages
+        id: deploy
+        uses: cloudflare/pages-action@1
+        env:
+          CLOUDFLARE_ACCOUNT_ID: ${{ SECRETS.CLOUDFLARE_ACCOUNT_ID }}
         with:
-          github_token: ${{ secrets.GITHUB_TOKEN }}
-          publish_dir: ./site
-          cname: qcoro.dvratil.cz
-          exclude_assets: '__pycache__'
+          apiToken: ${{ SECRETS.CLOUDFLARE_PAGES_TOKEN }}
+          accountId: ${{ SECRETS.CLOUDFLARE_ACCOUNT_ID }}
+          projectName: ${{ vars.CLOUDFLARE_PAGES_NAME }}
+          directory: ./site
+          githubToken: ${{ SECRETS.GITHUB_TOKEN }}
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/CMakeLists.txt 
new/qcoro-0.8.0/CMakeLists.txt
--- old/qcoro-0.7.0/CMakeLists.txt      2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/CMakeLists.txt      2023-01-31 20:50:01.000000000 +0100
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.18.4)
-set(qcoro_VERSION 0.7.0)
+set(qcoro_VERSION 0.8.0)
 set(qcoro_SOVERSION 0)
 project(qcoro LANGUAGES CXX VERSION ${qcoro_VERSION})
 
@@ -44,6 +44,8 @@
 include(cmake/CheckAtomic.cmake)
 
 set(REQUIRED_QT_COMPONENTS Core)
+set(REQUIRED_QT5_COMPONENTS)
+set(REQUIRED_QT6_COMPONENTS)
 if (QCORO_WITH_QTDBUS)
     list(APPEND REQUIRED_QT_COMPONENTS DBus)
 endif()
@@ -54,10 +56,12 @@
     list(APPEND REQUIRED_QT_COMPONENTS WebSockets)
 endif()
 if (QCORO_WITH_QTQUICK)
-    list(APPEND REQUIRED_QT_COMPONENTS Quick)
+    list(APPEND REQUIRED_QT_COMPONENTS Quick QuickPrivate)
 endif()
 if (QCORO_WITH_QML)
     list(APPEND REQUIRED_QT_COMPONENTS Qml)
+    # Qt6 needs access to private API
+    list(APPEND REQUIRED_QT6_COMPONENTS QmlPrivate)
 endif()
 if (QCORO_BUILD_EXAMPLES)
     list(APPEND REQUIRED_QT_COMPONENTS Widgets Concurrent)
@@ -69,21 +73,16 @@
 set(MIN_REQUIRED_QT5_VERSION "5.12")
 set(MIN_REQUIRED_QT6_VERSION "6.2.0")
 
-
-if (NOT USE_QT_VERSION)
-    # FIXME: find_package(QT NAMES Qt6 Qt5 ...) seems to prefer Qt5 on my 
system
-    find_package(Qt6 ${MIN_REQUIRED_QT6_VERSION} COMPONENTS 
${REQUIRED_QT_COMPONENTS})
-    if (NOT Qt6_FOUND)
-        find_package(Qt5 ${MIN_REQUIRED_QT5_VERSION} COMPONENTS 
${REQUIRED_QT_COMPONENTS} REQUIRED)
-        set(QT_VERSION_MAJOR 5)
-    else()
-        set(QT_VERSION_MAJOR 6)
-    endif()
-else()
-    find_package(Qt${USE_QT_VERSION} 
${MIN_REQUIRED_QT${USE_QT_VERSION}_VERSION}
-                 COMPONENTS ${REQUIRED_QT_COMPONENTS} REQUIRED)
-    set(QT_VERSION_MAJOR ${USE_QT_VERSION})
-endif()
+include(cmake/QCoroFindQt.cmake)
+# Find Qt. If USE_QT_VERSION is not set, it will try to look for Qt6 first
+# and fallback to Qt5 otherwise.
+qcoro_find_qt(
+    QT_VERSION "${USE_QT_VERSION}"
+    COMPONENTS "${REQUIRED_QT_COMPONENTS}"
+    QT5_COMPONENTS "${REQUIRED_QT5_COMPONENTS}"
+    QT6_COMPONENTS "${REQUIRED_QT6_COMPONENTS}"
+    FOUND_VER_VAR QT_VERSION_MAJOR
+)
 
 configure_file(
     ${CMAKE_CURRENT_SOURCE_DIR}/config.cmake.in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/README.md new/qcoro-0.8.0/README.md
--- old/qcoro-0.7.0/README.md   2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/README.md   2023-01-31 20:50:01.000000000 +0100
@@ -1,7 +1,7 @@
 [![Linux 
CI](https://github.com/danvratil/qcoro/actions/workflows/build-linux.yml/badge.svg)](https://github.com/danvratil/qcoro/actions/workflows/build-linux.yml)
 [![Windows 
CI](https://github.com/danvratil/qcoro/actions/workflows/build-windows.yml/badge.svg)](https://github.com/danvratil/qcoro/actions/workflows/build-windows.yml)
 [![MacOS 
CI](https://github.com/danvratil/qcoro/actions/workflows/build-macos.yml/badge.svg)](https://github.com/danvratil/qcoro/actions/workflows/build-macos.yml)
-[![Docs 
build](https://github.com/danvratil/qcoro/actions/workflows/update-docs.yml/badge.svg)](https://github.com/danvratil/qcoro/actions/workflows/update-docs.yml)
+[![Docs 
build](https://github.com/danvratil/qcoro/actions/workflows/update-docs.yml/badge.svg?branch=main)](https://github.com/danvratil/qcoro/actions/workflows/update-docs.yml)
 [![Latest 
release](https://img.shields.io/github/v/release/danvratil/qcoro?label=%F0%9F%93%A6%20Release)](https://github.com/danvratil/qcoro/releases)
 ![License: 
MIT](https://img.shields.io/badge/%E2%9A%96%EF%B8%8F%20License-MIT-brightgreen)
 ![C++20](https://img.shields.io/badge/C%2B%2B-20-%2300599C?logo=cplusplus)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/cmake/QCoroFindQt.cmake 
new/qcoro-0.8.0/cmake/QCoroFindQt.cmake
--- old/qcoro-0.7.0/cmake/QCoroFindQt.cmake     1970-01-01 01:00:00.000000000 
+0100
+++ new/qcoro-0.8.0/cmake/QCoroFindQt.cmake     2023-01-31 20:50:01.000000000 
+0100
@@ -0,0 +1,28 @@
+macro(qcoro_find_qt)
+    set(options)
+    set(oneValueArgs QT_VERSION FOUND_VER_VAR)
+    set(multiValueArgs COMPONENTS QT5_COMPONENTS QT6_COMPONENTS)
+    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" 
"${multiValueArgs}" ${ARGN})
+
+    if (NOT ARGS_QT_VERSION)
+        find_package(Qt6Core QUIET)
+        if (Qt6Core_FOUND)
+            set(ARGS_QT_VERSION 6)
+        else()
+            set(ARGS_QT_VERSION 5)
+        endif()
+    endif()
+
+    foreach (component IN LISTS ARGS_COMPONENTS 
ARGS_QT${ARGS_QT_VERSION}_COMPONENTS)
+        message(STATUS "Qt component: ${component}")
+        if ("${component}" MATCHES "Private$$")
+            string(REPLACE "Private" "" base_component "${component}")
+            find_package(Qt${ARGS_QT_VERSION}${base_component} REQUIRED 
COMPONENTS Private)
+        else()
+            find_package(Qt${ARGS_QT_VERSION}${component} REQUIRED)
+        endif()
+    endforeach()
+
+    set(${ARGS_FOUND_VER_VAR} ${ARGS_QT_VERSION})
+endmacro()
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/docs/changelog.md 
new/qcoro-0.8.0/docs/changelog.md
--- old/qcoro-0.7.0/docs/changelog.md   2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/docs/changelog.md   2023-01-31 20:50:01.000000000 +0100
@@ -10,6 +10,12 @@
 
 # Changelog
 
+## 0.7.0 (2022-11-20)
+
+* [Release announcement](news/2022/2022-11-17-qcoro-0.7.0-announcement.md)
+* [Github release 
changelog](https://github.com/danvratil/qcoro/releases/tag/v0.7.0)
+
+
 ## 0.6.0 (2022-07-09)
 
 * [Release announcement](news/2022/2022-07-09-qcoro-0.6.0-announcement.md)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qcoro-0.7.0/docs/news/2023/2023-01-31-qcoro-0.8.0-announcement.md 
new/qcoro-0.8.0/docs/news/2023/2023-01-31-qcoro-0.8.0-announcement.md
--- old/qcoro-0.7.0/docs/news/2023/2023-01-31-qcoro-0.8.0-announcement.md       
1970-01-01 01:00:00.000000000 +0100
+++ new/qcoro-0.8.0/docs/news/2023/2023-01-31-qcoro-0.8.0-announcement.md       
2023-01-31 20:50:01.000000000 +0100
@@ -0,0 +1,87 @@
+---
+title: QCoro 0.8.0 Release Announcement
+date: "2023-01-31"
+description: >
+  Improved QCoro::waitFor(), new sleepFor() and sleepUntil() helper functions 
and
+  improved thread support.
+---
+
+<!--
+SPDX-FileCopyrightText: 2022 Daniel Vrátil <[email protected]>
+
+SPDX-License-Identifier: GFDL-1.3-or-later
+-->
+
+# QCoro 0.8.0 Release Announcement
+
+This is a rather small release with only two new features and one small 
improvement.
+
+Big thank you to [Xstrahl Inc.](https://xstrahl.com) who sponsored development 
of
+new features included in this release and of QCoro in general.
+
+And as always, thank you to everyone who reported issues and contributed to 
QCoro.
+Your help is much appreciated!
+
+## Improved `QCoro::waitFor()`
+
+Up until this version, `QCoro::waitFor()` was only usable for `QCoro::Task<T>`.
+Starting with QCoro 0.8.0, it is possible to use it with any type that 
satisfies
+the `Awaitable` concept. The concept has also been fixed to satisfies not just
+types with the `await_resume()`, `await_suspend()` and `await_ready()` member 
functions,
+but also types with member `operator co_await()` and non-member `operator 
co_await()`
+functions.
+
+## `QCoro::sleepFor()` and `QCoro::sleepUntil()`
+
+Working both on QCoro codebase as well as some third-party code bases using 
QCoro
+it's clear that there's a usecase for a simple coroutine that will sleep for
+specified amount of time (or until a specified timepoint). It is especially 
useful
+in tests, where simulating delays, especially in asynchronous code is common.
+
+Previously I used to create small coroutines like this:
+
+```cpp
+QCoro::Task<> timer(std::chrono::milliseconds timeout) {
+    QTimer timer;
+    timer.setSingleShot(true);
+    timer.start(timeout);
+    co_await timer;
+}
+```
+
+Now we can do the same simply by using `QCoro::sleepFor()`.
+
+Read the [documentation for 
`QCoro::sleepFor()`](https://qcoro.dvratil.cz/reference/core/qtimer/#qcorosleepfor)
+and 
[`QCoro::sleepUntil()`](https://qcoro.dvratil.cz/reference/core/qtimer/#qcorosleepuntil)
 for more details.
+
+## `QCoro::moveToThread()`
+
+A small helper coroutine that allows a piece of function to be executed in the 
context
+of another thread.
+
+```cpp
+void App::runSlowOperation(QThread *helperThread) {
+    // Still on the main thread
+    ui->statusLabel.setText(tr("Running"));
+
+    const QString input = ui->userInput.text();
+
+    co_await QCoro::moveToThread(helperThread);
+    // Now we are running in the context of the helper thread, the main thread 
is not blocked
+
+    // It is safe to use `input` which was created in another thread
+    doSomeComplexCalculation(input);
+
+    // Move the execution back to the main thread
+    co_await QCoro::moveToThread(this->thread());
+    // Runs on the main thread again
+    ui->statusLabel.setText(tr("Done"));
+}
+```
+
+Read the [documentation for 
`QCoro::moveToThread`](https://qcoro.dvratil.cz/reference/core/qthread#qcoromovetothread)
 for more details.
+
+## Full changelog
+
+[See changelog on 
Github](https://github.com/danvratil/qcoro/releases/tag/v0.8.0)
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/docs/reference/core/qthread.md 
new/qcoro-0.8.0/docs/reference/core/qthread.md
--- old/qcoro-0.7.0/docs/reference/core/qthread.md      2022-11-19 
23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/docs/reference/core/qthread.md      2023-01-31 
20:50:01.000000000 +0100
@@ -50,6 +50,19 @@
 QCoro::Task<bool> QCoroThread::waitForFinished(std::chrono::milliseconds 
timeout);
 ```
 
+## `QCoro::moveToThread()`
+
+A helper coroutine that allows changing the thread context in which the 
coroutine
+code is currently being executed.
+
+When `co_await`ed, the current coroutine will be suspended on the current 
thread and 
+immediately resumed again, but in the context of the thread that was passed in 
as
+an argument.
+
+```cpp
+QCoro::Task<> QCoro::moveToThread(QThread *thread);
+```
+
 ## Examples
 
 ```cpp
@@ -58,6 +71,6 @@
 
 
 [qtdoc-qthread]: https://doc.qt.io/qt-5/qthread.html
-[qtdoc-qthread-waitForStarted]: 
https://doc.qt.io/qt-5/qthread.html#waitForStarted
-[qtdoc-qthread-waitForFiished]: 
https://doc.qt.io/qt-5/qthread.html#waitForFinished
+[qtdoc-qthread-started]: https://doc.qt.io/qt-5/qthread.html#started
+[qtdoc-qthread-finished]: https://doc.qt.io/qt-5/qthread.html#finished
 [qcoro-coro]: ../coro/coro.md
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/docs/reference/core/qtimer.md 
new/qcoro-0.8.0/docs/reference/core/qtimer.md
--- old/qcoro-0.7.0/docs/reference/core/qtimer.md       2022-11-19 
23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/docs/reference/core/qtimer.md       2023-01-31 
20:50:01.000000000 +0100
@@ -46,5 +46,38 @@
 }
 ```
 
+## `QCoro::sleepFor()`
+
+A simple coroutine that will suspend for the specified time duration. Can be 
quite
+useful especially in unit-tests.
+
+```cpp
+template<typename Rep, typename Period>
+QCoro::Task<> QCoro::sleepFor(const std::chrono::duration<Rep, Period> 
&timeout);
+```
+
+## `QCoro::sleepUntil()`
+
+A simple coroutine that will suspend until the specified point in time. Can be 
useful
+for scheduling tasks.
+
+```cpp
+template<typename Clock, typename Duration>
+QCoro::Task< QCoro::sleepUntil(const std::chrono::time_point<Clock, Duration> 
&when);
+```
+
+Example:
+
+```cpp
+const auto now = std::chrono::system_clock::now();
+const auto tomorrow_time = std::chrono::system_clock::to_time_t(now + 86400s);
+std::tm *gt = std::gmtime(&tomorrow_time);
+gt.tm_hour = 0;
+gt.tm_min = 0;
+gt.tm_sec = 0;
+const auto tomorrow_midnight = std::mktime(&gt);
+co_await 
QCoro::sleepUntil(std::chrono::system_clock::from_time_t(tomorrow_midnight));
+```
+
 [qdoc-qtimer]: https://doc.qt.io/qt-5/qtimer.html
 [qdoc-qtimer-timeout]: https://doc.qt.io/qt-5/qtimer.html#timeout
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/docs/reference/coro/task.md 
new/qcoro-0.8.0/docs/reference/coro/task.md
--- old/qcoro-0.7.0/docs/reference/coro/task.md 2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/docs/reference/coro/task.md 2023-01-31 20:50:01.000000000 
+0100
@@ -147,14 +147,17 @@
 until the coroutine finishes. If the coroutine has a non-void return value, 
the value is returned
 from `waitFor().`
 
+Since QCoro 0.8.0 it is possible to use `QCoro::waitFor()` with any awaitable 
type, not just `QCoro::Task<T>`.
+
 ```cpp
 QCoro::Task<int> computeAnswer() {
-    std::this_thread::sleep_for(std::chrono::year{7'500'000});
+    co_await QCoro::sleepFor(std::chrono::years{7'500'00});
     co_return 42;
 }
 
 void nonCoroutineFunction() {
-    // The following line will block as if computeAnswer were not a coroutine.
+    // The following line will block as if computeAnswer were not a coroutine. 
It will internally run a
+    // a QEventLoop, so other events are still processed.
     const int answer = QCoro::waitFor(computeAnswer());
     std::cout << "The answer is: " << answer << std::endl;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/examples/network/main.cpp 
new/qcoro-0.8.0/examples/network/main.cpp
--- old/qcoro-0.7.0/examples/network/main.cpp   2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/examples/network/main.cpp   2023-01-31 20:50:01.000000000 
+0100
@@ -63,14 +63,13 @@
         mBtn->setEnabled(false);
         mBtn->setText(tr("Downloading ..."));
 
-        auto *reply = co_await mNam.get(QNetworkRequest{wikiUrl});
+        std::unique_ptr<QNetworkReply> reply(co_await 
mNam.get(QNetworkRequest{wikiUrl}));
         if (reply->error()) {
             QMessageBox::warning(
                 this, tr("Network request error"),
                 tr("Error occured during network request. Error code: 
%1").arg(reply->error()));
             co_return;
         }
-        delete reply;
 
         mPb->setVisible(false);
         mBtn->setEnabled(true);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/mkdocs.yml new/qcoro-0.8.0/mkdocs.yml
--- old/qcoro-0.7.0/mkdocs.yml  2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/mkdocs.yml  2023-01-31 20:50:01.000000000 +0100
@@ -28,7 +28,8 @@
   - admonition
 
 plugins:
-  - search
+  - search:
+      separator: '[\s\-]+|::'
   - include-markdown
   - blogging:
       dirs:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/qcoro/core/qcorothread.cpp 
new/qcoro-0.8.0/qcoro/core/qcorothread.cpp
--- old/qcoro-0.7.0/qcoro/core/qcorothread.cpp  2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/qcoro/core/qcorothread.cpp  2023-01-31 20:50:01.000000000 
+0100
@@ -7,8 +7,80 @@
 
 #include <QThread>
 
+using namespace QCoro;
 using namespace QCoro::detail;
 
+namespace QCoro::detail {
+
+class ContextHelper : public QObject {
+    Q_OBJECT
+public:
+    static QEvent::Type eventType;
+
+    explicit ContextHelper(std::coroutine_handle<> awaiter, QThread *thread)
+        : mThread(thread)
+        , mAwaiter(awaiter)
+    {}
+
+    bool event(QEvent *event) override {
+        if (event->type() == eventType) {
+            Q_ASSERT(QThread::currentThread() == mThread);
+            mAwaiter.resume();
+            return true;
+        }
+
+        return QObject::event(event);
+    }
+
+private:
+    QThread *mThread;
+    std::coroutine_handle<> mAwaiter;
+};
+
+QEvent::Type ContextHelper::eventType = 
static_cast<QEvent::Type>(QEvent::registerEventType());
+
+class ThreadContextPrivate {
+public:
+    explicit ThreadContextPrivate(QThread *thread)
+        : mThread(thread)
+    {}
+
+    QThread *mThread;
+    std::unique_ptr<ContextHelper> mContext;
+};
+
+} // namespace QCoro::detail
+
+ThreadContext::ThreadContext(QThread *thread)
+    : d(std::make_unique<ThreadContextPrivate>(thread))
+{}
+
+#ifdef Q_CC_GNU
+ThreadContext::ThreadContext(ThreadContext &&) noexcept  = default;
+#endif
+
+ThreadContext::~ThreadContext() = default;
+
+bool ThreadContext::await_ready() const noexcept {
+    return false; // never ready!
+}
+
+void ThreadContext::await_suspend(std::coroutine_handle<> awaiter) noexcept {
+    d->mContext = std::make_unique<ContextHelper>(awaiter, d->mThread);
+    d->mContext->moveToThread(d->mThread);
+    qCoro(d->mThread).waitForStarted().then([this]() {
+        auto *event = new 
QEvent(static_cast<QEvent::Type>(detail::ContextHelper::eventType));
+        QCoreApplication::postEvent(d->mContext.get(), event);
+    });
+}
+
+void ThreadContext::await_resume() noexcept {}
+
+
+ThreadContext QCoro::moveToThread(QThread *thread) {
+    return ThreadContext(thread);
+}
+
 QCoroThread::QCoroThread(QThread *thread)
     : mThread(thread)
 {}
@@ -36,3 +108,5 @@
     const auto result = co_await qCoro(mThread.data(), &QThread::finished, 
timeout);
     co_return result.has_value();
 }
+
+#include "qcorothread.moc"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/qcoro/core/qcorothread.h 
new/qcoro-0.8.0/qcoro/core/qcorothread.h
--- old/qcoro-0.7.0/qcoro/core/qcorothread.h    2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/qcoro/core/qcorothread.h    2023-01-31 20:50:01.000000000 
+0100
@@ -5,7 +5,9 @@
 #pragma once
 
 #include <QPointer>
+
 #include "qcorocore_export.h"
+#include "qcoro/coroutine.h"
 
 #include <chrono>
 
@@ -14,6 +16,36 @@
 namespace QCoro {
 template<typename T>
 class Task;
+
+namespace detail {
+class ThreadContextPrivate;
+} // namespace detail
+
+class ThreadContext {
+public:
+    explicit ThreadContext(QThread *thread);
+    ~ThreadContext();
+    ThreadContext(const ThreadContext &) = delete;
+    ThreadContext &operator=(const ThreadContext &) = delete;
+#ifdef Q_CC_GNU
+    // Workaround for the a GCC bug(?) where GCC tries to move the 
ThreadContext
+    // into QCoro::TaskPromise::await_transform() (most likely).
+    ThreadContext(ThreadContext &&) noexcept;
+#else
+    ThreadContext(ThreadContext &&) = delete;
+#endif
+    ThreadContext &operator=(ThreadContext &&) = delete;
+
+    bool await_ready() const noexcept;
+    void await_suspend(std::coroutine_handle<> awaiter) noexcept;
+    void await_resume() noexcept;
+
+private:
+    std::unique_ptr<detail::ThreadContextPrivate> d;
+};
+
+ThreadContext moveToThread(QThread *thread);
+
 } // namespace QCoro
 
 namespace QCoro::detail {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/qcoro/core/qcorotimer.h 
new/qcoro-0.8.0/qcoro/core/qcorotimer.h
--- old/qcoro-0.7.0/qcoro/core/qcorotimer.h     2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/qcoro/core/qcorotimer.h     2023-01-31 20:50:01.000000000 
+0100
@@ -52,6 +52,26 @@
 
 } // namespace QCoro::detail
 
+namespace QCoro {
+
+//! A coroutine that suspends for given period of time.
+template<typename Rep, typename Period>
+QCoro::Task<> sleepFor(const std::chrono::duration<Rep, Period> &timeout) {
+    QTimer timer;
+    timer.setSingleShot(true);
+    
timer.start(std::chrono::duration_cast<std::chrono::milliseconds>(timeout));
+    co_await timer;
+}
+
+//! A coroutine that suspends until the specified time.
+template<typename Clock, typename Duration>
+QCoro::Task<> sleepUntil(const std::chrono::time_point<Clock, Duration> &when) 
{
+    const auto tp = when.time_since_epoch() - 
std::chrono::steady_clock::now().time_since_epoch();
+    return sleepFor(tp);
+}
+
+} // namespace QCoro
+
 /*! \endcond */
 
 //! Returns a coroutine-friendly wrapper for QTimer object.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/qcoro/coroutine.h 
new/qcoro-0.8.0/qcoro/coroutine.h
--- old/qcoro-0.7.0/qcoro/coroutine.h   2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/qcoro/coroutine.h   2023-01-31 20:50:01.000000000 +0100
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <version>
+#include <utility>
 
 // __cpp_lib_coroutine is not defined if the compiler doesn't support 
coroutines
 // (__cpp_impl_coroutine), e.g. clang as of 13.0.
@@ -257,6 +258,7 @@
 
 namespace detail {
 
+
 template<typename T>
 concept has_await_methods = requires(T t) {
     { t.await_ready() } -> std::same_as<bool>;
@@ -265,11 +267,21 @@
 };
 
 template<typename T>
-concept has_operator_coawait = requires(T t) {
+concept has_member_operator_coawait = requires(T t) {
     // TODO: Check that result of co_await() satisfies Awaitable again
     { t.operator co_await() };
 };
 
+template<typename T>
+concept has_nonmember_operator_coawait = requires(T t) {
+    // TODO: Check that result of the operator satisfied Awaitable again
+#if defined(_MSC_VER) && !defined(__clang__)
+    // FIXME: MSVC is unable to perform ADL lookup for operator co_await and 
just fails to compile
+    { ::operator co_await(static_cast<T &&>(t)) };
+#else
+    { operator co_await(static_cast<T &&>(t)) };
+#endif
+};
 
 } // namespace detail
 
@@ -278,7 +290,8 @@
  * Awaitable type is a type that can be passed as an argument to co_await.
  */
 template<typename T>
-concept Awaitable = detail::has_operator_coawait<T> ||
+concept Awaitable = detail::has_member_operator_coawait<T> ||
+                    detail::has_nonmember_operator_coawait<T> ||
                     detail::has_await_methods<T>;
 
 } // namespace QCoro
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/qcoro/qcorotask.h 
new/qcoro-0.8.0/qcoro/qcorotask.h
--- old/qcoro-0.7.0/qcoro/qcorotask.h   2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/qcoro/qcorotask.h   2023-01-31 20:50:01.000000000 +0100
@@ -661,10 +661,42 @@
     return Task<void>{std::coroutine_handle<TaskPromise>::from_promise(*this)};
 }
 
-} // namespace detail
 
 
-namespace detail {
+template <typename T>
+concept TaskConvertible = requires(T v, TaskPromiseBase t)
+{
+    { t.await_transform(v) };
+};
+
+template<typename T>
+struct awaitable_return_type {
+  using type = std::decay_t<decltype(std::declval<T>().await_resume())>;
+};
+
+template<QCoro::detail::has_member_operator_coawait T>
+struct awaitable_return_type<T> {
+    using type = std::decay_t<typename 
awaitable_return_type<decltype(std::declval<T>().operator co_await())>::type>;
+};
+
+template<QCoro::detail::has_nonmember_operator_coawait T>
+struct awaitable_return_type<T> {
+    using type = std::decay_t<typename awaitable_return_type<decltype(operator 
co_await(std::declval<T>()))>::type>;
+};
+
+template<Awaitable Awaitable>
+using awaitable_return_type_t = typename 
detail::awaitable_return_type<Awaitable>::type;
+
+template <typename Awaitable>
+requires TaskConvertible<Awaitable>
+using convertible_awaitable_return_type_t = typename 
detail::awaitable_return_type<decltype(std::declval<TaskPromiseBase>().await_transform(Awaitable()))>::type;
+
+template <typename Awaitable>
+requires TaskConvertible<Awaitable>
+auto toTask(Awaitable &&future) -> 
QCoro::Task<detail::convertible_awaitable_return_type_t<Awaitable>> {
+    co_return co_await future;
+}
+
 
 //! Helper class to run a coroutine in a nested event loop.
 /*!
@@ -675,32 +707,32 @@
  * So instead we do basically what Qt does internally, but we make sure to not 
delete th
  * QFunctorSlotObjectWithNoArgs until after the event loop quits.
  */
-template<typename Coroutine>
-Task<> runCoroutine(QEventLoop &loop, bool &startLoop, Coroutine &&coroutine) {
-    co_await coroutine;
+template<Awaitable Awaitable>
+Task<> runCoroutine(QEventLoop &loop, bool &startLoop, Awaitable &&awaitable) {
+    co_await awaitable;
     startLoop = false;
     loop.quit();
 }
 
-template<typename T, typename Coroutine>
-Task<> runCoroutine(QEventLoop &loop, bool &startLoop, T &result, Coroutine 
&&coroutine) {
-    result = co_await coroutine;
+template<typename T, Awaitable Awaitable>
+Task<> runCoroutine(QEventLoop &loop, bool &startLoop, T &result, Awaitable 
&&awaitable) {
+    result = co_await awaitable;
     startLoop = false;
     loop.quit();
 }
 
-template<typename T, typename Coroutine>
-T waitFor(Coroutine &&coro) {
+template<typename T, Awaitable Awaitable>
+T waitFor(Awaitable &&awaitable) {
     QEventLoop loop;
     bool startLoop = true; // for early returns: calling quit() before exec() 
still starts the loop
     if constexpr (std::is_void_v<T>) {
-        runCoroutine(loop, startLoop, std::forward<Coroutine>(coro));
+        runCoroutine(loop, startLoop, std::forward<Awaitable>(awaitable));
         if (startLoop) {
             loop.exec();
         }
     } else {
         T result;
-        runCoroutine(loop, startLoop, result, std::forward<Coroutine>(coro));
+        runCoroutine(loop, startLoop, result, 
std::forward<Awaitable>(awaitable));
         if (startLoop) {
             loop.exec();
         }
@@ -721,43 +753,18 @@
  */
 template<typename T>
 inline T waitFor(QCoro::Task<T> &task) {
-    return detail::waitFor<T>(task);
+    return detail::waitFor<T>(std::forward<QCoro::Task<T>>(task));
 }
 
 // \overload
 template<typename T>
 inline T waitFor(QCoro::Task<T> &&task) {
-    return detail::waitFor<T>(task);
-}
-
-namespace detail {
-
-template <typename T>
-concept TaskConvertible = requires(T v, TaskPromiseBase t)
-{
-    { t.await_transform(v) };
-};
-
-template<typename T>
-struct awaitable_return_type {
-  using type = decltype(std::declval<T>().await_resume());
-};
-
-template<QCoro::detail::has_operator_coawait T>
-struct awaitable_return_type<T> {
-    using type = typename 
awaitable_return_type<decltype(std::declval<T>().operator co_await())>::type;
-};
-
-template <typename Awaitable>
-requires TaskConvertible<Awaitable>
-using awaitable_return_type_t = typename 
detail::awaitable_return_type<decltype(std::declval<TaskPromiseBase>().await_transform(Awaitable()))>::type;
-
-template <typename Awaitable>
-requires TaskConvertible<Awaitable>
-auto toTask(Awaitable &&future) -> 
QCoro::Task<detail::awaitable_return_type_t<Awaitable>> {
-    co_return co_await future;
+    return detail::waitFor<T>(std::forward<QCoro::Task<T>>(task));
 }
 
+template<Awaitable Awaitable>
+inline auto waitFor(Awaitable &&awaitable) {
+    return 
detail::waitFor<detail::awaitable_return_type_t<Awaitable>>(std::forward<Awaitable>(awaitable));
 }
 
 //! Connect a callback to be called when the asynchronous task finishes.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/qcoro/quick/CMakeLists.txt 
new/qcoro-0.8.0/qcoro/quick/CMakeLists.txt
--- old/qcoro-0.7.0/qcoro/quick/CMakeLists.txt  2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/qcoro/quick/CMakeLists.txt  2023-01-31 20:50:01.000000000 
+0100
@@ -12,5 +12,5 @@
     QCORO_LINK_LIBRARIES
         PUBLIC Coro Core
     QT_LINK_LIBRARIES
-        PUBLIC Core Quick
+    PUBLIC Core Quick
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/requirements.txt 
new/qcoro-0.8.0/requirements.txt
--- old/qcoro-0.7.0/requirements.txt    2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/requirements.txt    2023-01-31 20:50:01.000000000 +0100
@@ -1,7 +1,7 @@
 setuptools
 wheel
-pymdown-extensions~=9.8
-pygments~=2.13
+pymdown-extensions~=9.9
+pygments~=2.14
 mkdocs
 mkdocs-material
 mkdocs-section-index
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/tests/CMakeLists.txt 
new/qcoro-0.8.0/tests/CMakeLists.txt
--- old/qcoro-0.7.0/tests/CMakeLists.txt        2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/tests/CMakeLists.txt        2023-01-31 20:50:01.000000000 
+0100
@@ -100,6 +100,9 @@
         Qt${QT_VERSION_MAJOR}::Quick
         Qt${QT_VERSION_MAJOR}::QuickPrivate
     )
+    get_test_property(test-${_name} ENVIRONMENT _env)
+    list(APPEND _env QT_QPA_PLATFORM=offscreen)
+    set_tests_properties(test-${_name} PROPERTIES ENVIRONMENT "${_env}")
 endfunction()
 
 qcoro_add_test(qtimer)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/tests/qcorotask.cpp 
new/qcoro-0.8.0/tests/qcorotask.cpp
--- old/qcoro-0.7.0/tests/qcorotask.cpp 2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/tests/qcorotask.cpp 2023-01-31 20:50:01.000000000 +0100
@@ -58,6 +58,66 @@
     QString string;
 };
 
+struct TestAwaitableBase {
+    std::chrono::milliseconds delay() const { return mDelay; }
+private:
+    std::chrono::milliseconds mDelay = 100ms;
+};
+
+template<typename T>
+struct TestAwaitable : TestAwaitableBase {
+public:
+    TestAwaitable(T val)
+        : mResult(val)
+    {}
+
+    bool await_ready() const { return false; }
+    void await_suspend(std::coroutine_handle<> handle) {
+        QTimer::singleShot(100ms, [handle = std::move(handle)]() {
+            handle.resume();
+        });
+    }
+    T await_resume() {
+        return mResult;
+    }
+
+private:
+    T mResult;
+};
+
+template<>
+struct TestAwaitable<void> : TestAwaitableBase {
+public:
+    bool await_ready() const { return false; }
+    void await_suspend(std::coroutine_handle<> handle) {
+        QTimer::singleShot(100ms, [handle = std::move(handle)]() {
+            handle.resume();
+        });
+    }
+    void await_resume() {}
+};
+
+template<typename T>
+struct TestAwaitableWithCoAwait {
+    TestAwaitableWithCoAwait(T val)
+        : mResult(val)
+    {}
+
+    TestAwaitable<T> operator co_await() {
+        return TestAwaitable(mResult);
+    }
+
+private:
+    T mResult;
+};
+
+template<>
+struct TestAwaitableWithCoAwait<void> {
+    TestAwaitable<void> operator co_await() {
+        return TestAwaitable<void>();
+    }
+};
+
 } // namespace
 
 class QCoroTaskTest : public QCoro::TestObject<QCoroTaskTest>
@@ -489,6 +549,53 @@
         QCOMPARE(result, 42);
     }
 
+    void testWaitForAwaitable() {
+        TestAwaitable<int> awaitable(42);
+        QElapsedTimer timer;
+        timer.start();
+
+        static_assert(std::is_same_v<decltype(QCoro::waitFor(awaitable)), 
int>);
+        const int result = QCoro::waitFor(awaitable);
+        QCOMPARE(result, 42);
+        QVERIFY(timer.elapsed() >= 
static_cast<float>(awaitable.delay().count()) * 0.9);
+
+    }
+
+    void testWaitForVoidAwaitable() {
+        TestAwaitable<void> awaitable;
+        QElapsedTimer timer;
+        timer.start();
+
+        static_assert(std::is_void_v<decltype(QCoro::waitFor(awaitable))>);
+        QCoro::waitFor(awaitable);
+
+        QVERIFY(timer.elapsed() >= 
static_cast<float>(awaitable.delay().count()) * 0.9);
+    }
+
+    void testWaitForAwaitableWithOperatorCoAwait() {
+        TestAwaitableWithCoAwait<int> awaitable(42);
+        QCoro::waitFor(awaitable);
+        QElapsedTimer timer;
+        timer.start();
+
+        static_assert(std::is_same_v<decltype(QCoro::waitFor(awaitable)), 
int>);
+        const int result = QCoro::waitFor(awaitable);
+        QCOMPARE(result, 42);
+        QVERIFY(timer.elapsed() >= (90ms).count());
+    }
+
+    void testWaitForVoidAwaitableWithOperatorCoAwait() {
+        TestAwaitableWithCoAwait<void> awaitable;
+        QElapsedTimer timer;
+        timer.start();
+
+        static_assert(std::is_void_v<decltype(QCoro::waitFor(awaitable))>);
+        QCoro::waitFor(awaitable);
+
+        QVERIFY(timer.elapsed() >= (90ms).count());
+    }
+
+
     void testIgnoredVoidTaskResult() {
         QEventLoop el;
         ignoreCoroutineResult(el, [&el]() -> QCoro::Task<> {
@@ -626,6 +733,8 @@
 
         QVERIFY(!called);
     }
+
+
 };
 
 QTEST_GUILESS_MAIN(QCoroTaskTest)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/tests/qcorothread.cpp 
new/qcoro-0.8.0/tests/qcorothread.cpp
--- old/qcoro-0.7.0/tests/qcorothread.cpp       2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/tests/qcorothread.cpp       2023-01-31 20:50:01.000000000 
+0100
@@ -47,9 +47,28 @@
         QCORO_VERIFY(ok);
     }
 
+    QCoro::Task<> testMoveToThread_coro(QCoro::TestContext) {
+        QThread newThread;
+        newThread.start();
+
+        QCORO_COMPARE(QThread::currentThread(), 
QCoreApplication::instance()->thread());
+
+        co_await QCoro::moveToThread(&newThread);
+
+        QCORO_COMPARE(QThread::currentThread(), &newThread);
+
+        co_await QCoro::moveToThread(qApp->thread());
+
+        QCORO_COMPARE(QThread::currentThread(), 
QCoreApplication::instance()->thread());
+
+        newThread.exit();
+        newThread.wait();
+    }
+
 private Q_SLOTS:
     addTest(WaitForStarted)
     addTest(WaitForFinished)
+    addTest(MoveToThread)
 };
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/tests/qtimer.cpp 
new/qcoro-0.8.0/tests/qtimer.cpp
--- old/qcoro-0.7.0/tests/qtimer.cpp    2022-11-19 23:54:23.000000000 +0100
+++ new/qcoro-0.8.0/tests/qtimer.cpp    2023-01-31 20:50:01.000000000 +0100
@@ -6,6 +6,10 @@
 
 #include "qcorotimer.h"
 
+#include <chrono>
+
+using namespace std::chrono_literals;
+
 class QCoroTimerTest : public QCoro::TestObject<QCoroTimerTest> {
     Q_OBJECT
 
@@ -68,12 +72,28 @@
         QVERIFY(triggered);
     }
 
+    QCoro::Task<> testSleepFor_coro(QCoro::TestContext) {
+        QElapsedTimer elapsed;
+        elapsed.start();
+        co_await QCoro::sleepFor(100ms);
+        QCORO_VERIFY(elapsed.elapsed() >= 75);
+    }
+
+    QCoro::Task<> testSleepUntil_coro(QCoro::TestContext) {
+        QElapsedTimer elapsed;
+        elapsed.start();
+        co_await QCoro::sleepUntil(std::chrono::steady_clock::now() + 500ms);
+        QCORO_VERIFY(elapsed.elapsed() >= 475);
+    }
+
 private Q_SLOTS:
     addTest(Triggers)
     addTest(QCoroWrapperTriggers)
     addTest(DoesntBlockEventLoop)
     addTest(DoesntCoAwaitInactiveTimer)
     addTest(DoesntCoAwaitNullTimer)
+    addTest(SleepFor)
+    addTest(SleepUntil)
 
     addThenTest(Triggers)
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qcoro-0.7.0/tests/testconstraints.cpp 
new/qcoro-0.8.0/tests/testconstraints.cpp
--- old/qcoro-0.7.0/tests/testconstraints.cpp   2022-11-19 23:54:23.000000000 
+0100
+++ new/qcoro-0.8.0/tests/testconstraints.cpp   2023-01-31 20:50:01.000000000 
+0100
@@ -14,7 +14,7 @@
 template<QCoro::Awaitable T>
 static constexpr bool is_awaitable_v = is_awaitable<T>::value;
 
-}
+} // namespace helper
 
 struct TestAwaitable {
     bool await_ready() const { return true; }
@@ -22,6 +22,33 @@
     void await_resume() const;
 };
 
+struct TestAwaitableWithOperatorCoAwait {
+    TestAwaitable operator co_await() {
+        return TestAwaitable{};
+    }
+};
+
+namespace TestNS {
+
+struct TestAwaitableWithNonmemberOperatorCoAwait {};
+
+#if !defined(_MSC_VER) || defined(__clang__)
+// This is how it's supposed to work: the operator must be defined in the same 
namespace
+// as the argument type and is discovered via ADL.
+auto operator co_await(TestAwaitableWithNonmemberOperatorCoAwait &&) {
+    return TestAwaitable{};
+}
+#endif
+
+} // namespace TestNS
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// Unfortunately, MSVC is only able to find the operator in global namespace :(
+// This is most likely a bug in MSVC.
+auto operator co_await(TestNS::TestAwaitableWithNonmemberOperatorCoAwait &&) {
+    return TestAwaitable{};
+}
+#endif
 
 class TestConstraints : public QObject {
     Q_OBJECT
@@ -31,7 +58,11 @@
         static_assert(helper::is_awaitable_v<QCoro::Task<void>>,
                       "Awaitable concept doesn't accept Task<T>, although it 
should.");
         static_assert(helper::is_awaitable_v<TestAwaitable>,
-                      "Awaitable concept doesn't accept TestAwaitable, 
although it should.");
+                      "Awaitable concept doesn't accept an awaitable with 
await member functions.");
+        static_assert(helper::is_awaitable_v<TestAwaitableWithOperatorCoAwait>,
+                      "Awaitable concept doesn't accept an awaitable with 
member operator co_await.");
+        
static_assert(helper::is_awaitable_v<TestNS::TestAwaitableWithNonmemberOperatorCoAwait>,
+                      "Awaitable concept doesn't accept an awaitable with 
non-member operator co_await.");
     }
 };
 

Reply via email to