diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..83403d9 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,54 @@ +# Copilot Instructions + +## Build Configuration + +**Always use debug builds when developing and testing.** Use the appropriate debug preset for your platform: + +- **MSVC on Windows:** `msvc-windows-x64-debug` +- **Clang on Windows:** `clang-windows-x64-debug` (or `clang-windows-x64-debug-local` if using `CMakeUserPresets.json`) +- **Clang on Linux:** `clang-linux-x64-debug` (or `clang-linux-x64-debug-local` if using `CMakeUserPresets.json`) + +Debug builds enable AddressSanitizer (`/fsanitize=address`) on MSVC, which helps catch memory errors during development. + +**All build and test commands must be run from a Visual Studio 2026 Developer PowerShell session.** Load it with: + +```powershell +Import-Module "C:\Program Files\Microsoft Visual Studio\18\Enterprise\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" +Enter-VsDevShell -VsInstallPath "C:\Program Files\Microsoft Visual Studio\18\Enterprise" -Arch amd64 -SkipAutomaticLocation +``` + +See [BUILDING.md](../BUILDING.md) for full build instructions. + +## Project Overview + +Phantom.Coroutines is a C++23 coroutine library with two implementation options: + +- **Header-only:** include headers from `Phantom.Coroutines/include/` +- **C++ Modules:** build and link against the `Phantom.Coroutines.Modules` CMake target + +Tests are in `Phantom.Coroutines.Test/` and cppcoro-compatibility tests in `Phantom.Coroutines.cppcoro.Test/`. + +## Testing + +### During development (iterative) + +Build and run only the C++ modules implementation and its tests. This is faster and catches most issues: + +``` +cmake --build --preset msvc-windows-x64-debug --target Phantom.Coroutines.Modules.Test +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.Test\Phantom.Coroutines.Modules.Test.exe +``` + +### When a task is complete (full suite) + +Build everything and run all three test executables: + +``` +cmake --build --preset msvc-windows-x64-debug +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.Test\Phantom.Coroutines.Test.exe +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.Test\Phantom.Coroutines.Modules.Test.exe +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.Test\Phantom.Coroutines.SingleModule.Test.exe +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.cppcoro.Test\Phantom.Coroutines.cppcoro.Test.exe +``` + +All PRs must include unit tests. Follow the existing naming style: descriptive test names with single-purpose assertions. diff --git a/.github/workflows/ok-to-test-command.yml b/.github/workflows/ok-to-test-command.yml new file mode 100644 index 0000000..53b6044 --- /dev/null +++ b/.github/workflows/ok-to-test-command.yml @@ -0,0 +1,21 @@ +name: ok-to-test command + +on: + issue_comment: + types: + - created + +permissions: + contents: read + issues: write + pull-requests: write + +jobs: + ok-to-test: + if: > + github.event.issue.pull_request && + (github.event.comment.body == '/ok-to-test' || + github.event.comment.body == '/remove-ok-to-test') + uses: JoshuaRowePhantom/Phantom.ContinuousIntegration/.github/workflows/ok-to-test-command.yml@main + with: + repository-profile: Phantom.Coroutines diff --git a/.github/workflows/pull-request-continuous-integration.yml b/.github/workflows/pull-request-continuous-integration.yml new file mode 100644 index 0000000..1813e9f --- /dev/null +++ b/.github/workflows/pull-request-continuous-integration.yml @@ -0,0 +1,21 @@ +name: Pull Request Continuous Integration + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + - unlabeled + - ready_for_review + +permissions: + contents: read + id-token: write + +jobs: + pull-request-continuous-integration: + uses: JoshuaRowePhantom/Phantom.ContinuousIntegration/.github/workflows/pull-request-continuous-integration.yml@main + with: + repository-profile: Phantom.Coroutines diff --git a/.github/workflows/pull-request-gate.yml b/.github/workflows/pull-request-gate.yml new file mode 100644 index 0000000..cc269ae --- /dev/null +++ b/.github/workflows/pull-request-gate.yml @@ -0,0 +1,21 @@ +name: Pull Request Gate + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + - unlabeled + - ready_for_review + +permissions: + contents: read + pull-requests: write + +jobs: + continuous-integration-eligibility: + uses: JoshuaRowePhantom/Phantom.ContinuousIntegration/.github/workflows/pull-request-gate.yml@main + with: + repository-profile: Phantom.Coroutines diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..2def7bc --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,99 @@ +# Building Phantom.Coroutines + +Phantom.Coroutines uses [CMake](https://cmake.org/) (3.30+) with [vcpkg](https://vcpkg.io/) for dependency management and [Ninja](https://ninja-build.org/) as the build generator. + +## Prerequisites + +- CMake 3.30 or later +- Ninja +- vcpkg (set `VCPKG_ROOT` environment variable to your vcpkg installation) +- A supported compiler: + - **Windows:** MSVC (Visual Studio 2026 or later) or Clang + - **Linux:** Clang 21 + +## Configure + +Use a CMake preset to configure. For development, prefer a **debug** preset: + +``` +cmake --preset msvc-windows-x64-debug +``` + +Available presets (defined in `CMakePresets.json`): + +| Preset | Platform | Compiler | Config | +|---|---|---|---| +| `msvc-windows-x64-debug` | Windows | MSVC | Debug | +| `msvc-windows-x64-release` | Windows | MSVC | RelWithDebInfo | +| `clang-windows-x64-debug` | Windows | Clang | Debug | +| `clang-windows-x64-release` | Windows | Clang | RelWithDebInfo | +| `clang-linux-x64-debug` | Linux | Clang 21 | Debug | +| `clang-linux-x64-release` | Linux | Clang 21 | RelWithDebInfo | + +> **Note:** The release configuration is `RelWithDebInfo` (not `Release`). It enables link-time code generation (`/GL`/`/LTCG`) on MSVC. + +> **Note:** Debug builds on MSVC enable AddressSanitizer (`/fsanitize=address`). + +### Local overrides + +`CMakeUserPresets.json` provides `*-local` variants of the Clang presets that hard-code local compiler paths. Copy and adapt as needed for your machine. + +## Build + +``` +cmake --build --preset msvc-windows-x64-debug +``` + +Replace the preset name to match your configured preset. + +## Run Tests + +``` +ctest --preset msvc-windows-x64-debug-unit +``` + +Test presets mirror the configure presets. Tests take roughly 5 seconds to run. + +## Visual Studio + +Open the repository folder in Visual Studio. It will detect `CMakePresets.json` automatically. Select a preset from the configuration drop-down and build/run tests from the IDE. + +## Building with VS2026 PowerShell + +From a **Visual Studio 2026 Developer PowerShell** session, cmake, ninja, cl, and the Windows SDK are all on `PATH` and the MSVC environment variables (`INCLUDE`, `LIB`) are set correctly. Use the VS Developer PowerShell shortcut, or load it yourself: + +```powershell +Import-Module "C:\Program Files\Microsoft Visual Studio\18\Enterprise\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" +Enter-VsDevShell -VsInstallPath "C:\Program Files\Microsoft Visual Studio\18\Enterprise" -Arch amd64 -SkipAutomaticLocation +``` + +Then configure (only needed once, or after clearing the cache): + +```powershell +cmake --preset msvc-windows-x64-debug +``` + +Build the C++ modules test target (iterative development): + +```powershell +cmake --build --preset msvc-windows-x64-debug --target Phantom.Coroutines.Modules.Test +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.Test\Phantom.Coroutines.Modules.Test.exe +``` + +Full build and test suite (run when done with a task): + +```powershell +cmake --build --preset msvc-windows-x64-debug +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.Test\Phantom.Coroutines.Test.exe +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.Test\Phantom.Coroutines.Modules.Test.exe +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.Test\Phantom.Coroutines.SingleModule.Test.exe +.\out\build\msvc-windows-x64-debug\Phantom.Coroutines.cppcoro.Test\Phantom.Coroutines.cppcoro.Test.exe +``` + +> **Note:** Use the test executables directly rather than `ctest`, as ctest spawns each test case as a separate process which is slow with AddressSanitizer enabled. + +> **Note:** If configure fails with `Could NOT find GTest`, delete `out\build\msvc-windows-x64-debug\CMakeCache.txt` and re-run configure. This can happen when the build directory was previously configured with a different toolchain. + +## C++ Modules + +The `Phantom.Coroutines.Modules` target builds C++ module support. Module linking is disabled for Clang builds (`DISABLE_LINK_MODULES=ON`) and can be disabled entirely with `-DDISABLE_COMPILE_MODULES=ON`. diff --git a/CMakePresets.json b/CMakePresets.json index 573ead5..be18f7c 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -123,6 +123,32 @@ } } ], + "buildPresets": [ + { + "name": "msvc-windows-x64-debug", + "configurePreset": "msvc-windows-x64-debug" + }, + { + "name": "msvc-windows-x64-release", + "configurePreset": "msvc-windows-x64-release" + }, + { + "name": "clang-windows-x64-debug", + "configurePreset": "clang-windows-x64-debug" + }, + { + "name": "clang-windows-x64-release", + "configurePreset": "clang-windows-x64-release" + }, + { + "name": "clang-linux-x64-debug", + "configurePreset": "clang-linux-x64-debug" + }, + { + "name": "clang-linux-x64-release", + "configurePreset": "clang-linux-x64-release" + } + ], "testPresets": [ { "name": "msvc-windows-x64-debug-unit", @@ -132,6 +158,14 @@ "name": "msvc-windows-x64-release-unit", "configurePreset": "msvc-windows-x64-release" }, + { + "name": "clang-windows-x64-debug-unit", + "configurePreset": "clang-windows-x64-debug" + }, + { + "name": "clang-windows-x64-release-unit", + "configurePreset": "clang-windows-x64-release" + }, { "name": "clang-linux-x64-debug-unit", "configurePreset": "clang-linux-x64-debug" @@ -141,4 +175,4 @@ "configurePreset": "clang-linux-x64-release" } ] -} \ No newline at end of file +} diff --git a/Documentation/tracing.md b/Documentation/tracing.md new file mode 100644 index 0000000..862c31c --- /dev/null +++ b/Documentation/tracing.md @@ -0,0 +1,244 @@ +# Phantom.Coroutines Tracing + +The tracing system allows coroutine lifecycle events to be observed by attaching a *trace sink* to a +`traced_promise`. The traced promise emits strongly-typed events before and after every coroutine +lifecycle operation (initial/final suspend, `co_await`, `co_yield`, `co_return`, etc.) and delivers +them to the trace sink. + +All tracing types live in `Phantom::Coroutines::tracing`. + +--- + +## Trace Sinks + +A *trace sink* is any callable object. The `is_trace_sink` concept accepts every type: + +```cpp +template +concept is_trace_sink = true; +``` + +The trace sink is called with two distinct kinds of arguments: + +| Argument kind | Purpose | +|---|---| +| `const events::event<...>&` | A lifecycle event has occurred — record or act on it. | +| `const events::should_trace_return_value&` | A query asking whether to capture the return value for the next result event. | +| `const events::should_capture_promise_creation_arguments&` | A query asking whether to capture promise creation arguments. | + +The two query types are described in detail below. + +--- + +## Events + +Every event is an instance of `events::event`. The three +members of interest are: + +| Member | Type | Description | +|---|---|---| +| `SourceLocation` | `std::source_location` | Where the `co_await`/`co_yield`/etc. appears in source. | +| `EventType` | `events::event_type