From 75afb3cb5ac24c9c7edb82d10120fa0715d0fd22 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Fri, 21 Aug 2026 11:29:56 -0600 Subject: [PATCH] docs: compile every reference example and inject it into the reference The `@code` examples in the public headers were never compiled by anything, so broken examples shipped to readers: of the 99 examples MrDocs publishes, 33 compiled. The rest referenced undeclared identifiers, elided code with `...`, or were fragments that could not build anywhere. Each example now lives as a tagged region in test/doc/reference/, in a file named after the symbol that documents it, and is compiled by boost_capy_doc_tests with the same warnings-as-errors posture as the page snippets. A Lua extension under doc/addons/extensions/ injects those regions into the MrDocs corpus at doc-build time, so the reference shows code the build has already checked. Compilation and rendering are independent: CI compiles the files whether or not the docs build, the docs build injects them whether or not they compile, and MrDocs stays a dependency of the docs workflow alone. A `@par !example ` marker in the docstring records where each example belongs and which region it wants. The transform replaces the marker with that region rather than rendering it, so nothing is added to the page and each example keeps its place: under a descriptive title, under an `@par Example` heading, or inline in the prose introducing it. Naming the region lets overloads and duplicated records share one file. Beyond compilation, the when_all and when_any examples fix documented undefined behaviour: they ran concurrent read_some calls on a single stream, and now fan out across separate streams. MrDocs loads extensions only from `/share/mrdocs/addons/extensions`, and its `addons-supplemental` config key is inert, so doc/build_antora.sh installs the extension into a MrDocs, exports MRDOCS_ROOT, and publishes it to GITHUB_ENV for later steps. Every caller therefore gets it: this repository's docs workflow, the C++ Alliance doc build, and a plain local run. The docs workflow checks the rendered HTML for an example that exists only in a snippet file, because a MrDocs without the extension renders the reference with no examples while still reporting success. Five `@code` blocks stay in their headers, on symbols MrDocs does not publish. Refs: cppalliance/capy#380 --- .github/workflows/docs.yml | 31 +- doc/addons/extensions/reference-snippets.lua | 245 +++++++++++++ doc/build_antora.sh | 51 +++ doc/local-playbook.yml | 11 + doc/mrdocs.yml | 18 +- include/boost/capy/buffers.hpp | 6 +- include/boost/capy/buffers/buffer_param.hpp | 47 +-- include/boost/capy/buffers/buffer_slice.hpp | 6 +- .../boost/capy/buffers/consuming_buffers.hpp | 13 +- .../boost/capy/concept/buffer_archetype.hpp | 20 +- include/boost/capy/concept/decomposes_to.hpp | 21 +- .../boost/capy/concept/execution_context.hpp | 20 +- include/boost/capy/concept/executor.hpp | 28 +- include/boost/capy/concept/io_awaitable.hpp | 42 +-- include/boost/capy/concept/io_runnable.hpp | 18 +- include/boost/capy/concept/read_stream.hpp | 23 +- include/boost/capy/concept/stream.hpp | 23 +- include/boost/capy/concept/write_stream.hpp | 23 +- include/boost/capy/cond.hpp | 17 +- include/boost/capy/ex/any_executor.hpp | 10 +- include/boost/capy/ex/async_event.hpp | 15 +- include/boost/capy/ex/async_mutex.hpp | 20 +- include/boost/capy/ex/async_waker.hpp | 17 +- include/boost/capy/ex/execution_context.hpp | 41 +-- include/boost/capy/ex/executor_ref.hpp | 10 +- include/boost/capy/ex/frame_alloc_mixin.hpp | 15 +- include/boost/capy/ex/immediate.hpp | 59 +-- .../capy/ex/io_awaitable_promise_base.hpp | 54 +-- .../capy/ex/recycling_memory_resource.hpp | 6 +- include/boost/capy/ex/run.hpp | 11 +- include/boost/capy/ex/run_async.hpp | 52 +-- include/boost/capy/ex/strand.hpp | 14 +- include/boost/capy/ex/this_coro.hpp | 49 +-- include/boost/capy/ex/thread_pool.hpp | 9 +- include/boost/capy/ex/work_guard.hpp | 13 +- include/boost/capy/io/any_read_stream.hpp | 14 +- include/boost/capy/io/any_stream.hpp | 27 +- include/boost/capy/io/any_write_stream.hpp | 14 +- include/boost/capy/io_result.hpp | 13 +- include/boost/capy/io_task.hpp | 15 +- include/boost/capy/read.hpp | 15 +- include/boost/capy/read_at_least.hpp | 15 +- include/boost/capy/task.hpp | 15 +- include/boost/capy/test/buffer_to_string.hpp | 18 +- include/boost/capy/test/bufgrind.hpp | 42 +-- include/boost/capy/test/fuse.hpp | 340 ++---------------- include/boost/capy/test/read_stream.hpp | 17 +- include/boost/capy/test/run_blocking.hpp | 22 +- include/boost/capy/test/stream.hpp | 25 +- include/boost/capy/test/write_stream.hpp | 19 +- include/boost/capy/when_all.hpp | 22 +- include/boost/capy/when_any.hpp | 28 +- include/boost/capy/write.hpp | 10 +- include/boost/capy/write_at_least.hpp | 11 +- test/doc/CMakeLists.txt | 8 +- test/doc/Jamfile | 4 +- .../reference/ExecutionContext.concept.cpp | 82 +++++ test/doc/reference/Executor.concept.cpp | 115 ++++++ test/doc/reference/IoAwaitable.concept.cpp | 109 ++++++ test/doc/reference/IoRunnable.concept.cpp | 77 ++++ test/doc/reference/README.md | 101 ++++++ test/doc/reference/ReadStream.concept.cpp | 83 +++++ test/doc/reference/Stream.concept.cpp | 84 +++++ test/doc/reference/WriteStream.concept.cpp | 83 +++++ test/doc/reference/any_executor.record.cpp | 78 ++++ test/doc/reference/any_read_stream.record.cpp | 87 +++++ test/doc/reference/any_stream.record.cpp | 106 ++++++ .../doc/reference/any_write_stream.record.cpp | 87 +++++ test/doc/reference/async_event.record.cpp | 77 ++++ test/doc/reference/async_mutex.record.cpp | 81 +++++ test/doc/reference/async_waker.record.cpp | 82 +++++ .../awaitable_decomposes_to.concept.cpp | 74 ++++ test/doc/reference/buffer_param.record.cpp | 107 ++++++ test/doc/reference/buffer_size.function.cpp | 69 ++++ test/doc/reference/buffer_slice.function.cpp | 69 ++++ test/doc/reference/cond.enum.cpp | 79 ++++ .../const_buffer_archetype_.record.cpp | 69 ++++ .../reference/consuming_buffers.record.cpp | 76 ++++ test/doc/reference/decomposes_to.concept.cpp | 67 ++++ .../reference/execution_context.record.cpp | 92 +++++ .../execution_context__service.record.cpp | 73 ++++ test/doc/reference/executor_ref.record.cpp | 75 ++++ .../reference/frame_alloc_mixin.record.cpp | 74 ++++ test/doc/reference/immediate.record.cpp | 94 +++++ .../io_awaitable_promise_base.record.cpp | 187 ++++++++++ test/doc/reference/io_result.typedef.cpp | 80 +++++ test/doc/reference/io_task.typedef.cpp | 74 ++++ .../mutable_buffer_archetype_.record.cpp | 69 ++++ test/doc/reference/operator_.function.cpp | 69 ++++ test/doc/reference/read.function.cpp | 74 ++++ test/doc/reference/read_at_least.function.cpp | 74 ++++ test/doc/reference/ready.function.cpp | 104 ++++++ .../recycling_memory_resource.record.cpp | 70 ++++ test/doc/reference/run.function.cpp | 80 +++++ test/doc/reference/run_async.function.cpp | 137 +++++++ .../reference/run_async_wrapper.record.cpp | 91 +++++ test/doc/reference/strand.record.cpp | 76 ++++ test/doc/reference/task.record.cpp | 75 ++++ .../test__buffer_to_string.function.cpp | 87 +++++ test/doc/reference/test__bufgrind.record.cpp | 123 +++++++ test/doc/reference/test__fuse.record.cpp | 210 +++++++++++ .../reference/test__fuse__armed.function.cpp | 144 ++++++++ .../reference/test__fuse__fail.function.cpp | 121 +++++++ .../reference/test__fuse__fuse.function.cpp | 107 ++++++ .../reference/test__fuse__inert.function.cpp | 114 ++++++ .../test__fuse__maybe_fail.function.cpp | 86 +++++ .../test__fuse__operator_.function.cpp | 89 +++++ .../reference/test__fuse__result.record.cpp | 95 +++++ .../reference/test__read_stream.record.cpp | 89 +++++ .../reference/test__run_blocking.function.cpp | 116 ++++++ test/doc/reference/test__stream.record.cpp | 92 +++++ .../reference/test__write_stream.record.cpp | 86 +++++ test/doc/reference/this_coro.namespace.cpp | 70 ++++ .../this_coro__environment.variable.cpp | 70 ++++ .../this_coro__executor.variable.cpp | 67 ++++ .../this_coro__frame_allocator.variable.cpp | 68 ++++ .../this_coro__stop_token.variable.cpp | 69 ++++ test/doc/reference/thread_pool.record.cpp | 73 ++++ test/doc/reference/when_all.function.cpp | 95 +++++ test/doc/reference/when_any.function.cpp | 108 ++++++ test/doc/reference/work_guard.record.cpp | 55 +++ test/doc/reference/write.function.cpp | 71 ++++ .../doc/reference/write_at_least.function.cpp | 72 ++++ 123 files changed, 6510 insertions(+), 1229 deletions(-) create mode 100644 doc/addons/extensions/reference-snippets.lua create mode 100644 test/doc/reference/ExecutionContext.concept.cpp create mode 100644 test/doc/reference/Executor.concept.cpp create mode 100644 test/doc/reference/IoAwaitable.concept.cpp create mode 100644 test/doc/reference/IoRunnable.concept.cpp create mode 100644 test/doc/reference/README.md create mode 100644 test/doc/reference/ReadStream.concept.cpp create mode 100644 test/doc/reference/Stream.concept.cpp create mode 100644 test/doc/reference/WriteStream.concept.cpp create mode 100644 test/doc/reference/any_executor.record.cpp create mode 100644 test/doc/reference/any_read_stream.record.cpp create mode 100644 test/doc/reference/any_stream.record.cpp create mode 100644 test/doc/reference/any_write_stream.record.cpp create mode 100644 test/doc/reference/async_event.record.cpp create mode 100644 test/doc/reference/async_mutex.record.cpp create mode 100644 test/doc/reference/async_waker.record.cpp create mode 100644 test/doc/reference/awaitable_decomposes_to.concept.cpp create mode 100644 test/doc/reference/buffer_param.record.cpp create mode 100644 test/doc/reference/buffer_size.function.cpp create mode 100644 test/doc/reference/buffer_slice.function.cpp create mode 100644 test/doc/reference/cond.enum.cpp create mode 100644 test/doc/reference/const_buffer_archetype_.record.cpp create mode 100644 test/doc/reference/consuming_buffers.record.cpp create mode 100644 test/doc/reference/decomposes_to.concept.cpp create mode 100644 test/doc/reference/execution_context.record.cpp create mode 100644 test/doc/reference/execution_context__service.record.cpp create mode 100644 test/doc/reference/executor_ref.record.cpp create mode 100644 test/doc/reference/frame_alloc_mixin.record.cpp create mode 100644 test/doc/reference/immediate.record.cpp create mode 100644 test/doc/reference/io_awaitable_promise_base.record.cpp create mode 100644 test/doc/reference/io_result.typedef.cpp create mode 100644 test/doc/reference/io_task.typedef.cpp create mode 100644 test/doc/reference/mutable_buffer_archetype_.record.cpp create mode 100644 test/doc/reference/operator_.function.cpp create mode 100644 test/doc/reference/read.function.cpp create mode 100644 test/doc/reference/read_at_least.function.cpp create mode 100644 test/doc/reference/ready.function.cpp create mode 100644 test/doc/reference/recycling_memory_resource.record.cpp create mode 100644 test/doc/reference/run.function.cpp create mode 100644 test/doc/reference/run_async.function.cpp create mode 100644 test/doc/reference/run_async_wrapper.record.cpp create mode 100644 test/doc/reference/strand.record.cpp create mode 100644 test/doc/reference/task.record.cpp create mode 100644 test/doc/reference/test__buffer_to_string.function.cpp create mode 100644 test/doc/reference/test__bufgrind.record.cpp create mode 100644 test/doc/reference/test__fuse.record.cpp create mode 100644 test/doc/reference/test__fuse__armed.function.cpp create mode 100644 test/doc/reference/test__fuse__fail.function.cpp create mode 100644 test/doc/reference/test__fuse__fuse.function.cpp create mode 100644 test/doc/reference/test__fuse__inert.function.cpp create mode 100644 test/doc/reference/test__fuse__maybe_fail.function.cpp create mode 100644 test/doc/reference/test__fuse__operator_.function.cpp create mode 100644 test/doc/reference/test__fuse__result.record.cpp create mode 100644 test/doc/reference/test__read_stream.record.cpp create mode 100644 test/doc/reference/test__run_blocking.function.cpp create mode 100644 test/doc/reference/test__stream.record.cpp create mode 100644 test/doc/reference/test__write_stream.record.cpp create mode 100644 test/doc/reference/this_coro.namespace.cpp create mode 100644 test/doc/reference/this_coro__environment.variable.cpp create mode 100644 test/doc/reference/this_coro__executor.variable.cpp create mode 100644 test/doc/reference/this_coro__frame_allocator.variable.cpp create mode 100644 test/doc/reference/this_coro__stop_token.variable.cpp create mode 100644 test/doc/reference/thread_pool.record.cpp create mode 100644 test/doc/reference/when_all.function.cpp create mode 100644 test/doc/reference/when_any.function.cpp create mode 100644 test/doc/reference/work_guard.record.cpp create mode 100644 test/doc/reference/write.function.cpp create mode 100644 test/doc/reference/write_at_least.function.cpp diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 4a3a4578a..df6a5f1a8 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -138,7 +138,12 @@ jobs: cd boost-root/libs/capy cd doc - bash ./build_antora.sh + # Tee'd purely to keep the build log readable in the step output; + # Antora exits zero even on failure, which is why the checks below + # exist. The injection gate reads a report file, not this log -- the + # reference extension does not pass MrDocs' stdout through. + set -o pipefail + bash ./build_antora.sh 2>&1 | tee "$RUNNER_TEMP/antora.log" # Antora returns zero even if it fails, so we check if the site directory exists if [ ! -d "build/site" ]; then @@ -146,6 +151,30 @@ jobs: exit 1 fi + + # BLOCKING, but deliberately not a count. A MrDocs without the + # extension installed ignores the script entirely and renders the + # reference with no examples while still reporting success, so something + # has to notice. Checking that one known example reached the HTML catches + # that without asking anyone to maintain a number: this example exists + # only in test/doc/reference/work_guard.record.cpp, never in a header. + - name: Doc-quality - reference examples were injected (BLOCKING) + run: | + set -euo pipefail + site=boost-root/libs/capy/doc/build/site + if ! grep -rqF keep_alive_while_setting_up "$site/capy/reference"; then + echo "No injected example found in the rendered reference." >&2 + echo "The reference-snippets transform did not run, or its output" >&2 + echo "did not reach the HTML. doc/build_antora.sh installs the" >&2 + echo "extension into a MrDocs and exports MRDOCS_ROOT; check that it" >&2 + echo "did, and that the Antora reference extension accepted it -- it" >&2 + echo "logs 'Using local MrDocs' at debug level, and setting a" >&2 + echo "'version' in doc/local-playbook.yml makes it reject a local" >&2 + echo "install and silently download its own instead." >&2 + exit 1 + fi + echo "the rendered reference carries its injected examples" + - name: Create Antora Docs Artifact uses: actions/upload-artifact@v4 with: diff --git a/doc/addons/extensions/reference-snippets.lua b/doc/addons/extensions/reference-snippets.lua new file mode 100644 index 000000000..6cd2f9edd --- /dev/null +++ b/doc/addons/extensions/reference-snippets.lua @@ -0,0 +1,245 @@ +-- Inject compiled reference examples into the MrDocs corpus. +-- +-- Examples live as tagged regions in checked-in .cpp files under +-- test/doc/reference/, compiled by boost_capy_doc_tests like every other +-- snippet. This transform reads those regions and injects them into the +-- matching symbol's documentation, so the reference renders an example the +-- normal build has already compiled. Compilation and injection stay +-- independent: CI compiles the files whether or not the docs build, and the +-- docs build injects them whether or not they compile. +-- +-- The file name IS the mapping: a symbol's examples live in +-- +-- test/doc/reference/..cpp +-- +-- where is the qualified name with `boost::capy::` stripped and `::` +-- replaced by `__`. So boost::capy::work_guard (a record) reads +-- `work_guard.record.cpp`. The kind is part of the name because a name alone +-- is ambiguous: `work_guard` also matches three constructors and their +-- overload set. Where even that is ambiguous, the symbol's unique MrDocs +-- anchor is tried first: `..cpp`. +-- +-- Discovery works symbol-first, opening a predicted path, because MrDocs' Lua +-- sandbox blocks io.popen and Lua has no directory listing. +-- +-- A file may hold several tagged regions; they are injected in file order. +-- Each is placed directly after the "Example" heading that `@par Example` +-- produces, so the rendered order matches what the docstring declares. +-- Without such a heading the block is appended. + +local SOURCE_DEFAULT = "test/doc/reference" +local STRIP_PREFIX = "boost::capy::" +-- Heading title that marks a position without rendering; see the anchor loop. +local SENTINEL = "!example" + +-- Scalar fields copied when rebuilding a block. `sym.doc.document` accepts only +-- plain tables and rejects the userdata proxies it hands out, so appending to a +-- symbol's documentation means deep-copying every existing block first. A field +-- missing from this list is dropped silently, which is why the injection is +-- verified against a no-transform baseline rather than trusted. +-- `level` is deliberately absent: MrDocs' generic setter refuses to write it +-- ("field 'level' has a type the generic setter cannot yet write"), as an +-- integer or a float. Every heading in this corpus is level 1, which is what +-- `@par` produces and what the templates default to, so omitting it round-trips +-- unchanged -- verified by diffing the rendered corpus against a no-transform +-- baseline. A corpus using deeper headings would need this fixed upstream. +local SCALARS = { + "kind", "literal", "lang", "title", "name", "text", + "href", "anchor", "id", "style", "admonition", "admonish", "symbol", "href_text", +} + +-- Child blocks hang off more than one field name: a paragraph uses `children`, +-- a list uses `items` (of `listItem`, which in turn uses `blocks`), and an +-- admonition uses `blocks`. Recursing only `children` silently drops list items +-- and note bodies -- caught by the baseline diff, not by any error. +local CONTAINERS = { "children", "items", "blocks" } + +local function fail(msg) + error("[reference-snippets] " .. msg, 0) +end + +local function copy(node) + local out = {} + for _, f in ipairs(SCALARS) do + local ok, v = pcall(function() return node[f] end) + if ok and v ~= nil and type(v) ~= "userdata" and type(v) ~= "table" then + -- Numbers read back as Lua floats (a heading's level is 1.0), and the + -- generic setter rejects a float where the DOM holds an integer. + if type(v) == "number" and math.tointeger(v) then v = math.tointeger(v) end + out[f] = v + end + end + for _, field in ipairs(CONTAINERS) do + local ok, kids = pcall(function() return node[field] end) + if ok and kids ~= nil then + local c = {} + for _, k in ipairs(kids) do c[#c + 1] = copy(k) end + if #c > 0 then out[field] = c end + end + end + return out +end + +-- The first literal found anywhere under a node, used to identify a heading. +local function text_of(node) + local ok, lit = pcall(function() return node.literal end) + if ok and type(lit) == "string" and lit ~= "" then return lit end + local ok2, kids = pcall(function() return node.children end) + if ok2 and kids then + for _, k in ipairs(kids) do + local t = text_of(k) + if t then return t end + end + end + return nil +end + +local function qualified_name(ctx, sym) + local parts, cur = {}, sym + while cur and cur.name ~= nil do + table.insert(parts, 1, cur.name) + cur = cur.parent and ctx.corpus.get(cur.parent) or nil + end + return table.concat(parts, "::") +end + +local function slug(qname) + local s = qname + if s:sub(1, #STRIP_PREFIX) == STRIP_PREFIX then s = s:sub(#STRIP_PREFIX + 1) end + s = s:gsub("::", "__") + -- Anything not an identifier character collapses to `_`, so a call operator + -- (whose qualified name is literally `operator()`) yields a usable file name. + return (s:gsub("[^%w_]+", "_")) +end + +local function dedent(lines) + local margin + for _, l in ipairs(lines) do + if l:match("%S") then + local n = #(l:match("^[ \t]*")) + if margin == nil or n < margin then margin = n end + end + end + local out = {} + for _, l in ipairs(lines) do out[#out + 1] = l:sub((margin or 0) + 1) end + while #out > 0 and not out[1]:match("%S") do table.remove(out, 1) end + while #out > 0 and not out[#out]:match("%S") do table.remove(out) end + return table.concat(out, "\n") +end + +-- Tagged regions in a file, in order. Returns nil when the file does not exist. +local function read_regions(path) + local f = io.open(path, "r") + if not f then return nil end + local lines = {} + for l in f:lines() do lines[#lines + 1] = l end + f:close() + + local out, open_tag, body = {}, nil, nil + for i, l in ipairs(lines) do + local t = l:match("^%s*//%s*tag::([%w_%-]+)%[%]%s*$") + local e = l:match("^%s*//%s*end::([%w_%-]+)%[%]%s*$") + if t then + if open_tag then fail(path .. ":" .. i .. ": tag '" .. t .. "' opens inside '" .. open_tag .. "'") end + open_tag, body = t, {} + elseif e then + if open_tag ~= e then + fail(path .. ":" .. i .. ": end::" .. e .. "[] does not close the open tag") + end + out[#out + 1] = { tag = open_tag, code = dedent(body) } + open_tag, body = nil, nil + elseif open_tag then + body[#body + 1] = l + end + end + if open_tag then fail(path .. ": tag '" .. open_tag .. "' is never closed") end + if #out == 0 then fail(path .. ": file exists but declares no // tag::name[] region") end + return out +end + +mrdocs.register_transform("reference-snippets", function(ctx) + local root = (ctx.params and ctx.params.source) or SOURCE_DEFAULT + local injected, files, missing = 0, 0, {} + + for _, sym in ipairs(ctx.corpus.symbols) do + if sym.name ~= nil and sym.doc then + local doc = sym.doc.document or {} + + -- Anchors are the bare `@par Example` headings, in order, each + -- taking exactly one region. A titled heading such as + -- `@par Mutable Buffer Example` is a section label, not a position: + -- the migration put a bare `@par Example` immediately before every + -- block, so the bare ones mark where the code actually was. Pinning + -- every region to the first anchor would stack them under one title + -- and leave the other sections empty. + -- Each `@par !example ` marker names the region it wants. The + -- marker is consumed rather than rendered, so the example lands where + -- the docstring puts it, and naming the region keeps overloads that + -- share a file independent of the order MrDocs visits them in -- an + -- order that differs between corpora, and that silently swapped two + -- `armed` examples on the published site. + local seq, anchors = {}, {} + for _, b in ipairs(doc) do seq[#seq + 1] = b end + for i, b in ipairs(seq) do + if b.kind == "heading" then + local t = text_of(b) + local tag = t and t:match("^" .. SENTINEL .. "%s+(%S+)$") + if tag then anchors[#anchors + 1] = { at = i, tag = tag } end + end + end + local at = anchors[1] and anchors[1].at or nil + + if at then + local base = root .. "/" .. slug(qualified_name(ctx, sym)) + local path = base .. "." .. tostring(sym.anchor) .. ".cpp" + local regions = read_regions(path) + if not regions then + path = base .. "." .. tostring(sym.kind) .. ".cpp" + regions = read_regions(path) + end + if not regions then + -- Fail-open guard: the docstring promises an example and no + -- file provides one, so the reference would render an empty + -- "Example" section. + missing[#missing + 1] = qualified_name(ctx, sym) .. + " (expected " .. base .. "." .. tostring(sym.kind) .. ".cpp)" + else + files = files + 1 + local blocks + local by_tag = {} + for _, r in ipairs(regions) do by_tag[r.tag] = r end + local picked = {} + for k, a in ipairs(anchors) do + local r = by_tag[a.tag] + if not r then + fail(string.format("%s has no region tagged '%s', named by %s", + path, a.tag, qualified_name(ctx, sym))) + end + picked[k] = r + end + + -- Rebuild, replacing each marker with the region it names. + local nth, out = 0, {} + for i, b in ipairs(seq) do + if anchors[nth + 1] and anchors[nth + 1].at == i then + nth = nth + 1 + out[#out + 1] = { kind = "code", literal = picked[nth].code } + injected = injected + 1 + else + out[#out + 1] = copy(b) + end + end + blocks = out + sym.doc.document = blocks + end + end + end + end + + if #missing > 0 then + fail("these symbols document an @par Example with no snippet file:\n " .. + table.concat(missing, "\n ")) + end + print(string.format("[reference-snippets] injected %d example(s) from %d file(s) under %s", + injected, files, root)) +end) diff --git a/doc/build_antora.sh b/doc/build_antora.sh index 14251113c..277e485a0 100755 --- a/doc/build_antora.sh +++ b/doc/build_antora.sh @@ -21,6 +21,57 @@ echo "Building documentation with Antora..." echo "Installing npm dependencies..." npm ci +# The reference examples are injected by addons/extensions/reference-snippets.lua. +# MrDocs loads extensions only from /share/mrdocs/addons/extensions, and +# its `addons-supplemental` config key is recognised but has no effect, so the +# extension has to be placed inside a MrDocs install. Doing it here rather than in +# CI means every caller gets it: this repository's docs workflow, the C++ Alliance +# doc build, and a plain local run. Without it the reference builds with no +# examples at all and reports success. +# +# develop-release rather than a tagged release: MrDocs' extension API postdates +# v0.8.0. The tag is rolling, so this URL always names the current develop build +# and needs no API call or token. +if [ -z "${MRDOCS_ROOT:-}" ]; then + case "$(uname -s)" in + Linux) mrdocs_asset="MrDocs-develop-Linux.tar.gz" ;; + Darwin) mrdocs_asset="MrDocs-develop-Darwin.tar.gz" ;; + *) echo "No MrDocs build for $(uname -s); set MRDOCS_ROOT to an install." >&2 + exit 1 ;; + esac + mrdocs_dir="$(pwd)/build/mrdocs" + if ! find "$mrdocs_dir" -type f -name mrdocs -perm -u+x 2>/dev/null | grep -q .; then + echo "Fetching MrDocs ($mrdocs_asset)" + mkdir -p "$mrdocs_dir" + curl -fsSL --retry 3 --retry-delay 2 \ + "https://github.com/cppalliance/mrdocs/releases/download/develop-release/$mrdocs_asset" \ + -o "$mrdocs_dir/mrdocs.tar.gz" + tar -xzf "$mrdocs_dir/mrdocs.tar.gz" -C "$mrdocs_dir" + rm -f "$mrdocs_dir/mrdocs.tar.gz" + fi + mrdocs_bin=$(find "$mrdocs_dir" -type f -name mrdocs -perm -u+x | head -n 1) + if [ -z "$mrdocs_bin" ]; then + echo "MrDocs binary not found under $mrdocs_dir" >&2 + exit 1 + fi + MRDOCS_ROOT=$(dirname "$(dirname "$mrdocs_bin")") + export MRDOCS_ROOT +fi + +# Install the extension into whichever MrDocs will be used, including one the +# caller supplied. +mkdir -p "$MRDOCS_ROOT/share/mrdocs/addons/extensions" +cp addons/extensions/*.lua "$MRDOCS_ROOT/share/mrdocs/addons/extensions/" +echo "MrDocs: $MRDOCS_ROOT (reference-snippets extension installed)" + +# Later CI steps run in their own shells, so the export above does not reach +# them. lint/mrdocs-warnings.mjs looks for MRDOCS_ROOT; it used to find MrDocs in +# the reference-collector cache, which is no longer populated now that the +# collector is handed an install instead of downloading one. +if [ -n "${GITHUB_ENV:-}" ]; then + echo "MRDOCS_ROOT=$MRDOCS_ROOT" >> "$GITHUB_ENV" +fi + echo "Building docs in custom dir..." PATH="$(pwd)/node_modules/.bin:${PATH}" export PATH diff --git a/doc/local-playbook.yml b/doc/local-playbook.yml index 76ff7ec6d..bd2bee089 100644 --- a/doc/local-playbook.yml +++ b/doc/local-playbook.yml @@ -30,6 +30,17 @@ antora: using-namespaces: - 'boost::' - require: '@cppalliance/antora-cpp-reference-extension' + # Deliberately NO `version` key. The reference examples are injected by + # doc/addons/extensions/reference-snippets.lua, which needs MrDocs' + # extension API -- not in any tagged release (corpus transforms shipped in + # cppalliance/mrdocs#1196, script generators in #1218, both after v0.8.0). + # The docs workflow therefore installs a develop build with that extension + # copied in and points here via MRDOCS_ROOT, which is the real pin. + # + # Setting `version` DEFEATS that: a local install reports its version as + # `0.8.0+`, which can never satisfy "develop", so the extension + # rejects MRDOCS_ROOT and downloads its own copy -- one without the + # extension, which then renders the reference with no examples at all. dependencies: - name: 'boost' repo: 'https://github.com/boostorg/boost.git' diff --git a/doc/mrdocs.yml b/doc/mrdocs.yml index cc3020896..ef518c8ca 100644 --- a/doc/mrdocs.yml +++ b/doc/mrdocs.yml @@ -35,11 +35,14 @@ exclude-symbols: implementation-defined: - 'boost::capy::detail' - 'boost::capy::*::detail' -inaccessible-members: never -inaccessible-bases: never +# `inaccessible-members`/`inaccessible-bases` are gone on develop, which is the +# channel the docs are pinned to (see doc/local-playbook.yml). Their job is done +# by the extract-private* defaults: verified that state_, has_ep_, dummy_, arr_ +# and ep_ appear nowhere in the generated corpus without them. -# Generator -generate: adoc +# Generator. Spelled `generator` since develop; the Antora reference extension +# passes --generator=adoc explicitly in any case. +generator: adoc base-url: https://www.github.com/cppalliance/capy/blob/develop/ # Style @@ -66,6 +69,13 @@ warn-if-doc-error: true # include/boost/capy/ex/run.hpp -- "run: Documented parameter 'alloc' # does not exist" +# Reference examples are injected by addons/extensions/reference-snippets.lua. +# MrDocs loads extensions from /share/mrdocs/addons/extensions, so the +# doc build installs it there (see .github/workflows/docs.yml). Setting +# `addons-supplemental` here does NOT work: the key is recognised but only the +# command-line flag reaches extension discovery, and the Antora extension does +# not expose one. + # Automation auto-function-metadata: false diff --git a/include/boost/capy/buffers.hpp b/include/boost/capy/buffers.hpp index 36f999734..8c5385b8c 100644 --- a/include/boost/capy/buffers.hpp +++ b/include/boost/capy/buffers.hpp @@ -380,10 +380,8 @@ constexpr struct @return The sum of the sizes of all buffers in `bs`. @par Example - @code - std::array bufs = { ... }; - std::size_t total = buffer_size( bufs ); // sum of both sizes - @endcode + @par !example example + */ template constexpr std::size_t operator()( diff --git a/include/boost/capy/buffers/buffer_param.hpp b/include/boost/capy/buffers/buffer_param.hpp index ebe3ae812..2deefbf0b 100644 --- a/include/boost/capy/buffers/buffer_param.hpp +++ b/include/boost/capy/buffers/buffer_param.hpp @@ -50,10 +50,8 @@ namespace capy { When used in coroutine APIs, the outer template function MUST accept the buffer sequence parameter BY VALUE: - @code - task<> write(ConstBufferSequence auto buffers); // CORRECT - task<> write(ConstBufferSequence auto& buffers); // WRONG - dangling reference - @endcode + @par !example example_1 + Pass-by-value ensures the buffer sequence is copied into the coroutine frame and remains valid across suspension @@ -76,20 +74,8 @@ namespace capy { processing some bytes, call `consume()` to advance through the sequence. - @code - task<> send(ConstBufferSequence auto buffers) - { - buffer_param bp(buffers); - while(true) - { - auto bufs = bp.data(); - if(bufs.empty()) - break; - auto n = co_await do_something(bufs); - bp.consume(n); - } - } - @endcode + @par !example example_2 + @par Virtual Interface Pattern @@ -102,31 +88,8 @@ namespace capy { `write_impl`'s `span` parameter. Use @ref const_buffer_param to force `const_buffer` storage regardless of what `BS` is: - @code - class base - { - public: - template - task<> write(BS buffers) - { - const_buffer_param bp(buffers); - while(true) - { - auto bufs = bp.data(); - if(bufs.empty()) - break; - std::size_t n = 0; - co_await write_impl(bufs, n); - bp.consume(n); - } - } + @par !example example_3 - protected: - virtual task<> write_impl( - std::span buffers, - std::size_t& bytes_written) = 0; - }; - @endcode @tparam BS The buffer sequence type. Must satisfy either ConstBufferSequence or MutableBufferSequence. diff --git a/include/boost/capy/buffers/buffer_slice.hpp b/include/boost/capy/buffers/buffer_slice.hpp index 71e9f6d46..2ce1b0d10 100644 --- a/include/boost/capy/buffers/buffer_slice.hpp +++ b/include/boost/capy/buffers/buffer_slice.hpp @@ -60,10 +60,8 @@ using slice_type = std::conditional_t< concept as `seq` (mutable if `seq` is mutable). @par Example - @code - co_await write(sock, buffer_slice(bufs, 0, 16384)); // first 16 KB - auto rest = buffer_slice(bufs, n); // drop first n - @endcode + @par !example example + @see slice_type, consuming_buffers */ diff --git a/include/boost/capy/buffers/consuming_buffers.hpp b/include/boost/capy/buffers/consuming_buffers.hpp index 509bf85ca..00ebd5040 100644 --- a/include/boost/capy/buffers/consuming_buffers.hpp +++ b/include/boost/capy/buffers/consuming_buffers.hpp @@ -35,17 +35,8 @@ namespace capy { cursor is a local of a composed operation that took its buffers by value. @par Example - @code - consuming_buffers consuming(buffers); - std::size_t total = 0, want = buffer_size(buffers); - while (total < want) - { - auto [ec, n] = co_await stream.read_some(consuming.data()); - consuming.consume(n); - total += n; - if (ec && total < want) co_return {ec, total}; - } - @endcode + @par !example example + @see buffer_slice, slice_of */ diff --git a/include/boost/capy/concept/buffer_archetype.hpp b/include/boost/capy/concept/buffer_archetype.hpp index 7517f0426..e3b5f36cf 100644 --- a/include/boost/capy/concept/buffer_archetype.hpp +++ b/include/boost/capy/concept/buffer_archetype.hpp @@ -25,14 +25,8 @@ namespace capy { accepts any ConstBufferSequence. @par Example - @code - template - concept MyWritable = - requires(T& stream, const_buffer_archetype buffers) - { - stream.write(buffers); - }; - @endcode + @par !example example + */ struct const_buffer_archetype_ { @@ -90,14 +84,8 @@ using const_buffer_archetype = const_buffer_archetype_; accepts any MutableBufferSequence. @par Example - @code - template - concept MyReadable = - requires(T& stream, mutable_buffer_archetype buffers) - { - stream.read(buffers); - }; - @endcode + @par !example example + */ struct mutable_buffer_archetype_ { diff --git a/include/boost/capy/concept/decomposes_to.hpp b/include/boost/capy/concept/decomposes_to.hpp index b1e86398c..911b03638 100644 --- a/include/boost/capy/concept/decomposes_to.hpp +++ b/include/boost/capy/concept/decomposes_to.hpp @@ -135,12 +135,8 @@ using awaitable_return_t = decltype( @tparam Types The expected element types after decomposition. @par Example - @code - struct result { int a; double b; }; + @par !example example - static_assert(decomposes_to); - static_assert(decomposes_to, int, double>); - @endcode */ template concept decomposes_to = requires(T&& t) { @@ -161,19 +157,8 @@ concept decomposes_to = requires(T&& t) { @li The return type of `await_resume()` must decompose to `Types...` @par Example - @code - // Constrain a function to accept only awaitables that return - // a decomposable result of (error_code, size_t) - template - requires awaitable_decomposes_to - task process(A&& op) - { - auto [ec, n] = co_await std::forward(op); - if (ec) - co_return; - // process n bytes... - } - @endcode + @par !example example + */ template concept awaitable_decomposes_to = requires { diff --git a/include/boost/capy/concept/execution_context.hpp b/include/boost/capy/concept/execution_context.hpp index 4fe784cac..c075e86ec 100644 --- a/include/boost/capy/concept/execution_context.hpp +++ b/include/boost/capy/concept/execution_context.hpp @@ -48,28 +48,16 @@ namespace capy { @par Conforming Signatures - @code - class X : public execution_context - { - public: - using executor_type = // Executor - executor_type get_executor() noexcept; - }; - @endcode + @par !example example_1 + @par Example `post` takes a `continuation&`, which no closure converts to; ordinary callers reach it indirectly through `run_async` or similar combinators: - @code - template - void spawn_work( Ctx& ctx, task<> work ) - { - auto ex = ctx.get_executor(); - run_async(ex)(std::move(work)); // schedules work; runs on ctx - } - @endcode + @par !example example_2 + @see Executor, execution_context */ diff --git a/include/boost/capy/concept/executor.hpp b/include/boost/capy/concept/executor.hpp index 6cae87ea3..21e4cc4bd 100644 --- a/include/boost/capy/concept/executor.hpp +++ b/include/boost/capy/concept/executor.hpp @@ -87,16 +87,8 @@ class execution_context; A conforming implementation might look like: - @code - std::coroutine_handle<> dispatch( - continuation& c ) const - { - if( ctx_.running_in_this_thread() ) - return c.h; // symmetric transfer - post( c ); - return std::noop_coroutine(); - } - @endcode + @par !example example_1 + The `post` operation queues for later execution: @@ -143,22 +135,8 @@ class execution_context; @par Conforming Signatures - @code - class E - { - public: - execution_context& context() const noexcept; - - void on_work_started() const noexcept; - void on_work_finished() const noexcept; + @par !example example_2 - std::coroutine_handle<> dispatch( - continuation& c ) const; - void post( continuation& c ) const; - - bool operator==( E const& ) const noexcept; - }; - @endcode @see ExecutionContext, execution_context */ diff --git a/include/boost/capy/concept/io_awaitable.hpp b/include/boost/capy/concept/io_awaitable.hpp index 835c59480..014dd4279 100644 --- a/include/boost/capy/concept/io_awaitable.hpp +++ b/include/boost/capy/concept/io_awaitable.hpp @@ -78,49 +78,13 @@ namespace capy { compiler to find them on the awaiter type. This concept does not require them. - @code - struct A - { - bool await_ready() const noexcept; - - auto await_suspend( - std::coroutine_handle<> h, - io_env const* env ); + @par !example example_1 - T await_resume(); - }; - @endcode @par Example - @code - struct my_io_op - { - io_env const* env_ = nullptr; - continuation cont_; - - auto await_suspend( - std::coroutine_handle<> h, - io_env const* env ) - { - env_ = env; - cont_ = continuation{h}; - // Pass members by value; capturing this - // risks use-after-free in async callbacks. - // When the async operation completes, resume - // via executor.post(cont_) or executor.dispatch(cont_) - // rather than calling h.resume() directly. - start_async( - env_->stop_token, - env_->executor, - cont_ ); - return std::noop_coroutine(); - } - - bool await_ready() const noexcept { return false; } - void await_resume() {} - }; - @endcode + @par !example example_2 + @see IoRunnable */ diff --git a/include/boost/capy/concept/io_runnable.hpp b/include/boost/capy/concept/io_runnable.hpp index cb56b51b5..661847b70 100644 --- a/include/boost/capy/concept/io_runnable.hpp +++ b/include/boost/capy/concept/io_runnable.hpp @@ -81,22 +81,8 @@ namespace capy { @par Conforming Signatures - @code - class T - { - public: - struct promise_type - { - std::exception_ptr exception() noexcept; - R result(); // non-void tasks only - void set_continuation(std::coroutine_handle<>) noexcept; - void set_environment(io_env const*) noexcept; - }; - - std::coroutine_handle handle() const noexcept; - void release() noexcept; - }; - @endcode + @par !example example + @see IoAwaitable, run, run_async */ diff --git a/include/boost/capy/concept/read_stream.hpp b/include/boost/capy/concept/read_stream.hpp index 2cdf5267e..1b8b02d70 100644 --- a/include/boost/capy/concept/read_stream.hpp +++ b/include/boost/capy/concept/read_stream.hpp @@ -80,10 +80,8 @@ namespace capy { remains valid until the `co_await` expression returns. @par Conforming Signatures - @code - template< MutableBufferSequence MB > - IoAwaitable auto read_some( MB buffers ); - @endcode + @par !example example_1 + @warning **Pass buffer sequences by value.** A by-value parameter is copied into the coroutine frame, or into the awaitable's state. @@ -101,21 +99,8 @@ namespace capy { copies in O(1). See `doc/buffers-passing-rationale.md`. @par Example - @code - template< ReadStream Stream > - task<> read_all( Stream& s, char* buf, std::size_t size ) - { - std::size_t total = 0; - while( total < size ) - { - auto [ec, n] = co_await s.read_some( - mutable_buffer( buf + total, size - total ) ); - total += n; - if( ec ) - co_return; - } - } - @endcode + @par !example example_2 + @see IoAwaitable, MutableBufferSequence, awaitable_decomposes_to */ diff --git a/include/boost/capy/concept/stream.hpp b/include/boost/capy/concept/stream.hpp index 571f42d8d..43526020d 100644 --- a/include/boost/capy/concept/stream.hpp +++ b/include/boost/capy/concept/stream.hpp @@ -33,29 +33,8 @@ namespace capy { `write_some` operations. @par Example - @code - template - task<> echo(S& stream) - { - char buf[1024]; - auto [ec, n] = co_await stream.read_some(make_buffer(buf)); - if(ec) - co_return; + @par !example example - // write_some may transfer fewer than n bytes (the partial-write - // contract it inherits from WriteStream), so loop until every - // byte read is written, or an error stops the loop early. - std::size_t total = 0; - while(total < n) - { - auto [ec2, n2] = co_await stream.write_some( - const_buffer(buf + total, n - total)); - total += n2; - if(ec2) - co_return; - } - } - @endcode @see ReadStream, WriteStream */ diff --git a/include/boost/capy/concept/write_stream.hpp b/include/boost/capy/concept/write_stream.hpp index 7d326f04f..97b9554b0 100644 --- a/include/boost/capy/concept/write_stream.hpp +++ b/include/boost/capy/concept/write_stream.hpp @@ -88,10 +88,8 @@ namespace capy { @par Conforming Signatures - @code - template< ConstBufferSequence Buffers > - IoAwaitable auto write_some( Buffers buffers ); - @endcode + @par !example example_1 + @warning **Pass buffer sequences by value.** A by-value parameter is copied into the coroutine frame, or into the awaitable's state. @@ -110,21 +108,8 @@ namespace capy { @par Example - @code - template< WriteStream Stream > - task<> write_all( Stream& s, char const* buf, std::size_t size ) - { - std::size_t total = 0; - while( total < size ) - { - auto [ec, n] = co_await s.write_some( - const_buffer( buf + total, size - total ) ); - total += n; - if( ec ) - co_return; - } - } - @endcode + @par !example example_2 + @see IoAwaitable, ConstBufferSequence, awaitable_decomposes_to */ diff --git a/include/boost/capy/cond.hpp b/include/boost/capy/cond.hpp index d542f0c04..a814f6aaa 100644 --- a/include/boost/capy/cond.hpp +++ b/include/boost/capy/cond.hpp @@ -26,21 +26,8 @@ namespace capy { @par Example - @code - auto [ec, n] = co_await stream.read_some( bufs ); - if( ec == cond::canceled ) - { - // handle cancellation - } - else if( ec == cond::eof ) - { - // handle end of stream - } - else if( ec ) - { - // handle other errors - } - @endcode + @par !example example + @see error */ diff --git a/include/boost/capy/ex/any_executor.hpp b/include/boost/capy/ex/any_executor.hpp index bde7539f5..28b2a8c36 100644 --- a/include/boost/capy/ex/any_executor.hpp +++ b/include/boost/capy/ex/any_executor.hpp @@ -72,14 +72,8 @@ struct is_strand_type> : std::true_type {}; anywhere a concrete executor is expected. @par Example - @code - any_executor exec = ctx.get_executor(); - if(exec) - { - auto& context = exec.context(); - exec.post(my_coroutine); - } - @endcode + @par !example example + @see executor_ref, Executor */ diff --git a/include/boost/capy/ex/async_event.hpp b/include/boost/capy/ex/async_event.hpp index 241a6ee4d..d0fb7a2bd 100644 --- a/include/boost/capy/ex/async_event.hpp +++ b/include/boost/capy/ex/async_event.hpp @@ -81,21 +81,8 @@ namespace capy { waiters hold intrusive pointers into the event's internal list. @par Example - @code - async_event event; - - task<> waiter() { - auto [ec] = co_await event.wait(); - if(ec) - co_return; - // ... event was set ... - } + @par !example example - task<> notifier() { - // ... do some work ... - event.set(); // Wake all waiters - } - @endcode */ class async_event { diff --git a/include/boost/capy/ex/async_mutex.hpp b/include/boost/capy/ex/async_mutex.hpp index b81f783c6..b73d5f861 100644 --- a/include/boost/capy/ex/async_mutex.hpp +++ b/include/boost/capy/ex/async_mutex.hpp @@ -125,26 +125,8 @@ namespace capy { waiters hold intrusive pointers into the mutex's internal list. @par Example - @code - async_mutex cm; - - task<> protected_operation() { - auto [ec] = co_await cm.lock(); - if(ec) - co_return; - // ... critical section ... - cm.unlock(); - } + @par !example example - // Or with RAII: - task<> protected_operation_raii() { - auto [ec, guard] = co_await cm.scoped_lock(); - if(ec) - co_return; - // ... critical section ... - // unlocks automatically - } - @endcode */ class async_mutex { diff --git a/include/boost/capy/ex/async_waker.hpp b/include/boost/capy/ex/async_waker.hpp index f556bc22b..61531a056 100644 --- a/include/boost/capy/ex/async_waker.hpp +++ b/include/boost/capy/ex/async_waker.hpp @@ -100,21 +100,8 @@ namespace capy { waiter holds a pointer into the object. @par Example - @code - async_waker waker; - - // user-provided timing thread - std::thread th([&waker] { - std::this_thread::sleep_for(100ms); - waker.wake(); - }); - - task<> waiter() { - auto [ec] = co_await waker.wait(); - // resumed on the executor after ~100ms - } - // ... th.join() after the pool drains - @endcode + @par !example example + */ class async_waker { diff --git a/include/boost/capy/ex/execution_context.hpp b/include/boost/capy/ex/execution_context.hpp index c6e956309..8cc7e15ee 100644 --- a/include/boost/capy/ex/execution_context.hpp +++ b/include/boost/capy/ex/execution_context.hpp @@ -51,35 +51,8 @@ namespace capy { and must only be called during destruction. @par Example - @code - struct file_service : execution_context::service - { - protected: - void shutdown() override {} - }; + @par !example example - struct posix_file_service : file_service - { - using key_type = file_service; - - explicit posix_file_service(execution_context&) {} - }; - - class io_context : public execution_context - { - public: - ~io_context() - { - shutdown(); - destroy(); - } - }; - - io_context ctx; - ctx.make_service(); - ctx.find_service(); // returns posix_file_service* - ctx.find_service(); // also works - @endcode @see service, ExecutionContext */ @@ -138,18 +111,8 @@ class BOOST_CAPY_DECL @li Optionally define `key_type` to enable base-class lookup. @par Example - @code - struct my_service : execution_context::service - { - explicit my_service(execution_context&) {} + @par !example example - protected: - void shutdown() override - { - // Cancel pending operations, release resources - } - }; - @endcode @see execution_context */ diff --git a/include/boost/capy/ex/executor_ref.hpp b/include/boost/capy/ex/executor_ref.hpp index 8339dfcba..7ba625e4e 100644 --- a/include/boost/capy/ex/executor_ref.hpp +++ b/include/boost/capy/ex/executor_ref.hpp @@ -95,16 +95,8 @@ inline constexpr executor_vtable vtable_for = { anywhere a concrete executor is expected. @par Example - @code - void store_executor(executor_ref ex) - { - if(ex) - ex.post(my_continuation); - } + @par !example example - thread_pool ctx; - store_executor(ctx.get_executor()); - @endcode @see any_executor, Executor */ diff --git a/include/boost/capy/ex/frame_alloc_mixin.hpp b/include/boost/capy/ex/frame_alloc_mixin.hpp index 1823d81ee..e4b0d4127 100644 --- a/include/boost/capy/ex/frame_alloc_mixin.hpp +++ b/include/boost/capy/ex/frame_alloc_mixin.hpp @@ -41,19 +41,8 @@ namespace capy { support that `io_awaitable_promise_base` provides. @par Example - @code - struct my_internal_coroutine - { - struct promise_type : frame_alloc_mixin - { - my_internal_coroutine get_return_object(); - std::suspend_always initial_suspend() noexcept; - std::suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception() noexcept; - }; - }; - @endcode + @par !example example + @par Thread Safety The allocation fast path uses thread-local storage and requires diff --git a/include/boost/capy/ex/immediate.hpp b/include/boost/capy/ex/immediate.hpp index 88b42aa13..9ffd96c60 100644 --- a/include/boost/capy/ex/immediate.hpp +++ b/include/boost/capy/ex/immediate.hpp @@ -35,38 +35,12 @@ namespace capy { @tparam T The result type to wrap. @par Example - @code - // Wrap a sync operation as an awaitable - immediate get_value() - { - return {42}; - } + @par !example example_1 - task example() - { - int x = co_await get_value(); // No suspension, returns 42 - } - @endcode @par Building synchronous I/O operations - @code - struct my_sync_sink - { - template - immediate> - write(CB buffers) - { - auto n = process_sync(buffers); - return {{std::error_code(), n}}; - } - - immediate> - write_eof() - { - return {{}}; - } - }; - @endcode + @par !example example_2 + @see ready, io_result */ @@ -136,21 +110,8 @@ struct immediate with no error and the provided values. @par Example - @code - immediate> - write(const_buffer buf) - { - auto n = write_sync(buf); - return ready(n); // success with n bytes - } + @par !example example_1 - immediate> - connect() - { - connect_sync(); - return ready(); // void success - } - @endcode @return An immediate awaitable containing a successful io_result. @@ -211,16 +172,8 @@ ready(T1 t1, T2 t2, T3 t3) with an error code. @par Example - @code - immediate> - write(const_buffer buf) - { - auto ec = write_sync(buf); - if(ec) - return ready(ec, std::size_t{0}); - return ready(buffer_size(buf)); - } - @endcode + @par !example example_2 + @param ec The error code. diff --git a/include/boost/capy/ex/io_awaitable_promise_base.hpp b/include/boost/capy/ex/io_awaitable_promise_base.hpp index abfafa738..216d3f30b 100644 --- a/include/boost/capy/ex/io_awaitable_promise_base.hpp +++ b/include/boost/capy/ex/io_awaitable_promise_base.hpp @@ -46,49 +46,16 @@ namespace capy { For coroutines that need to access their execution environment: - @code - struct my_task - { - struct promise_type : io_awaitable_promise_base - { - my_task get_return_object(); - std::suspend_always initial_suspend() noexcept; - std::suspend_always final_suspend() noexcept; - void return_void(); - void unhandled_exception(); - }; + @par !example example_1 - // ... awaitable interface ... - }; - - my_task example() - { - auto env = co_await this_coro::environment; - // Access env->executor, env->stop_token, env->frame_allocator - - // Or use fine-grained accessors: - auto ex = co_await this_coro::executor; - auto token = co_await this_coro::stop_token; - auto* alloc = co_await this_coro::frame_allocator; - } - @endcode @par Custom Awaitable Transformation If your promise needs to transform awaitables (e.g., for affinity or logging), override `transform_awaitable` instead of `await_transform`: - @code - struct promise_type : io_awaitable_promise_base - { - template - auto transform_awaitable(A&& a) - { - // Your custom transformation logic - return std::forward(a); - } - }; - @endcode + @par !example example_2 + The mixin's `await_transform` intercepts @ref this_coro::environment_tag and the fine-grained tag types (@ref this_coro::executor_tag, @@ -102,21 +69,8 @@ namespace capy { (satisfying @ref IoAwaitable), implement the `await_suspend` overload on your coroutine return type: - @code - struct my_task - { - struct promise_type : io_awaitable_promise_base { ... }; + @par !example example_3 - std::coroutine_handle h_; - - // IoAwaitable await_suspend receives and stores the environment - std::coroutine_handle<> await_suspend(std::coroutine_handle<> cont, io_env const* env) - { - h_.promise().set_environment(env); - // ... rest of suspend logic ... - } - }; - @endcode @par Thread Safety The environment is stored during `await_suspend` and read during diff --git a/include/boost/capy/ex/recycling_memory_resource.hpp b/include/boost/capy/ex/recycling_memory_resource.hpp index 54ac89fd8..486b792e3 100644 --- a/include/boost/capy/ex/recycling_memory_resource.hpp +++ b/include/boost/capy/ex/recycling_memory_resource.hpp @@ -39,10 +39,8 @@ namespace capy { The global pool uses a mutex for cross-thread access. @par Example - @code - auto* mr = get_recycling_memory_resource(); - run_async(ex, mr)(my_task()); - @endcode + @par !example example + @see get_recycling_memory_resource @see run_async diff --git a/include/boost/capy/ex/run.hpp b/include/boost/capy/ex/run.hpp index 9f21bd6b6..43bc56330 100644 --- a/include/boost/capy/ex/run.hpp +++ b/include/boost/capy/ex/run.hpp @@ -611,9 +611,8 @@ namespace boost::capy { When co_awaited, the task runs on the specified executor. @par Example - @code - co_await run(other_executor)(my_task()); - @endcode + @par !example example_2 + @param ex The executor on which the task should run. @@ -712,10 +711,8 @@ run(Ex ex, std::stop_token st, Alloc alloc) is overridden. @par Example - @code - std::stop_source source; - co_await run(source.get_token())(cancellable_task()); - @endcode + @par !example example_1 + @param st The stop token for cooperative cancellation. diff --git a/include/boost/capy/ex/run_async.hpp b/include/boost/capy/ex/run_async.hpp index 3233ed064..137959555 100644 --- a/include/boost/capy/ex/run_async.hpp +++ b/include/boost/capy/ex/run_async.hpp @@ -373,19 +373,8 @@ make_trampoline(Ex, Handlers, Alloc) C++17-evaluation-order rationale behind this constraint. @par Example - @code - // Correct usage - wrapper is temporary, task is the direct argument - run_async(ex)(my_task()); + @par !example example - // Compiles - copy elision constructs w directly from the prvalue - auto w = run_async(ex); - w(my_task()); // Compile error: operator() requires rvalue - std::move(w)(my_task()); // Compiles: w is now an rvalue - - // Compiles, but WRONG - task frame allocated before run_async runs - auto t = my_task(); - run_async(ex)(std::move(t)); - @endcode @see run_async */ @@ -538,9 +527,8 @@ class [[nodiscard]] run_async_wrapper The wrapper itself should only be used from one thread. @par Example - @code - run_async(ioc.get_executor())(my_task()); - @endcode + @par !example example_1 + @param ex The executor to execute the task on. @@ -576,18 +564,8 @@ run_async(Ex ex) may be invoked from any thread where the executor schedules work. @par Example - @code - // Handler for result only (exceptions rethrown) - run_async(ex, [](int result) { - std::cout << "Got: " << result << "\n"; - })(compute_value()); - - // Overloaded handler for both result and exception - run_async(ex, overloaded{ - [](int result) { std::cout << "Got: " << result << "\n"; }, - [](std::exception_ptr) { std::cout << "Failed\n"; } - })(compute_value()); - @endcode + @par !example example_2 + @param ex The executor to execute the task on. @param h1 The handler to invoke with the result (and optionally exception). @@ -624,17 +602,8 @@ run_async(Ex ex, H1 h1) may be invoked from any thread where the executor schedules work. @par Example - @code - run_async(ex, - [](int result) { std::cout << "Got: " << result << "\n"; }, - [](std::exception_ptr ep) { - try { std::rethrow_exception(ep); } - catch (std::exception const& e) { - std::cout << "Error: " << e.what() << "\n"; - } - } - )(compute_value()); - @endcode + @par !example example_3 + @param ex The executor to execute the task on. @param h1 The handler to invoke with the result on success. @@ -674,11 +643,8 @@ run_async(Ex ex, H1 h1, H2 h2) The wrapper itself should only be used from one thread. @par Example - @code - std::stop_source source; - run_async(ex, source.get_token())(cancellable_task()); - // Later: source.request_stop(); - @endcode + @par !example example_4 + @param ex The executor to execute the task on. @param st The stop token for cooperative cancellation. diff --git a/include/boost/capy/ex/strand.hpp b/include/boost/capy/ex/strand.hpp index 44523381d..646f79428 100644 --- a/include/boost/capy/ex/strand.hpp +++ b/include/boost/capy/ex/strand.hpp @@ -69,18 +69,8 @@ namespace capy { Shared objects: Safe. @par Example - @code - thread_pool pool(4); - strand strand(pool.get_executor()); // CTAD deduces the executor type - - // Continuations are linked intrusively into the strand's queue, - // so each one must outlive its time there. Storage is typically - // owned by the awaitable or operation state that posted it. - continuation c1{h1}, c2{h2}, c3{h3}; - strand.post(c1); - strand.post(c2); - strand.post(c3); - @endcode + @par !example example + @tparam Ex The type of the underlying executor. Must satisfy the `Executor` concept. diff --git a/include/boost/capy/ex/this_coro.hpp b/include/boost/capy/ex/this_coro.hpp index 31bb306ad..a21562302 100644 --- a/include/boost/capy/ex/this_coro.hpp +++ b/include/boost/capy/ex/this_coro.hpp @@ -24,15 +24,8 @@ namespace capy { `await_transform` to yield the appropriate values without suspending. @par Example - @code - task example() - { - auto* env = co_await this_coro::environment; - auto ex = co_await this_coro::executor; - auto token = co_await this_coro::stop_token; - auto* alloc = co_await this_coro::frame_allocator; - } - @endcode + @par !example example + @see io_awaitable_promise_base, io_env */ @@ -90,15 +83,8 @@ struct frame_allocator_tag {}; executor, stop token, and allocator for this coroutine. @par Example - @code - task example() - { - auto* env = co_await this_coro::environment; - // env->executor - the executor this coroutine is bound to - // env->stop_token - the stop token for cancellation - // env->frame_allocator - the frame allocator - } - @endcode + @par !example example + @par Preconditions An `io_env` must have been installed for this coroutine before the tag @@ -124,12 +110,8 @@ inline constexpr environment_tag environment{}; executor this coroutine is bound to. @par Example - @code - task example() - { - executor_ref ex = co_await this_coro::executor; - } - @endcode + @par !example example + @par Preconditions An `io_env` must have been installed for this coroutine before the tag @@ -156,14 +138,8 @@ inline constexpr executor_tag executor{}; token was passed to this coroutine when it was awaited. @par Example - @code - task cancellable_work() - { - auto token = co_await this_coro::stop_token; - if (token.stop_requested()) - co_return; - } - @endcode + @par !example example + @par Preconditions An `io_env` must have been installed for this coroutine before the tag @@ -191,13 +167,8 @@ inline constexpr stop_token_tag stop_token{}; used for coroutine frame allocation. @par Example - @code - task example() - { - auto* alloc = co_await this_coro::frame_allocator; - // alloc is nullptr when using the default allocator - } - @endcode + @par !example example + @par Preconditions An `io_env` must have been installed for this coroutine before the tag diff --git a/include/boost/capy/ex/thread_pool.hpp b/include/boost/capy/ex/thread_pool.hpp index 866791ae6..d0e20afe1 100644 --- a/include/boost/capy/ex/thread_pool.hpp +++ b/include/boost/capy/ex/thread_pool.hpp @@ -34,13 +34,8 @@ namespace capy { @ref stop. Unsafe for construction and destruction. @par Example - @code - thread_pool pool(4); // 4 worker threads - auto ex = pool.get_executor(); - run_async(ex)(some_task()); // start work; tracked so join() waits for it - pool.join(); // wait for outstanding work to complete - // pool destructor stops the pool, discarding any pending work - @endcode + @par !example example + @note `join()` waits only for work that holds outstanding-work counting, which `run_async` (and `make_work_guard`) provide. A bare diff --git a/include/boost/capy/ex/work_guard.hpp b/include/boost/capy/ex/work_guard.hpp index decd5a77f..926327feb 100644 --- a/include/boost/capy/ex/work_guard.hpp +++ b/include/boost/capy/ex/work_guard.hpp @@ -45,19 +45,8 @@ namespace capy { object requires external synchronization. @par Example - @code - thread_pool pool(1); + @par !example work_guard - // Keep the pool from completing while we set things up - auto guard = make_work_guard(pool.get_executor()); - - // ... post work to pool ... - - // Allow the pool to complete when work is done - guard.reset(); - - pool.join(); - @endcode @note The executor is returned by reference, allowing callers to manage the executor's lifetime directly. This is essential in diff --git a/include/boost/capy/io/any_read_stream.hpp b/include/boost/capy/io/any_read_stream.hpp index c10a70680..229055280 100644 --- a/include/boost/capy/io/any_read_stream.hpp +++ b/include/boost/capy/io/any_read_stream.hpp @@ -62,18 +62,8 @@ namespace capy { are undefined behavior. @par Example - @code - // Owning - takes ownership of the stream - any_read_stream owning_stream(socket{ioc}); - - // Reference - wraps without ownership - socket sock(ioc); - any_read_stream ref_stream(&sock); - - char data[1024]; - mutable_buffer buf(data, sizeof(data)); - auto [ec, n] = co_await owning_stream.read_some(buf); - @endcode + @par !example example + @see any_write_stream, any_stream, ReadStream */ diff --git a/include/boost/capy/io/any_stream.hpp b/include/boost/capy/io/any_stream.hpp index b3ff43183..33fb3fcb4 100644 --- a/include/boost/capy/io/any_stream.hpp +++ b/include/boost/capy/io/any_stream.hpp @@ -52,31 +52,8 @@ namespace capy { and one write may be in flight simultaneously. @par Example - @code - void reader(any_read_stream&); - void writer(any_write_stream&); - - // Owning - takes ownership of the stream - any_stream owning_stream(socket{ioc}); - - // Reference - wraps without ownership - socket sock(ioc); - any_stream ref_stream(&sock); - - // Use read_some from the any_read_stream base - char rdata[1024]; - mutable_buffer rbuf(rdata, sizeof(rdata)); - auto [ec1, n1] = co_await owning_stream.read_some(std::span(&rbuf, 1)); - - // Use write_some from the any_write_stream base - char wdata[] = "hello"; - const_buffer wbuf(wdata, sizeof(wdata)); - auto [ec2, n2] = co_await owning_stream.write_some(std::span(&wbuf, 1)); - - // Pass to functions expecting one capability - reader(owning_stream); // Implicit upcast - writer(owning_stream); // Implicit upcast - @endcode + @par !example example + @see any_read_stream, any_write_stream, ReadStream, WriteStream */ diff --git a/include/boost/capy/io/any_write_stream.hpp b/include/boost/capy/io/any_write_stream.hpp index dd23eda15..de9d37f10 100644 --- a/include/boost/capy/io/any_write_stream.hpp +++ b/include/boost/capy/io/any_write_stream.hpp @@ -63,18 +63,8 @@ namespace capy { are undefined behavior. @par Example - @code - // Owning - takes ownership of the stream - any_write_stream owning_stream(socket{ioc}); - - // Reference - wraps without ownership - socket sock(ioc); - any_write_stream ref_stream(&sock); - - char data[] = "hello"; - const_buffer buf(data, sizeof(data)); - auto [ec, n] = co_await owning_stream.write_some(std::span(&buf, 1)); - @endcode + @par !example example + @see any_read_stream, any_stream, WriteStream */ diff --git a/include/boost/capy/io_result.hpp b/include/boost/capy/io_result.hpp index b9578ad57..f434756a6 100644 --- a/include/boost/capy/io_result.hpp +++ b/include/boost/capy/io_result.hpp @@ -30,18 +30,13 @@ namespace capy { tuple assignment. @par Example - @code - auto [ec, n] = co_await s.read_some(buf); - if (ec) { ... } - @endcode + @par !example example_1 + `std::tie` rebinds into existing variables without introducing new bindings: - @code - std::error_code ec; - std::size_t n = 0; - std::tie(ec, n) = co_await s.read_some(buf); - @endcode + @par !example example_2 + @note Whether the payload is meaningful when the error code is set is defined by the operation that produced the result. diff --git a/include/boost/capy/io_task.hpp b/include/boost/capy/io_task.hpp index ba3bfdcb2..d26d150b5 100644 --- a/include/boost/capy/io_task.hpp +++ b/include/boost/capy/io_task.hpp @@ -24,19 +24,8 @@ namespace capy { The tuple converting constructor allows direct `co_return` of error codes: - @code - io_task<> connect_to_server(socket& s, endpoint ep) - { - co_return co_await s.connect(ep); // returns io_result<> - } - - io_task<> require_ready(bool ready) - { - if(!ready) - co_return make_error_code(error::eof); // error_code converts to io_result<> - co_return {}; - } - @endcode + @par !example example + @tparam Ts Additional value types beyond error_code. */ diff --git a/include/boost/capy/read.hpp b/include/boost/capy/read.hpp index f566fbb1e..97a30d396 100644 --- a/include/boost/capy/read.hpp +++ b/include/boost/capy/read.hpp @@ -74,19 +74,8 @@ namespace capy { @par Example - @code - capy::task<> process_message(capy::ReadStream auto& stream) - { - std::vector header(16); // known header size for some protocol - auto [ec, n] = co_await capy::read(stream, capy::make_buffer(header)); - if (ec == capy::cond::eof) - co_return; // Connection closed - if (ec) - throw std::system_error(ec); - - // at this point `header` contains exactly 16 bytes - } - @endcode + @par !example example + @see ReadStream, MutableBufferSequence */ diff --git a/include/boost/capy/read_at_least.hpp b/include/boost/capy/read_at_least.hpp index de84540d2..7e9e7a89b 100644 --- a/include/boost/capy/read_at_least.hpp +++ b/include/boost/capy/read_at_least.hpp @@ -94,19 +94,8 @@ namespace capy { @par Example - @code - capy::task<> fill_buffer(capy::ReadStream auto& stream) - { - std::vector storage(4096); // generous capacity - // Require 16 header bytes; opportunistically take more. - auto [ec, n] = co_await capy::read_at_least( - stream, capy::make_buffer(storage), 16); - if(ec) - throw std::system_error(ec); - - // at least 16 bytes are available; n may be larger - } - @endcode + @par !example example + @see read, ReadStream, MutableBufferSequence */ diff --git a/include/boost/capy/task.hpp b/include/boost/capy/task.hpp index 85ba2f752..774d6b33e 100644 --- a/include/boost/capy/task.hpp +++ b/include/boost/capy/task.hpp @@ -106,21 +106,8 @@ struct task_return_base @par Example - @code - task compute_value() - { - auto [ec, n] = co_await stream.read_some( buf ); - if( ec ) - co_return 0; - co_return process( buf, n ); - } + @par !example example - task<> run_session( tcp_socket sock ) - { - int result = co_await compute_value(); - // ... - } - @endcode @tparam T The result type. Use `task<>` for `task`. diff --git a/include/boost/capy/test/buffer_to_string.hpp b/include/boost/capy/test/buffer_to_string.hpp index 89c026570..1c95039ea 100644 --- a/include/boost/capy/test/buffer_to_string.hpp +++ b/include/boost/capy/test/buffer_to_string.hpp @@ -27,24 +27,8 @@ namespace test { arguments, it concatenates them in order. @par Example - @code - // Single buffer sequence - const_buffer cb( "hello", 5 ); - std::string s = buffer_to_string( cb ); // "hello" + @par !example example - // Multiple buffer sequences (concatenation) - const_buffer b1( "hello", 5 ); - const_buffer b2( " world", 6 ); - std::string s = buffer_to_string( b1, b2 ); // "hello world" - - // With bufgrind splits: each half is itself a buffer sequence, - // so pass it directly -- there is no .data() to unwrap. - bufgrind bg( cb ); - while( bg ) { - auto [b1, b2] = co_await bg.next(); - BOOST_TEST_EQ( buffer_to_string( b1, b2 ), "hello" ); - } - @endcode @param bufs One or more buffer sequences to concatenate. diff --git a/include/boost/capy/test/bufgrind.hpp b/include/boost/capy/test/bufgrind.hpp index 3a92c8176..88a08c3dc 100644 --- a/include/boost/capy/test/bufgrind.hpp +++ b/include/boost/capy/test/bufgrind.hpp @@ -45,46 +45,16 @@ namespace test { Not thread-safe. @par Example - @code - // Test all split points of a buffer - std::string data = "hello world"; - auto cb = make_buffer( data ); - - fuse f; - auto r = f.inert( [&]( fuse& ) -> task<> { - bufgrind bg( cb ); - while( bg ) { - auto [b1, b2] = co_await bg.next(); - // b1 contains first N bytes (as a buffer sequence) - // b2 contains remaining bytes (as a buffer sequence) - // concatenating b1 + b2 equals original - co_await some_async_operation( b1, b2 ); - } - } ); - @endcode + @par !example example_1 + @par Mutable Buffer Example - @code - // Mutable buffers preserve mutability - char data[100]; - mutable_buffer mb( data, sizeof( data ) ); - - bufgrind bg( mb ); - while( bg ) { - auto [b1, b2] = co_await bg.next(); - // b1, b2 yield mutable_buffer when iterated - } - @endcode + @par !example example_2 + @par Step Size Example - @code - // Skip by 10 bytes for faster iteration - bufgrind bg( cb, 10 ); - while( bg ) { - auto [b1, b2] = co_await bg.next(); - // Visits positions 0, 10, 20, ..., and always size - } - @endcode + @par !example example_3 + @see buffer_slice */ diff --git a/include/boost/capy/test/fuse.hpp b/include/boost/capy/test/fuse.hpp index 4291b7307..c50c0ff73 100644 --- a/include/boost/capy/test/fuse.hpp +++ b/include/boost/capy/test/fuse.hpp @@ -72,38 +72,18 @@ namespace test { @par Basic Inline Usage - @code - fuse()([](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - return; + @par !example example_1 - ec = f.maybe_fail(); - if(ec) - return; - }); - @endcode @par Named Fuse with armed() - @code - fuse f; - MyObject obj(f); - auto r = f.armed([&](fuse&) { - obj.do_something(); - }); - @endcode + @par !example example_2 + @par Using inert() for Single-Run Tests - @code - fuse f; - auto r = f.inert([](fuse& f) { - auto ec = f.maybe_fail(); // Always succeeds - if(some_condition) - f.fail(); // Only way to signal failure - }); - @endcode + @par !example example_3 + @par Dependency Injection (Standalone Usage) @@ -112,87 +92,23 @@ namespace test { to classes for dependency injection without affecting normal operation. - @code - class MyService - { - fuse& f_; - public: - explicit MyService(fuse& f) : f_(f) {} - - std::error_code do_work() - { - auto ec = f_.maybe_fail(); // No-op outside armed/inert - if(ec) - return ec; - // ... actual work ... - return {}; - } - }; - - // Production usage - fuse is no-op - fuse f; - MyService svc(f); - svc.do_work(); // maybe_fail() returns {} always + @par !example example_4 - // Test usage - failures are injected - auto r = f.armed([&](fuse&) { - svc.do_work(); // maybe_fail() triggers failures - }); - @endcode @par Custom Error Code - @code - auto custom_ec = make_error_code( - std::errc::operation_canceled); - fuse f(custom_ec); - auto r = f.armed([](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - return; - }); - @endcode + @par !example example_5 + @par Checking the Result - @code - fuse f; - auto r = f([](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - return; - }); + @par !example example_6 - if(!r) - { - std::cerr << "Failure at " - << r.loc.file_name() << ":" - << r.loc.line() << "\n"; - } - @endcode @par Test Framework Integration - @code - fuse f; - auto r = f([](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - return; - }); - - // Boost.Test - BOOST_TEST(r.success); - if(!r) - BOOST_TEST_MESSAGE("Failed at " << r.loc.file_name() - << ":" << r.loc.line()); - - // Catch2 - REQUIRE(r.success); - if(!r) - INFO("Failed at " << r.loc.file_name() - << ":" << r.loc.line()); - @endcode + @par !example example_7 + */ class fuse { @@ -249,21 +165,8 @@ class fuse @par Example - @code - fuse f; - auto r = f([](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - return; - }); + @par !example example - if(!r) - { - std::cerr << "Failure at " - << r.loc.file_name() << ":" - << r.loc.line() << "\n"; - } - @endcode */ struct result { @@ -290,23 +193,8 @@ class fuse @par Example - @code - auto custom_ec = make_error_code( - std::errc::operation_canceled); - fuse f(custom_ec); - - std::error_code captured_ec; - auto r = f([&](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - { - captured_ec = ec; - return; - } - }); + @par !example example_1 - assert(captured_ec == custom_ec); - @endcode @param ec The error code to deliver at failure points. */ @@ -322,21 +210,8 @@ class fuse @par Example - @code - fuse f; - std::error_code captured_ec; + @par !example example_2 - auto r = f([&](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - { - captured_ec = ec; - return; - } - }); - - assert(captured_ec == error::test_failure); - @endcode */ fuse() : fuse(error::test_failure) @@ -358,27 +233,13 @@ class fuse @par Example - @code - fuse f; - auto r = f([](fuse& f) { - // Error code mode: returns the error - auto ec = f.maybe_fail(); - if(ec) - return; - - // Exception mode: throws system_error - ec = f.maybe_fail(); - if(ec) - return; - }); - @endcode + @par !example example_1 + @par Standalone Usage - @code - fuse f; - auto ec = f.maybe_fail(); // Always returns {} (no-op) - @endcode + @par !example example_2 + @param loc The source location of the call site, captured automatically. @@ -420,28 +281,8 @@ class fuse @par Example - @code - fuse f; - auto r = f([](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - return; + @par !example example_1 - // Explicit failure when a condition is not met - if(some_value != expected) - { - f.fail(); - return; - } - }); - - if(!r) - { - std::cerr << "Test failed at " - << r.loc.file_name() << ":" - << r.loc.line() << "\n"; - } - @endcode @param loc The source location of the call site, captured automatically. @@ -464,33 +305,8 @@ class fuse @par Example - @code - fuse f; - auto r = f([](fuse& f) { - try - { - do_something(); - } - catch(...) - { - f.fail(std::current_exception()); - return; - } - }); + @par !example example_2 - if(!r) - { - try - { - if(r.ep) - std::rethrow_exception(r.ep); - } - catch(std::exception const& e) - { - std::cerr << "Exception: " << e.what() << "\n"; - } - } - @endcode @param ep The exception pointer to capture. @@ -604,25 +420,8 @@ class fuse @par Example - @code - fuse f; - auto r = f.armed([](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - return; + @par !example example_2 - ec = f.maybe_fail(); - if(ec) - return; - }); - - if(!r) - { - std::cerr << "Failure at " - << r.loc.file_name() << ":" - << r.loc.line() << "\n"; - } - @endcode @param fn The test function to invoke. It receives a reference to the fuse and should call @ref maybe_fail @@ -722,25 +521,8 @@ class fuse @par Example - @code - fuse f; - auto r = f.armed([&](fuse&) -> task { - auto ec = f.maybe_fail(); - if(ec) - co_return; - - ec = f.maybe_fail(); - if(ec) - co_return; - }); + @par !example example_3 - if(!r) - { - std::cerr << "Failure at " - << r.loc.file_name() << ":" - << r.loc.line() << "\n"; - } - @endcode @param fn The coroutine test function to invoke. It receives a reference to the fuse and should call @ref maybe_fail @@ -781,25 +563,8 @@ class fuse handler and return it once the run loop is done. @par Example - @code - // Drive each iteration on a fresh io_context. - auto io_runner = [](capy::task<> t) -> std::exception_ptr - { - corosio::io_context ioc; - std::exception_ptr ep; - capy::run_async(ioc.get_executor(), - [](auto&&...){}, - [&ep](std::exception_ptr e){ ep = e; } - )(std::move(t)); - ioc.run(); - return ep; - }; - auto r = f.armed(io_runner, - [&](capy::test::fuse&) -> capy::task<> - { - co_await corosio::timeout(some_op(), 5s); - }); - @endcode + @par !example example_1 + @param run_one A callable invoked with each iteration's task; it runs the task to completion and returns any escaped exception @@ -830,19 +595,8 @@ class fuse @par Example - @code - // These are equivalent: - fuse f; - auto r1 = f.armed([](fuse& f) { ... }); - auto r2 = f([](fuse& f) { ... }); - - // Inline usage: - auto r3 = fuse()([](fuse& f) { - auto ec = f.maybe_fail(); - if(ec) - return; - }); - @endcode + @par !example example + @param fn The test function to run under failure injection. @@ -886,27 +640,8 @@ class fuse @par Example - @code - fuse f; - auto r = f.inert([](fuse& f) { - auto ec = f.maybe_fail(); // Always succeeds - assert(!ec); + @par !example example_1 - // Only way to signal failure: - if(some_condition) - { - f.fail(); - return; - } - }); - - if(!r) - { - std::cerr << "Test failed at " - << r.loc.file_name() << ":" - << r.loc.line() << "\n"; - } - @endcode @param fn The test function to invoke. It receives a reference to the fuse. Calls to @ref maybe_fail @@ -951,27 +686,8 @@ class fuse @par Example - @code - fuse f; - auto r = f.inert([](fuse& f) -> task { - auto ec = f.maybe_fail(); // Always succeeds - assert(!ec); + @par !example example_2 - // Only way to signal failure: - if(some_condition) - { - f.fail(); - co_return; - } - }); - - if(!r) - { - std::cerr << "Test failed at " - << r.loc.file_name() << ":" - << r.loc.line() << "\n"; - } - @endcode @param fn The coroutine test function to invoke. It receives a reference to the fuse. Calls to @ref maybe_fail diff --git a/include/boost/capy/test/read_stream.hpp b/include/boost/capy/test/read_stream.hpp index 881377bb8..c077f5d26 100644 --- a/include/boost/capy/test/read_stream.hpp +++ b/include/boost/capy/test/read_stream.hpp @@ -42,21 +42,8 @@ namespace test { Not thread-safe. @par Example - @code - fuse f; - read_stream rs( f ); - rs.provide( "Hello, " ); - rs.provide( "World!" ); - - auto r = f.armed( [&]( fuse& ) -> task { - char buf[32]; - auto [ec, n] = co_await rs.read_some( - mutable_buffer( buf, sizeof( buf ) ) ); - if( ec ) - co_return; - // buf contains "Hello, World!" - } ); - @endcode + @par !example example + @see fuse, ReadStream */ diff --git a/include/boost/capy/test/run_blocking.hpp b/include/boost/capy/test/run_blocking.hpp index 7e1cec2cf..6c3a1299c 100644 --- a/include/boost/capy/test/run_blocking.hpp +++ b/include/boost/capy/test/run_blocking.hpp @@ -401,9 +401,8 @@ class [[nodiscard]] run_blocking_wrapper rethrown to the caller. @par Example - @code - run_blocking()(my_void_task()); - @endcode + @par !example example_2 + @return A wrapper that accepts a task for blocking execution. @@ -434,10 +433,8 @@ run_blocking() rethrown. @par Example - @code - int result = 0; - run_blocking([&](int v) { result = v; })(compute()); - @endcode + @par !example example_3 + @param h1 Handler invoked with the result on success, and optionally with `std::exception_ptr` on failure. @@ -469,15 +466,8 @@ run_blocking(H1 h1) to `h2`. @par Example - @code - int result = 0; - run_blocking( - [&](int v) { result = v; }, - [](std::exception_ptr ep) { - std::rethrow_exception(ep); - } - )(compute()); - @endcode + @par !example example_1 + @param h1 Handler invoked with the result on success. @param h2 Handler invoked with the exception on failure. diff --git a/include/boost/capy/test/stream.hpp b/include/boost/capy/test/stream.hpp index 54a6f9a40..3b7f5d5c4 100644 --- a/include/boost/capy/test/stream.hpp +++ b/include/boost/capy/test/stream.hpp @@ -60,29 +60,8 @@ namespace test { undefined behavior. @par Example - @code - fuse f; - - auto r = f.armed( [&]( fuse& ) -> task<> { - // Constructed inside the lambda: armed() re-invokes this - // function once per injected failure point, and a stream - // pair constructed outside would carry buffered state - // across those rounds. - auto [a, b] = make_stream_pair( f ); - - auto [ec, n] = co_await a.write_some( - const_buffer( "hello", 5 ) ); - if( ec ) - co_return; - - char buf[32]; - auto [ec2, n2] = co_await b.read_some( - mutable_buffer( buf, sizeof( buf ) ) ); - if( ec2 ) - co_return; - // buf contains "hello" - } ); - @endcode + @par !example example + @see make_stream_pair, fuse */ diff --git a/include/boost/capy/test/write_stream.hpp b/include/boost/capy/test/write_stream.hpp index 5ba1fd9e7..00211fcf0 100644 --- a/include/boost/capy/test/write_stream.hpp +++ b/include/boost/capy/test/write_stream.hpp @@ -44,23 +44,8 @@ namespace test { Not thread-safe. @par Example - @code - fuse f; - - auto r = f.armed( [&]( fuse& ) -> task { - // Constructed inside the lambda: armed() re-invokes this - // function once per injected failure point, and a write_stream - // constructed outside would carry accumulated data across - // those rounds. - write_stream ws( f ); - - auto [ec, n] = co_await ws.write_some( - const_buffer( "Hello", 5 ) ); - if( ec ) - co_return; - // ws.data() returns "Hello" - } ); - @endcode + @par !example example + @see fuse, WriteStream */ diff --git a/include/boost/capy/when_all.hpp b/include/boost/capy/when_all.hpp index c073a95a9..a649fd4c3 100644 --- a/include/boost/capy/when_all.hpp +++ b/include/boost/capy/when_all.hpp @@ -618,18 +618,8 @@ class when_all_homogeneous_launcher all children complete (exception beats error_code). @par Example - @code - task example() - { - std::vector> reads; - for (auto& buf : buffers) - reads.push_back(stream.read_some(buf)); + @par !example example_1 - auto [ec, counts] = co_await when_all(std::move(reads)); - if (ec) { // handle error - } - } - @endcode @see IoAwaitableRange, when_all */ @@ -741,16 +731,8 @@ template all children complete (exception beats error_code). @par Example - @code - task example() - { - std::vector> jobs; - for (int i = 0; i < n; ++i) - jobs.push_back(process(i)); + @par !example example_2 - auto [ec] = co_await when_all(std::move(jobs)); - } - @endcode @see IoAwaitableRange, when_all */ diff --git a/include/boost/capy/when_any.hpp b/include/boost/capy/when_any.hpp index 43832532e..74e2ed2c8 100644 --- a/include/boost/capy/when_any.hpp +++ b/include/boost/capy/when_any.hpp @@ -695,20 +695,8 @@ class when_any_io_homogeneous_launcher exception is rethrown (which child is unspecified). @par Example - @code - task example() - { - std::vector> reads; - for (auto& buf : buffers) - reads.push_back(stream.read_some(buf)); + @par !example example_1 - auto result = co_await when_any(std::move(reads)); - if (result.index() == 1) - { - auto [idx, n] = std::get<1>(result); - } - } - @endcode @see IoAwaitableRange, when_any */ @@ -826,20 +814,8 @@ template that child's exception is rethrown (which child is unspecified). @par Example - @code - task example() - { - std::vector> jobs; - jobs.push_back(background_work_a()); - jobs.push_back(background_work_b()); + @par !example example_2 - auto result = co_await when_any(std::move(jobs)); - if (result.index() == 1) - { - auto winner = std::get<1>(result); - } - } - @endcode @see IoAwaitableRange, when_any */ diff --git a/include/boost/capy/write.hpp b/include/boost/capy/write.hpp index 4699aba30..8ec858065 100644 --- a/include/boost/capy/write.hpp +++ b/include/boost/capy/write.hpp @@ -82,16 +82,8 @@ namespace capy { @par Example - @code - capy::task<> send_response(capy::WriteStream auto& stream, std::string_view body) - { - auto [ec, n] = co_await capy::write(stream, capy::make_buffer(body)); - if (ec) - throw std::system_error(ec); + @par !example example - // All bytes written successfully - } - @endcode @see WriteStream, ConstBufferSequence, IoAwaitable, io_result, cond. */ diff --git a/include/boost/capy/write_at_least.hpp b/include/boost/capy/write_at_least.hpp index 53773d516..b0879ab28 100644 --- a/include/boost/capy/write_at_least.hpp +++ b/include/boost/capy/write_at_least.hpp @@ -92,17 +92,8 @@ namespace capy { @par Example - @code - capy::task<> flush_at_least(capy::WriteStream auto& stream, std::string_view data) - { - auto [ec, n] = co_await capy::write_at_least( - stream, capy::make_buffer(data), 8); - if(ec) - throw std::system_error(ec); + @par !example example - // at least 8 bytes written; n may be larger - } - @endcode @see write, WriteStream, ConstBufferSequence */ diff --git a/test/doc/CMakeLists.txt b/test/doc/CMakeLists.txt index 0f9d68f4f..07b27eceb 100644 --- a/test/doc/CMakeLists.txt +++ b/test/doc/CMakeLists.txt @@ -26,7 +26,13 @@ function(boost_capy_doc_warnings_as_errors target) endfunction() file(GLOB SNIPPETS CONFIGURE_DEPENDS snippets/*.cpp) -set(PFILES ${SNIPPETS} CMakeLists.txt Jamfile) +# Reference examples: injected into the MrDocs reference by +# doc/addons/extensions/reference-snippets.lua, and compiled here so an example +# in the reference is one the build has already checked. Same target as the +# page snippets -- each file keeps its code in an anonymous namespace, so +# independently authored examples that both define example() do not collide. +file(GLOB REFERENCE_SNIPPETS CONFIGURE_DEPENDS reference/*.cpp) +set(PFILES ${SNIPPETS} ${REFERENCE_SNIPPETS} CMakeLists.txt Jamfile) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "" FILES ${PFILES}) add_executable(boost_capy_doc_tests ${PFILES}) diff --git a/test/doc/Jamfile b/test/doc/Jamfile index 76174cc47..e4ec77fe0 100644 --- a/test/doc/Jamfile +++ b/test/doc/Jamfile @@ -18,7 +18,9 @@ project on ; -run [ glob snippets/*.cpp ] +# reference/*.cpp holds the examples MrDocs injects into the reference; they are +# compiled here so the b2 legs check them too, not just the CMake ones. +run [ glob snippets/*.cpp ] [ glob reference/*.cpp ] ../../extra/test_suite/test_main.cpp ../../extra/test_suite/test_suite.cpp : : : ../../extra/test_suite diff --git a/test/doc/reference/ExecutionContext.concept.cpp b/test/doc/reference/ExecutionContext.concept.cpp new file mode 100644 index 000000000..ed4c7e70e --- /dev/null +++ b/test/doc/reference/ExecutionContext.concept.cpp @@ -0,0 +1,82 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::ExecutionContext, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/execution_context.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example_1[] +class X : public execution_context +{ +public: + using executor_type = executor_ref; // any type satisfying Executor + executor_type get_executor() noexcept; +}; + +static_assert( ExecutionContext ); +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +template +void spawn_work( Ctx& ctx, task<> work ) +{ + auto ex = ctx.get_executor(); + run_async(ex)(std::move(work)); // schedules work; runs on ctx +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/Executor.concept.cpp b/test/doc/reference/Executor.concept.cpp new file mode 100644 index 000000000..05569d138 --- /dev/null +++ b/test/doc/reference/Executor.concept.cpp @@ -0,0 +1,115 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::Executor, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/executor.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example_1[] +class E +{ + execution_context& ctx_; + std::thread::id home_ = std::this_thread::get_id(); + +public: + explicit E(execution_context& ctx) noexcept : ctx_(ctx) {} + + execution_context& context() const noexcept { return ctx_; } + void on_work_started() const noexcept {} + void on_work_finished() const noexcept {} + + bool operator==(E const& other) const noexcept + { + return &ctx_ == &other.ctx_; + } + + std::coroutine_handle<> dispatch( + continuation& c ) const + { + if( std::this_thread::get_id() == home_ ) + return c.h; // symmetric transfer + post( c ); + return std::noop_coroutine(); + } + + void post( continuation& ) const + { + // enqueue for later execution on this executor's context + } +}; + +static_assert( Executor ); +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +class E +{ +public: + execution_context& context() const noexcept; + + void on_work_started() const noexcept; + void on_work_finished() const noexcept; + + std::coroutine_handle<> dispatch( + continuation& c ) const; + void post( continuation& c ) const; + + bool operator==( E const& ) const noexcept; +}; +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/IoAwaitable.concept.cpp b/test/doc/reference/IoAwaitable.concept.cpp new file mode 100644 index 000000000..6a7cf869e --- /dev/null +++ b/test/doc/reference/IoAwaitable.concept.cpp @@ -0,0 +1,109 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::IoAwaitable, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/io_awaitable.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example_1[] +struct A +{ + bool await_ready() const noexcept; + + auto await_suspend( + std::coroutine_handle<> h, + io_env const* env ); + + auto await_resume(); +}; +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +struct my_io_op +{ + io_env const* env_ = nullptr; + continuation cont_; + + // Stands in for a real asynchronous entry point (a socket read, a + // timer, ...) that takes its own stop token and executor and + // resumes the continuation from an async callback once the + // operation completes. + void start_async(std::stop_token, any_executor, continuation&) {} + + auto await_suspend( + std::coroutine_handle<> h, + io_env const* env ) + { + env_ = env; + cont_ = continuation{h}; + // Pass members by value; capturing this + // risks use-after-free in async callbacks. + start_async( + env_->stop_token, + env_->executor, + cont_ ); + return std::noop_coroutine(); + } + + bool await_ready() const noexcept { return false; } + io_result await_resume() { return {}; } +}; + +static_assert( IoAwaitable ); +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/IoRunnable.concept.cpp b/test/doc/reference/IoRunnable.concept.cpp new file mode 100644 index 000000000..b13f09060 --- /dev/null +++ b/test/doc/reference/IoRunnable.concept.cpp @@ -0,0 +1,77 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::IoRunnable, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/io_runnable.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +class T +{ +public: + struct promise_type + { + std::exception_ptr exception() noexcept; + int result(); // non-void tasks only + void set_continuation(std::coroutine_handle<>) noexcept; + void set_environment(io_env const*) noexcept; + }; + + std::coroutine_handle handle() const noexcept; + void release() noexcept; +}; +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/README.md b/test/doc/reference/README.md new file mode 100644 index 000000000..259f71767 --- /dev/null +++ b/test/doc/reference/README.md @@ -0,0 +1,101 @@ +# Reference examples + +The examples shown in the MrDocs reference live here, as ordinary C++ compiled by +`boost_capy_doc_tests` alongside the page snippets in `test/doc/snippets/`. An +example in the reference is therefore one the build has already checked. + +Compilation and rendering are independent. CI compiles these files whether or +not the docs build; the docs build injects them whether or not they compile. +Neither waits on the other, and MrDocs stays a dependency of the docs workflow +only. + +## Adding an example + +1. Write the example in the file named after the symbol that documents it: + + ```text + test/doc/reference/..cpp + ``` + + `` is the symbol's qualified name with `boost::capy::` stripped and + `::` replaced by `__`; `` is what MrDocs calls it (`record`, + `function`, `namespace`, `concept`, `typedef`, `variable`, `enum`). So + `boost::capy::work_guard`, a class, is `work_guard.record.cpp`, and + `boost::capy::test::fuse` is `test__fuse.record.cpp`. The name *is* the + mapping: the transform opens that path, because MrDocs' Lua sandbox has no + directory listing. + +2. Put the code the reference should show inside a tagged region: + + ```cpp + namespace ex_1 { + // tag::example[] + void keep_alive_while_setting_up() + { + ... + } + // end::example[] + } // namespace ex_1 + ``` + + Only what is between the tags renders. Includes, warning suppressions and + the namespaces stay outside them, so the reader sees the example and not the + scaffolding. Each region gets its own namespace inside a file-level + anonymous one: ten examples across the library define `example()`, and this + is what keeps them from colliding with each other or across files. + +3. Add `@par Example` to the docstring where the example belongs: + + ```text + @par Example + ``` + + The transform inserts the code directly after that heading, which is how the + example lands where the docstring says rather than at the bottom. A docstring + with `@par Example` and no example, and no file to supply one, fails the docs + build. + +## Several examples for one symbol + +Add more tagged regions to the same file, each in its own namespace. They are +injected in file order. + +## Symbols that share a file + +Overload sets and duplicated records can share a `.` name. Give +each region a declaration naming the symbols it belongs to: + +```cpp +// mrdocs::for buffer_param-0e buffer_param-0c +``` + +The names are MrDocs anchors, which you can read from the generated reference. +Without this, every symbol sharing the file takes every example in it, and an +overload page shows its siblings' examples. + +## Checks + +- `boost_capy_doc_tests` compiles these files with `-Wall -Wextra -Werror`. +- The docs workflow asserts the number of injected examples, because a MrDocs + without the extension installed ignores the script and renders the reference + with no examples at all while still reporting success. +- Five `@code` blocks remain in headers: MrDocs does not publish those symbols, + so there is nothing to inject them into. + +## Requirements + +Injection needs MrDocs' extension API, which is not in any tagged release -- +corpus transforms arrived in cppalliance/mrdocs#1196 and script-driven +generators in #1218, both after v0.8.0. + +`doc/build_antora.sh` downloads a develop build, copies +`doc/addons/extensions/*.lua` into `/share/mrdocs/addons/extensions/`, +and exports `MRDOCS_ROOT` so the Antora reference extension uses it instead of +downloading its own. Doing it there rather than in CI means every caller gets +it: this repository's docs workflow, the C++ Alliance doc build, and a plain +local run. + +Set `MRDOCS_ROOT` yourself to build against a specific MrDocs; the extension is +copied into whatever install is used. Note that setting a `version` for the +reference extension in `doc/local-playbook.yml` makes it reject a local install +and download its own, which silently produces a reference with no examples. diff --git a/test/doc/reference/ReadStream.concept.cpp b/test/doc/reference/ReadStream.concept.cpp new file mode 100644 index 000000000..141aca66c --- /dev/null +++ b/test/doc/reference/ReadStream.concept.cpp @@ -0,0 +1,83 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::ReadStream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/read_stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example_1[] +template< MutableBufferSequence MB > +IoAwaitable auto read_some( MB buffers ); +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +template< ReadStream Stream > +task<> read_all( Stream& s, char* buf, std::size_t size ) +{ + std::size_t total = 0; + while( total < size ) + { + auto [ec, n] = co_await s.read_some( + mutable_buffer( buf + total, size - total ) ); + total += n; + if( ec ) + co_return; + } +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/Stream.concept.cpp b/test/doc/reference/Stream.concept.cpp new file mode 100644 index 000000000..44f2c7704 --- /dev/null +++ b/test/doc/reference/Stream.concept.cpp @@ -0,0 +1,84 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::Stream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +template +task<> echo(S& stream) +{ + char buf[1024]; + auto [ec, n] = co_await stream.read_some(make_buffer(buf)); + if(ec) + co_return; + + // write_some may transfer fewer than n bytes (the partial-write + // contract it inherits from WriteStream), so loop until every + // byte read is written, or an error stops the loop early. + std::size_t total = 0; + while(total < n) + { + auto [ec2, n2] = co_await stream.write_some( + const_buffer(buf + total, n - total)); + total += n2; + if(ec2) + co_return; + } +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/WriteStream.concept.cpp b/test/doc/reference/WriteStream.concept.cpp new file mode 100644 index 000000000..ed5def1e0 --- /dev/null +++ b/test/doc/reference/WriteStream.concept.cpp @@ -0,0 +1,83 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::WriteStream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/write_stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example_1[] +template< ConstBufferSequence Buffers > +IoAwaitable auto write_some( Buffers buffers ); +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +template< WriteStream Stream > +task<> write_all( Stream& s, char const* buf, std::size_t size ) +{ + std::size_t total = 0; + while( total < size ) + { + auto [ec, n] = co_await s.write_some( + const_buffer( buf + total, size - total ) ); + total += n; + if( ec ) + co_return; + } +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/any_executor.record.cpp b/test/doc/reference/any_executor.record.cpp new file mode 100644 index 000000000..1a023fdcc --- /dev/null +++ b/test/doc/reference/any_executor.record.cpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::any_executor, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/any_executor.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +// c must stay at a stable address until the executor dequeues it, so +// the caller owns it -- typically as part of the awaitable or +// operation state that posts it, never as a callee-local temporary. +void dispatch_via_context(thread_pool& ctx, continuation& c) +{ + any_executor exec = ctx.get_executor(); + if(exec) + { + auto& context = exec.context(); + // dispatch() may hand the continuation straight back for + // symmetric transfer instead of enqueuing it, so the returned + // handle must be resumed or the continuation is dropped. + exec.dispatch(c).resume(); + } +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/any_read_stream.record.cpp b/test/doc/reference/any_read_stream.record.cpp new file mode 100644 index 000000000..08969217f --- /dev/null +++ b/test/doc/reference/any_read_stream.record.cpp @@ -0,0 +1,87 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::any_read_stream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/io/any_read_stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +// A minimal ReadStream: completes immediately, reporting +// the whole buffer sequence as read. +struct instant_stream +{ + template + auto read_some(MB buffers) + { + return ready(buffer_size(buffers)); + } +}; + +task<> use_any_read_stream() +{ + // Owning - takes ownership of the stream + any_read_stream owning_stream(instant_stream{}); + + // Reference - wraps without ownership + instant_stream instant; + any_read_stream ref_stream(&instant); + + char data[1024]; + mutable_buffer buf(data, sizeof(data)); + auto [ec, n] = co_await owning_stream.read_some(buf); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/any_stream.record.cpp b/test/doc/reference/any_stream.record.cpp new file mode 100644 index 000000000..1845deabf --- /dev/null +++ b/test/doc/reference/any_stream.record.cpp @@ -0,0 +1,106 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::any_stream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/io/any_stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +// A minimal bidirectional stream: both operations complete +// immediately, reporting the whole buffer sequence transferred. +struct instant_stream +{ + template + auto read_some(MB buffers) + { + return ready(buffer_size(buffers)); + } + + template + auto write_some(CB buffers) + { + return ready(buffer_size(buffers)); + } +}; + +void reader(any_read_stream&) {} +void writer(any_write_stream&) {} + +task<> use_any_stream() +{ + // Owning - takes ownership of the stream + any_stream owning_stream(instant_stream{}); + + // Reference - wraps without ownership + instant_stream instant; + any_stream ref_stream(&instant); + + // Use read_some from the any_read_stream base + char rdata[1024]; + mutable_buffer rbuf(rdata, sizeof(rdata)); + auto [ec1, n1] = co_await owning_stream.read_some(std::span(&rbuf, 1)); + + // Use write_some from the any_write_stream base + char wdata[] = "hello"; + const_buffer wbuf(wdata, sizeof(wdata)); + auto [ec2, n2] = co_await owning_stream.write_some(std::span(&wbuf, 1)); + + // Pass to functions expecting one capability + reader(owning_stream); // Implicit upcast + writer(owning_stream); // Implicit upcast +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/any_write_stream.record.cpp b/test/doc/reference/any_write_stream.record.cpp new file mode 100644 index 000000000..e2c148fa5 --- /dev/null +++ b/test/doc/reference/any_write_stream.record.cpp @@ -0,0 +1,87 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::any_write_stream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/io/any_write_stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +// A minimal WriteStream: completes immediately, reporting +// the whole buffer sequence as written. +struct instant_stream +{ + template + auto write_some(CB buffers) + { + return ready(buffer_size(buffers)); + } +}; + +task<> use_any_write_stream() +{ + // Owning - takes ownership of the stream + any_write_stream owning_stream(instant_stream{}); + + // Reference - wraps without ownership + instant_stream instant; + any_write_stream ref_stream(&instant); + + char data[] = "hello"; + const_buffer buf(data, sizeof(data)); + auto [ec, n] = co_await owning_stream.write_some(std::span(&buf, 1)); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/async_event.record.cpp b/test/doc/reference/async_event.record.cpp new file mode 100644 index 000000000..3e18c5e2a --- /dev/null +++ b/test/doc/reference/async_event.record.cpp @@ -0,0 +1,77 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::async_event, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/async_event.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +async_event event; + +task<> waiter() { + auto [ec] = co_await event.wait(); + if(ec) + co_return; + // ... event was set ... +} + +task<> notifier() { + // ... do some work ... + event.set(); // Wake all waiters + co_return; +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/async_mutex.record.cpp b/test/doc/reference/async_mutex.record.cpp new file mode 100644 index 000000000..123a813b3 --- /dev/null +++ b/test/doc/reference/async_mutex.record.cpp @@ -0,0 +1,81 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::async_mutex, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/async_mutex.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +async_mutex cm; + +task<> protected_operation() { + auto [ec] = co_await cm.lock(); + if(ec) + co_return; + // ... critical section ... + cm.unlock(); +} + +// Or with RAII: +task<> protected_operation_raii() { + auto [ec, guard] = co_await cm.scoped_lock(); + if(ec) + co_return; + // ... critical section ... + // unlocks automatically +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/async_waker.record.cpp b/test/doc/reference/async_waker.record.cpp new file mode 100644 index 000000000..c7dec87a7 --- /dev/null +++ b/test/doc/reference/async_waker.record.cpp @@ -0,0 +1,82 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::async_waker, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/async_waker.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +void waker_example() +{ + async_waker waker; + + // user-provided timing thread + std::thread th([&waker] { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + waker.wake(); + }); + + auto waiter = [&waker]() -> task<> { + auto [ec] = co_await waker.wait(); + // resumed on the executor after ~100ms + }; + + // ... run waiter() on an executor and let the pool drain + + th.join(); // waker.wake() has run; safe to destroy waker now +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/awaitable_decomposes_to.concept.cpp b/test/doc/reference/awaitable_decomposes_to.concept.cpp new file mode 100644 index 000000000..7c41da108 --- /dev/null +++ b/test/doc/reference/awaitable_decomposes_to.concept.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::awaitable_decomposes_to, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/decomposes_to.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +// Constrain a function to accept only awaitables that return +// a decomposable result of (error_code, size_t) +template + requires awaitable_decomposes_to +task process(A&& op) +{ + auto [ec, n] = co_await std::forward(op); + if (ec) + co_return; + // process n bytes... +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/buffer_param.record.cpp b/test/doc/reference/buffer_param.record.cpp new file mode 100644 index 000000000..9e27880f9 --- /dev/null +++ b/test/doc/reference/buffer_param.record.cpp @@ -0,0 +1,107 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::buffer_param, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/buffers/buffer_param.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { +namespace ex_1 { +// tag::example_1[] +task<> write(ConstBufferSequence auto buffers); // CORRECT +task<> write(ConstBufferSequence auto& buffers); // WRONG - dangling reference +// end::example_1[] +} // namespace ex_1 +namespace ex_2 { +// tag::example_2[] +task<> send(ConstBufferSequence auto buffers) +{ + buffer_param bp(buffers); + while(true) + { + auto bufs = bp.data(); + if(bufs.empty()) + break; + auto n = co_await do_something(bufs); + bp.consume(n); + } +} +// end::example_2[] +} // namespace ex_2 +namespace ex_3 { +// tag::example_3[] +class base +{ +public: + template + task<> write(BS buffers) + { + const_buffer_param bp(buffers); + while(true) + { + auto bufs = bp.data(); + if(bufs.empty()) + break; + std::size_t n = 0; + co_await write_impl(bufs, n); + bp.consume(n); + } + } + +protected: + virtual task<> write_impl( + std::span buffers, + std::size_t& bytes_written) = 0; +}; +// end::example_3[] +} // namespace ex_3 + +} // namespace diff --git a/test/doc/reference/buffer_size.function.cpp b/test/doc/reference/buffer_size.function.cpp new file mode 100644 index 000000000..07d02bc6a --- /dev/null +++ b/test/doc/reference/buffer_size.function.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::buffer_size, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/buffers.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +unsigned char header[16]; +unsigned char payload[512]; +std::array bufs = { + mutable_buffer( header, sizeof(header) ), + mutable_buffer( payload, sizeof(payload) ) }; +std::size_t total = buffer_size( bufs ); // 16 + 512 +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/buffer_slice.function.cpp b/test/doc/reference/buffer_slice.function.cpp new file mode 100644 index 000000000..ebe388ae5 --- /dev/null +++ b/test/doc/reference/buffer_slice.function.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::buffer_slice, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/buffers/buffer_slice.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task<> send_in_two_parts( any_write_stream& sock, const_buffer bufs ) +{ + co_await write(sock, buffer_slice(bufs, 0, 16384)); // first 16 KB + auto rest = buffer_slice(bufs, 16384); // drop first 16 KB + co_await write(sock, rest); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/cond.enum.cpp b/test/doc/reference/cond.enum.cpp new file mode 100644 index 000000000..ef70c7cce --- /dev/null +++ b/test/doc/reference/cond.enum.cpp @@ -0,0 +1,79 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::cond, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/cond.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task<> classify_read_error( any_read_stream& stream, mutable_buffer bufs ) +{ + auto [ec, n] = co_await stream.read_some( bufs ); + if( ec == cond::canceled ) + { + // handle cancellation + } + else if( ec == cond::eof ) + { + // handle end of stream + } + else if( ec ) + { + // handle other errors + } +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/const_buffer_archetype_.record.cpp b/test/doc/reference/const_buffer_archetype_.record.cpp new file mode 100644 index 000000000..3ea59c485 --- /dev/null +++ b/test/doc/reference/const_buffer_archetype_.record.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::const_buffer_archetype_, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/buffer_archetype.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +template +concept MyWritable = + requires(T& stream, const_buffer_archetype buffers) + { + stream.write(buffers); + }; +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/consuming_buffers.record.cpp b/test/doc/reference/consuming_buffers.record.cpp new file mode 100644 index 000000000..e848313f9 --- /dev/null +++ b/test/doc/reference/consuming_buffers.record.cpp @@ -0,0 +1,76 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::consuming_buffers, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/buffers/consuming_buffers.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { +namespace ex_1 { +// tag::example[] +template +io_task read_until_full( any_read_stream& stream, Buffers buffers ) +{ + consuming_buffers consuming(buffers); + std::size_t total = 0, want = buffer_size(buffers); + while (total < want) + { + auto [ec, n] = co_await stream.read_some(consuming.data()); + consuming.consume(n); + total += n; + if (ec && total < want) co_return {ec, total}; + } + co_return {std::error_code(), total}; +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/decomposes_to.concept.cpp b/test/doc/reference/decomposes_to.concept.cpp new file mode 100644 index 000000000..43648b2ac --- /dev/null +++ b/test/doc/reference/decomposes_to.concept.cpp @@ -0,0 +1,67 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::decomposes_to, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/decomposes_to.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +struct result { int a; double b; }; + +static_assert(decomposes_to); +static_assert(decomposes_to, int, double>); +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/execution_context.record.cpp b/test/doc/reference/execution_context.record.cpp new file mode 100644 index 000000000..4db6f70a5 --- /dev/null +++ b/test/doc/reference/execution_context.record.cpp @@ -0,0 +1,92 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::execution_context, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/execution_context.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +struct file_service : execution_context::service +{ +protected: + void shutdown() override {} +}; + +struct posix_file_service : file_service +{ + using key_type = file_service; + + explicit posix_file_service(execution_context&) {} +}; + +class io_context : public execution_context +{ +public: + ~io_context() + { + shutdown(); + destroy(); + } +}; + +void configure_services(io_context& ctx) +{ + ctx.make_service(); + ctx.find_service(); // returns posix_file_service* + ctx.find_service(); // also works +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/execution_context__service.record.cpp b/test/doc/reference/execution_context__service.record.cpp new file mode 100644 index 000000000..132c4d3f8 --- /dev/null +++ b/test/doc/reference/execution_context__service.record.cpp @@ -0,0 +1,73 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::execution_context::service, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/execution_context.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +struct my_service : execution_context::service +{ + explicit my_service(execution_context&) {} + +protected: + void shutdown() override + { + // Cancel pending operations, release resources + } +}; +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/executor_ref.record.cpp b/test/doc/reference/executor_ref.record.cpp new file mode 100644 index 000000000..89d413800 --- /dev/null +++ b/test/doc/reference/executor_ref.record.cpp @@ -0,0 +1,75 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::executor_ref, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/executor_ref.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +// my_continuation must stay at a stable address until the executor +// dequeues it, so it is owned by the caller, not by store_executor(). +void store_executor(executor_ref ex, continuation& my_continuation) +{ + if(ex) + ex.post(my_continuation); +} + +void use_thread_pool(thread_pool& ctx, continuation& my_continuation) +{ + store_executor(ctx.get_executor(), my_continuation); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/frame_alloc_mixin.record.cpp b/test/doc/reference/frame_alloc_mixin.record.cpp new file mode 100644 index 000000000..4a87b7aa0 --- /dev/null +++ b/test/doc/reference/frame_alloc_mixin.record.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::frame_alloc_mixin, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/frame_alloc_mixin.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +struct my_internal_coroutine +{ + struct promise_type : frame_alloc_mixin + { + my_internal_coroutine get_return_object(); + std::suspend_always initial_suspend() noexcept; + std::suspend_always final_suspend() noexcept; + void return_void(); + void unhandled_exception() noexcept; + }; +}; +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/immediate.record.cpp b/test/doc/reference/immediate.record.cpp new file mode 100644 index 000000000..81f2e2c9e --- /dev/null +++ b/test/doc/reference/immediate.record.cpp @@ -0,0 +1,94 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::immediate, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/immediate.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example_1[] +// Wrap a sync operation as an awaitable +immediate get_value() +{ + return {42}; +} + +task example() +{ + int x = co_await get_value(); // No suspension, returns 42 +} +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +struct my_sync_sink +{ + template + immediate> + write(CB buffers) + { + auto n = process_sync(buffers); + return {{std::error_code(), n}}; + } + + immediate> + write_eof() + { + return {{}}; + } +}; +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/io_awaitable_promise_base.record.cpp b/test/doc/reference/io_awaitable_promise_base.record.cpp new file mode 100644 index 000000000..ac11803a1 --- /dev/null +++ b/test/doc/reference/io_awaitable_promise_base.record.cpp @@ -0,0 +1,187 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::io_awaitable_promise_base, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/io_awaitable_promise_base.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example_1[] +// Both examples on this page show the same minimal promise_type +// deliberately: the point here is the mixin's environment access, not +// variations on promise plumbing. +struct my_task +{ + struct promise_type : io_awaitable_promise_base + { + my_task get_return_object() + { + return my_task{std::coroutine_handle::from_promise(*this)}; + } + std::suspend_always initial_suspend() noexcept { return {}; } + + // Resumes the awaiting coroutine by symmetric transfer, as the + // base class requires: the continuation stored by + // set_continuation() must be handed back here, or the awaiting + // coroutine is never resumed. + auto final_suspend() noexcept + { + struct awaiter + { + promise_type* p_; + bool await_ready() const noexcept { return false; } + std::coroutine_handle<> + await_suspend(std::coroutine_handle<>) const noexcept + { + return p_->continuation(); + } + void await_resume() const noexcept {} + }; + return awaiter{this}; + } + void return_void() {} + + // Capture rather than swallow. A real awaitable rethrows + // this from its own await_resume(). + void unhandled_exception() noexcept { ep_ = std::current_exception(); } + + std::exception_ptr ep_; + }; + + std::coroutine_handle h; +}; + +my_task example() +{ + auto env = co_await this_coro::environment; + // Access env->executor, env->stop_token, env->frame_allocator + + // Or use fine-grained accessors: + auto ex = co_await this_coro::executor; + auto token = co_await this_coro::stop_token; + auto* alloc = co_await this_coro::frame_allocator; +} +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +struct promise_type : io_awaitable_promise_base +{ + template + auto transform_awaitable(A&& a) + { + // Your custom transformation logic + return std::forward(a); + } +}; +// end::example_2[] +} // namespace ex_2 + +namespace ex_3 { +// tag::example_3[] +// Same minimal promise_type as the Basic Usage example above -- this +// section's point is the await_suspend overload below, not the promise. +struct my_task +{ + struct promise_type : io_awaitable_promise_base + { + my_task get_return_object() + { + return my_task{std::coroutine_handle::from_promise(*this)}; + } + std::suspend_always initial_suspend() noexcept { return {}; } + + // Resumes the awaiting coroutine by symmetric transfer, as the + // base class requires: the continuation stored by + // set_continuation() must be handed back here, or the awaiting + // coroutine is never resumed. + auto final_suspend() noexcept + { + struct awaiter + { + promise_type* p_; + bool await_ready() const noexcept { return false; } + std::coroutine_handle<> + await_suspend(std::coroutine_handle<>) const noexcept + { + return p_->continuation(); + } + void await_resume() const noexcept {} + }; + return awaiter{this}; + } + void return_void() {} + + // Capture rather than swallow. A real awaitable rethrows + // this from its own await_resume(). + void unhandled_exception() noexcept { ep_ = std::current_exception(); } + + std::exception_ptr ep_; + }; + + std::coroutine_handle h_; + + // IoAwaitable await_suspend receives and stores the environment, + // then resumes into the coroutine body via symmetric transfer + std::coroutine_handle<> await_suspend(std::coroutine_handle<> cont, io_env const* env) + { + h_.promise().set_continuation(cont); + h_.promise().set_environment(env); + return h_; + } +}; +// end::example_3[] +} // namespace ex_3 + +} // namespace diff --git a/test/doc/reference/io_result.typedef.cpp b/test/doc/reference/io_result.typedef.cpp new file mode 100644 index 000000000..e6b2a6cf9 --- /dev/null +++ b/test/doc/reference/io_result.typedef.cpp @@ -0,0 +1,80 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::io_result, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/io_result.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example_1[] +task<> discard_first_chunk( any_read_stream& s, mutable_buffer buf ) +{ + auto [ec, n] = co_await s.read_some(buf); + if (ec) + co_return; // error: n's meaning here is defined by read_some +} +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +task<> read_into_locals( any_read_stream& s, mutable_buffer buf ) +{ + std::error_code ec; + std::size_t n = 0; + std::tie(ec, n) = co_await s.read_some(buf); +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/io_task.typedef.cpp b/test/doc/reference/io_task.typedef.cpp new file mode 100644 index 000000000..4e5eb3b76 --- /dev/null +++ b/test/doc/reference/io_task.typedef.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::io_task, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/io_task.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +io_task read_one( any_read_stream& s, mutable_buffer buf ) +{ + co_return co_await s.read_some(buf); // returns io_result +} + +io_task<> require_ready(bool ready) +{ + if(!ready) + co_return make_error_code(error::eof); // error_code converts to io_result<> + co_return {}; +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/mutable_buffer_archetype_.record.cpp b/test/doc/reference/mutable_buffer_archetype_.record.cpp new file mode 100644 index 000000000..3272db5a0 --- /dev/null +++ b/test/doc/reference/mutable_buffer_archetype_.record.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::mutable_buffer_archetype_, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/concept/buffer_archetype.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +template +concept MyReadable = + requires(T& stream, mutable_buffer_archetype buffers) + { + stream.read(buffers); + }; +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/operator_.function.cpp b/test/doc/reference/operator_.function.cpp new file mode 100644 index 000000000..06ca6279c --- /dev/null +++ b/test/doc/reference/operator_.function.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for operator(), injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/buffers.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +unsigned char header[16]; +unsigned char payload[512]; +std::array bufs = { + mutable_buffer( header, sizeof(header) ), + mutable_buffer( payload, sizeof(payload) ) }; +std::size_t total = buffer_size( bufs ); // 16 + 512 +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/read.function.cpp b/test/doc/reference/read.function.cpp new file mode 100644 index 000000000..41fe6d79f --- /dev/null +++ b/test/doc/reference/read.function.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::read, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/read.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +capy::task<> process_message(capy::ReadStream auto& stream) +{ + std::vector header(16); // known header size for some protocol + auto [ec, n] = co_await capy::read(stream, capy::make_buffer(header)); + if (ec == capy::cond::eof) + co_return; // Connection closed + if (ec) + throw std::system_error(ec); + + // at this point `header` contains exactly 16 bytes +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/read_at_least.function.cpp b/test/doc/reference/read_at_least.function.cpp new file mode 100644 index 000000000..752bc4742 --- /dev/null +++ b/test/doc/reference/read_at_least.function.cpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::read_at_least, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/read_at_least.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +capy::task<> fill_buffer(capy::ReadStream auto& stream) +{ + std::vector storage(4096); // generous capacity + // Require 16 header bytes; opportunistically take more. + auto [ec, n] = co_await capy::read_at_least( + stream, capy::make_buffer(storage), 16); + if(ec) + throw std::system_error(ec); + + // at least 16 bytes are available; n may be larger +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/ready.function.cpp b/test/doc/reference/ready.function.cpp new file mode 100644 index 000000000..1823e72f4 --- /dev/null +++ b/test/doc/reference/ready.function.cpp @@ -0,0 +1,104 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::ready, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/immediate.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { +namespace ex_1 { +// tag::example_1[] +std::size_t write_all_sync(const_buffer buf) +{ + return buffer_size(buf); +} + +std::error_code connect_sync() +{ + return {}; +} + +immediate> +write(const_buffer buf) +{ + auto n = write_all_sync(buf); + return ready(n); // success with n bytes +} + +immediate> +connect() +{ + connect_sync(); + return ready(); // void success +} +// end::example_1[] +} // namespace ex_1 +namespace ex_2 { +// tag::example_2[] +std::error_code write_checked_sync(const_buffer buf) +{ + if(buffer_size(buf) == 0) + return std::make_error_code(std::errc::invalid_argument); + return {}; +} + +immediate> +write(const_buffer buf) +{ + auto ec = write_checked_sync(buf); + if(ec) + return ready(ec, std::size_t{0}); + return ready(buffer_size(buf)); +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/recycling_memory_resource.record.cpp b/test/doc/reference/recycling_memory_resource.record.cpp new file mode 100644 index 000000000..91cb70d59 --- /dev/null +++ b/test/doc/reference/recycling_memory_resource.record.cpp @@ -0,0 +1,70 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::recycling_memory_resource, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/recycling_memory_resource.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task my_task() { co_return; } + +void run_with_recycling( any_executor ex ) +{ + auto* mr = get_recycling_memory_resource(); + run_async(ex, mr)(my_task()); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/run.function.cpp b/test/doc/reference/run.function.cpp new file mode 100644 index 000000000..b94a3963e --- /dev/null +++ b/test/doc/reference/run.function.cpp @@ -0,0 +1,80 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::run, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/run.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { +namespace ex_1 { +// tag::example_1[] +task cancellable_task() { co_return; } + +task override_stop_token() +{ + std::stop_source source; + co_await run(source.get_token())(cancellable_task()); +} +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +task my_task() { co_return; } + +task switch_executor( any_executor other_executor ) +{ + co_await run(other_executor)(my_task()); +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/run_async.function.cpp b/test/doc/reference/run_async.function.cpp new file mode 100644 index 000000000..c615d93e7 --- /dev/null +++ b/test/doc/reference/run_async.function.cpp @@ -0,0 +1,137 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::run_async, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/run_async.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { +namespace ex_1 { +// tag::example_1[] +task my_task() { co_return; } + +void start_task( any_executor ex ) +{ + run_async(ex)(my_task()); +} +// end::example_1[] +} // namespace ex_1 +namespace ex_2 { +// tag::example_2[] +task compute_value() { co_return 42; } + +template +struct overloaded : Fs... { using Fs::operator()...; }; +template +overloaded(Fs...) -> overloaded; + +// The handlers may run after this function returns, on whichever thread +// the executor schedules them, so the state they write must outlive +// the call. +int last_result = 0; +int last_result2 = 0; +bool last_failed = false; + +void run_with_result_handler_demo( any_executor ex ) +{ + run_async(ex, [](int result) { + last_result = result; // the successful value arrives here + })(compute_value()); + + // Overloaded handler for both result and exception + overloaded handle_result_or_exception{ + [](int result) { last_result2 = result; }, // the successful value arrives here + [](std::exception_ptr) { last_failed = true; } // the failure arrives here + }; + run_async(ex, handle_result_or_exception)(compute_value()); +} +// end::example_2[] +} // namespace ex_2 +namespace ex_3 { +// tag::example_3[] +task compute_value() { co_return 42; } + +// The handlers may run after this function returns, on whichever thread +// the executor schedules them, so the state they write must outlive +// the call. +int separate_handlers_result = 0; +std::string separate_handlers_error; + +void run_with_separate_handlers_demo( any_executor ex ) +{ + run_async(ex, + [](int result) { + separate_handlers_result = result; // the successful value arrives here + }, + [](std::exception_ptr ep) { + try { std::rethrow_exception(ep); } + catch (std::exception const& e) { + separate_handlers_error = e.what(); // copied: the message outlives the exception + } + } + )(compute_value()); +} +// end::example_3[] +} // namespace ex_3 +namespace ex_4 { +// tag::example_4[] +task cancellable_task() { co_return; } + +void run_with_cancellation( any_executor ex ) +{ + std::stop_source source; + run_async(ex, source.get_token())(cancellable_task()); + // Later: source.request_stop(); +} +// end::example_4[] +} // namespace ex_4 + +} // namespace diff --git a/test/doc/reference/run_async_wrapper.record.cpp b/test/doc/reference/run_async_wrapper.record.cpp new file mode 100644 index 000000000..eb19ea45b --- /dev/null +++ b/test/doc/reference/run_async_wrapper.record.cpp @@ -0,0 +1,91 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::run_async_wrapper, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/run_async.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task my_task() { co_return; } + +void correct_usage( any_executor ex ) +{ + // Correct usage - wrapper is temporary, task is the direct argument + run_async(ex)(my_task()); +} + +void rvalue_only_call( any_executor ex ) +{ + // Compiles - copy elision constructs w directly from the prvalue + auto w = run_async(ex); + + // Calling on the rvalue is the supported form; calling through + // the stored lvalue is rejected by the rvalue ref-qualifier. + using wrapper = decltype(w); + static_assert( std::is_invocable_v< wrapper, task > ); + static_assert( ! std::is_invocable_v< wrapper&, task > ); + + std::move(w)(my_task()); // Compiles: w is now an rvalue +} + +void silent_misuse( any_executor ex ) +{ + // Compiles, but WRONG - task frame allocated before run_async runs + auto t = my_task(); + run_async(ex)(std::move(t)); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/strand.record.cpp b/test/doc/reference/strand.record.cpp new file mode 100644 index 000000000..cf90911eb --- /dev/null +++ b/test/doc/reference/strand.record.cpp @@ -0,0 +1,76 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::strand, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/strand.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +// Continuations are linked intrusively into the strand's queue, so +// each must outlive its time there. The caller owns c1/c2/c3 -- +// typically as members of the awaitable or operation state that +// posts them, never as locals that go out of scope while enqueued. +void post_three(thread_pool& pool, + continuation& c1, continuation& c2, continuation& c3) +{ + strand sd(pool.get_executor()); // CTAD deduces the executor type + + sd.post(c1); + sd.post(c2); + sd.post(c3); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/task.record.cpp b/test/doc/reference/task.record.cpp new file mode 100644 index 000000000..a843a2fd3 --- /dev/null +++ b/test/doc/reference/task.record.cpp @@ -0,0 +1,75 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::task, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/task.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task compute_value( any_read_stream& stream, mutable_buffer buf ) +{ + auto [ec, n] = co_await stream.read_some( buf ); + if( ec ) + co_return 0; + co_return static_cast( n ); +} + +task<> run_session( any_read_stream& stream, mutable_buffer buf ) +{ + int result = co_await compute_value( stream, buf ); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/test__buffer_to_string.function.cpp b/test/doc/reference/test__buffer_to_string.function.cpp new file mode 100644 index 000000000..41e8d14d5 --- /dev/null +++ b/test/doc/reference/test__buffer_to_string.function.cpp @@ -0,0 +1,87 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::buffer_to_string, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/buffer_to_string.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example[] +task<> +buffer_to_string_examples() +{ + // Single buffer sequence + const_buffer cb( "hello", 5 ); + BOOST_TEST_EQ( buffer_to_string( cb ), "hello" ); + + // Multiple buffer sequences (concatenation) + const_buffer b1( "hello", 5 ); + const_buffer b2( " world", 6 ); + BOOST_TEST_EQ( buffer_to_string( b1, b2 ), "hello world" ); + + // With bufgrind splits: each half is itself a buffer sequence, + // so pass it directly -- there is no .data() to unwrap. + bufgrind bg( cb ); + while( bg ) { + auto [h1, h2] = co_await bg.next(); + BOOST_TEST_EQ( buffer_to_string( h1, h2 ), "hello" ); + } +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/test__bufgrind.record.cpp b/test/doc/reference/test__bufgrind.record.cpp new file mode 100644 index 000000000..993abe173 --- /dev/null +++ b/test/doc/reference/test__bufgrind.record.cpp @@ -0,0 +1,123 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::bufgrind, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/bufgrind.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example_1[] +void +bufgrind_walk_splits_demo() +{ + // Test all split points of a buffer + std::string data = "hello world"; + auto cb = make_buffer( data ); + + fuse f; + auto r = f.inert( [&]( fuse& ) -> task<> { + bufgrind bg( cb ); + while( bg ) { + auto [b1, b2] = co_await bg.next(); + // b1 contains first N bytes (as a buffer sequence) + // b2 contains remaining bytes (as a buffer sequence) + // concatenating b1 + b2 equals original + BOOST_TEST( buffer_to_string( b1, b2 ) == data ); + } + } ); +} +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +// Mutable buffers preserve mutability +char data[100]; +mutable_buffer buf( data, sizeof( data ) ); + +task<> +bufgrind_walk_mutable() +{ + bufgrind bg( buf ); + while( bg ) { + auto [b1, b2] = co_await bg.next(); + // b1, b2 yield mutable_buffer when iterated + static_assert( MutableBufferSequence ); + static_assert( MutableBufferSequence ); + } +} +// end::example_2[] +} // namespace ex_2 + +namespace ex_3 { +// tag::example_3[] +// Skip by 10 bytes for faster iteration +const_buffer bufgrind_step_data( "0123456789ABCDE", 15 ); + +task<> +bufgrind_walk_by_step() +{ + bufgrind bg( bufgrind_step_data, 10 ); + while( bg ) { + auto [b1, b2] = co_await bg.next(); + // Visits positions 0, 10, 20, ..., and always size + } +} +// end::example_3[] +} // namespace ex_3 + +} // namespace diff --git a/test/doc/reference/test__fuse.record.cpp b/test/doc/reference/test__fuse.record.cpp new file mode 100644 index 000000000..ab4f3463b --- /dev/null +++ b/test/doc/reference/test__fuse.record.cpp @@ -0,0 +1,210 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::fuse, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/fuse.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example_1[] +void basic_inline_usage() +{ + fuse()([](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; + + ec = f.maybe_fail(); + if(ec) + return; + }); +} +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +void named_fuse_with_armed() +{ + struct MyObject + { + fuse& f; + explicit MyObject(fuse& f) : f(f) {} + + void do_something() + { + auto ec = f.maybe_fail(); + if(ec) + return; + } + }; + + fuse f; + MyObject obj(f); + auto r = f.armed([&](fuse&) { + obj.do_something(); + }); +} +// end::example_2[] +} // namespace ex_2 + +namespace ex_3 { +// tag::example_3[] +void inert_single_run_test(bool some_condition) +{ + fuse f; + auto r = f.inert([&](fuse& f) { + auto ec = f.maybe_fail(); // Always succeeds + if(some_condition) + f.fail(); // Only way to signal failure + }); +} +// end::example_3[] +} // namespace ex_3 + +namespace ex_4 { +// tag::example_4[] +void dependency_injection_standalone_usage() +{ + class MyService + { + fuse& f_; + public: + explicit MyService(fuse& f) : f_(f) {} + + std::error_code do_work() + { + auto ec = f_.maybe_fail(); // No-op outside armed/inert + if(ec) + return ec; + // ... actual work ... + return {}; + } + }; + + // Production usage - fuse is no-op + fuse f; + MyService svc(f); + svc.do_work(); // maybe_fail() returns {} always + + // Test usage - failures are injected + auto r = f.armed([&](fuse&) { + svc.do_work(); // maybe_fail() triggers failures + }); +} +// end::example_4[] +} // namespace ex_4 + +namespace ex_5 { +// tag::example_5[] +auto custom_ec = make_error_code( + std::errc::operation_canceled); +fuse f(custom_ec); +auto r = f.armed([](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; +}); +// end::example_5[] +} // namespace ex_5 + +namespace ex_6 { +// tag::example_6[] +void checking_the_result() +{ + fuse f; + auto r = f([](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; + }); + + if(!r) + { + std::cerr << "Failed at " << r.loc.file_name() + << ":" << r.loc.line() << "\n"; + } +} +// end::example_6[] +} // namespace ex_6 + +namespace ex_7 { +// tag::example_7[] +void test_framework_integration() +{ + fuse f; + auto r = f([](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; + }); + + // BOOST_TEST is capy's own Boost.Test-style assertion macro, + // declared in extra/test_suite/test_suite.hpp and included as + // "test_suite.hpp". A Catch2 suite would spell the same check + // REQUIRE(r.success). + BOOST_TEST(r.success); + if(!r) + { + std::cerr << "Failed at " << r.loc.file_name() + << ":" << r.loc.line() << "\n"; + } +} +// end::example_7[] +} // namespace ex_7 + +} // namespace diff --git a/test/doc/reference/test__fuse__armed.function.cpp b/test/doc/reference/test__fuse__armed.function.cpp new file mode 100644 index 000000000..c8f52b62f --- /dev/null +++ b/test/doc/reference/test__fuse__armed.function.cpp @@ -0,0 +1,144 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::fuse::armed, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/fuse.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { +namespace ex_1 { +// tag::example_1[] +// This runner drives each iteration on a background thread via +// thread_pool, rather than run_blocking's single-threaded event +// loop -- demonstrating that armed() only needs a way to run the +// task to completion and report any exception, not any +// particular kind of executor. join() blocks until the posted +// task and its handlers have finished, so ep is safe to read +// once it returns. +std::exception_ptr run_one_iteration(task<> t) +{ + thread_pool pool(1); + std::exception_ptr ep; + run_async(pool.get_executor(), + [](auto&&...) {}, + [&](std::exception_ptr e) { ep = e; } + )(std::move(t)); + pool.join(); + return ep; +} + +void armed_with_custom_runner() +{ + fuse f; + auto r = f.armed(run_one_iteration, + [](fuse& f) -> task<> + { + auto ec = f.maybe_fail(); + if(ec) + co_return; + }); +} +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +void armed_basic_two_points() +{ + fuse f; + auto r = f.armed([](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; + + ec = f.maybe_fail(); + if(ec) + return; + }); + + if(!r) + { + std::cerr << "Failed at " << r.loc.file_name() + << ":" << r.loc.line() << "\n"; + } +} +// end::example_2[] +} // namespace ex_2 + +namespace ex_3 { +// tag::example_3[] +void armed_coroutine_two_points() +{ + fuse f; + auto r = f.armed([&](fuse&) -> task { + auto ec = f.maybe_fail(); + if(ec) + co_return; + + ec = f.maybe_fail(); + if(ec) + co_return; + }); + + if(!r) + { + std::cerr << "Failed at " << r.loc.file_name() + << ":" << r.loc.line() << "\n"; + } +} +// end::example_3[] +} // namespace ex_3 + +} // namespace diff --git a/test/doc/reference/test__fuse__fail.function.cpp b/test/doc/reference/test__fuse__fail.function.cpp new file mode 100644 index 000000000..fc62b383d --- /dev/null +++ b/test/doc/reference/test__fuse__fail.function.cpp @@ -0,0 +1,121 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::fuse::fail, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/fuse.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { +namespace ex_1 { +// tag::example_1[] +void fail_on_unmet_condition(int some_value, int expected) +{ + fuse f; + auto r = f([&](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; + + // Explicit failure when a condition is not met + if(some_value != expected) + { + f.fail(); + return; + } + }); + + if(!r) + { + std::cerr << "Failed at " << r.loc.file_name() + << ":" << r.loc.line() << "\n"; + } +} +// end::example_1[] +} // namespace ex_1 +namespace ex_2 { +// tag::example_2[] +void fail_captures_exception(void (*do_something)()) +{ + fuse f; + auto r = f([&](fuse& f) { + try + { + do_something(); + } + catch(...) + { + f.fail(std::current_exception()); + return; + } + }); + + if(!r) + { + std::string message; + try + { + if(r.ep) + std::rethrow_exception(r.ep); + } + catch(std::exception const& e) + { + message = e.what(); // copied: outlives the exception + } + } +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/test__fuse__fuse.function.cpp b/test/doc/reference/test__fuse__fuse.function.cpp new file mode 100644 index 000000000..5b77be0bd --- /dev/null +++ b/test/doc/reference/test__fuse__fuse.function.cpp @@ -0,0 +1,107 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::fuse::fuse, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/fuse.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { +namespace ex_1 { +// tag::example_1[] +void custom_error_code() +{ + auto custom_ec = make_error_code( + std::errc::operation_canceled); + fuse f(custom_ec); + + std::error_code captured_ec; + auto r = f([&](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + { + captured_ec = ec; + return; + } + }); + + // The fuse delivers the error code it was constructed with, + // not error::test_failure. + BOOST_TEST( captured_ec == custom_ec ); +} +// end::example_1[] +} // namespace ex_1 +namespace ex_2 { +// tag::example_2[] +void default_error_code() +{ + fuse f; + std::error_code captured_ec; + + auto r = f([&](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + { + captured_ec = ec; + return; + } + }); + + // A default-constructed fuse delivers error::test_failure. + BOOST_TEST( captured_ec == error::test_failure ); +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/test__fuse__inert.function.cpp b/test/doc/reference/test__fuse__inert.function.cpp new file mode 100644 index 000000000..379aa53e3 --- /dev/null +++ b/test/doc/reference/test__fuse__inert.function.cpp @@ -0,0 +1,114 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::fuse::inert, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/fuse.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { +namespace ex_1 { +// tag::example_1[] +void inert_run_once(bool some_condition) +{ + fuse f; + auto r = f.inert([&](fuse& f) { + auto ec = f.maybe_fail(); // Always succeeds + + assert(!ec); // inert() never injects + + // Only way to signal failure: + if(some_condition) + { + f.fail(); + return; + } + }); + + if(!r) + { + std::cerr << "Failed at " << r.loc.file_name() + << ":" << r.loc.line() << "\n"; + } +} +// end::example_1[] +} // namespace ex_1 +namespace ex_2 { +// tag::example_2[] +void inert_coroutine_run_once(bool some_condition) +{ + fuse f; + auto r = f.inert([&](fuse& f) -> task { + auto ec = f.maybe_fail(); // Always succeeds + + assert(!ec); // inert() never injects + + // Only way to signal failure: + if(some_condition) + { + f.fail(); + co_return; + } + }); + + if(!r) + { + std::cerr << "Failed at " << r.loc.file_name() + << ":" << r.loc.line() << "\n"; + } +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/test__fuse__maybe_fail.function.cpp b/test/doc/reference/test__fuse__maybe_fail.function.cpp new file mode 100644 index 000000000..41235ec95 --- /dev/null +++ b/test/doc/reference/test__fuse__maybe_fail.function.cpp @@ -0,0 +1,86 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::fuse::maybe_fail, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/fuse.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example_1[] +fuse f; +auto r = f([](fuse& f) { + // Error code mode: returns the error + auto ec = f.maybe_fail(); + if(ec) + return; + + // Exception mode: throws system_error + ec = f.maybe_fail(); + if(ec) + return; +}); +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +fuse f; +auto ec = f.maybe_fail(); // Always returns {} (no-op) +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/test__fuse__operator_.function.cpp b/test/doc/reference/test__fuse__operator_.function.cpp new file mode 100644 index 000000000..0fdf1df96 --- /dev/null +++ b/test/doc/reference/test__fuse__operator_.function.cpp @@ -0,0 +1,89 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::fuse::operator(), injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/fuse.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example[] +void call_operator_is_armed_alias() +{ + // These are equivalent: + fuse f; + auto r1 = f.armed([](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; + }); + auto r2 = f([](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; + }); + + // Inline usage: + auto r3 = fuse()([](fuse& f) { + auto ec = f.maybe_fail(); + if(ec) + return; + }); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/test__fuse__result.record.cpp b/test/doc/reference/test__fuse__result.record.cpp new file mode 100644 index 000000000..375a437ab --- /dev/null +++ b/test/doc/reference/test__fuse__result.record.cpp @@ -0,0 +1,95 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::fuse::result, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/fuse.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example[] +void inspecting_the_captured_exception() +{ + fuse f; + auto r = f([](fuse& f) { + try + { + throw std::exception(); + } + catch(...) + { + f.fail(std::current_exception()); + } + }); + + // result::ep holds the exception passed to fail(), if any. + if(!r && r.ep) + { + std::string message; + try + { + std::rethrow_exception(r.ep); + } + catch(std::exception const& e) + { + message = e.what(); // copied: outlives the exception + } + } +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/test__read_stream.record.cpp b/test/doc/reference/test__read_stream.record.cpp new file mode 100644 index 000000000..6b68a93a5 --- /dev/null +++ b/test/doc/reference/test__read_stream.record.cpp @@ -0,0 +1,89 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::read_stream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/read_stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example[] +void +read_stream_armed_demo() +{ + fuse f; + + auto r = f.armed( [&]( fuse& ) -> task { + // Constructed inside the lambda: armed() re-invokes this + // function once per injected failure point, and a + // read_stream constructed outside would carry a stale + // read position across those rounds. + read_stream rs( f ); + rs.provide( "Hello, " ); + rs.provide( "World!" ); + + char buf[32]; + auto [ec, n] = co_await rs.read_some( + mutable_buffer( buf, sizeof( buf ) ) ); + if( ec ) + co_return; + // buf contains "Hello, World!" + } ); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/test__run_blocking.function.cpp b/test/doc/reference/test__run_blocking.function.cpp new file mode 100644 index 000000000..873822b83 --- /dev/null +++ b/test/doc/reference/test__run_blocking.function.cpp @@ -0,0 +1,116 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::run_blocking, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/run_blocking.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { +namespace ex_1 { +// tag::example_1[] +task +compute_example_2() +{ + co_return 7; +} + +void +run_blocking_two_handler_demo() +{ + int result = 0; + run_blocking( + [&](int v) { result = v; }, + [](std::exception_ptr ep) { std::rethrow_exception( ep ); } + )( compute_example_2() ); +} +// end::example_1[] +} // namespace ex_1 + +namespace ex_2 { +// tag::example_2[] +task<> +run_blocking_void_example() +{ + co_return; +} + +void +run_blocking_no_handler_demo() +{ + run_blocking()( run_blocking_void_example() ); +} +// end::example_2[] +} // namespace ex_2 + +namespace ex_3 { +// tag::example_3[] +task +compute_example() +{ + co_return 42; +} + +void +run_blocking_h1_demo() +{ + int result = 0; + run_blocking( [&](int v) { result = v; } )( + compute_example() ); + BOOST_TEST_EQ( result, 42 ); +} +// end::example_3[] +} // namespace ex_3 + +} // namespace diff --git a/test/doc/reference/test__stream.record.cpp b/test/doc/reference/test__stream.record.cpp new file mode 100644 index 000000000..e1045c3e4 --- /dev/null +++ b/test/doc/reference/test__stream.record.cpp @@ -0,0 +1,92 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::stream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example[] +void +stream_pair_armed_demo() +{ + fuse f; + + auto r = f.armed( [&]( fuse& ) -> task<> { + // Constructed inside the lambda: armed() re-invokes this + // function once per injected failure point, and a stream + // pair constructed outside would carry buffered state + // across those rounds. + auto [a, b] = make_stream_pair( f ); + + auto [ec, n] = co_await a.write_some( + const_buffer( "hello", 5 ) ); + if( ec ) + co_return; + + char buf[32]; + auto [ec2, n2] = co_await b.read_some( + mutable_buffer( buf, sizeof( buf ) ) ); + if( ec2 ) + co_return; + // buf contains "hello" + } ); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/test__write_stream.record.cpp b/test/doc/reference/test__write_stream.record.cpp new file mode 100644 index 000000000..98108af5a --- /dev/null +++ b/test/doc/reference/test__write_stream.record.cpp @@ -0,0 +1,86 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::test::write_stream, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/test/write_stream.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include +#include + +#include "test_suite.hpp" + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; +using namespace boost::capy::test; + +namespace { + +namespace ex_1 { +// tag::example[] +void +write_stream_armed_demo() +{ + fuse f; + + auto r = f.armed( [&]( fuse& ) -> task { + // Constructed inside the lambda: armed() re-invokes this + // function once per injected failure point, and a + // write_stream constructed outside would carry + // accumulated data across those rounds. + write_stream ws( f ); + + auto [ec, n] = co_await ws.write_some( + const_buffer( "Hello", 5 ) ); + if( ec ) + co_return; + // ws.data() returns "Hello" + } ); +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/this_coro.namespace.cpp b/test/doc/reference/this_coro.namespace.cpp new file mode 100644 index 000000000..f71593733 --- /dev/null +++ b/test/doc/reference/this_coro.namespace.cpp @@ -0,0 +1,70 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::this_coro, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/this_coro.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task example() +{ + auto* env = co_await this_coro::environment; + auto ex = co_await this_coro::executor; + auto token = co_await this_coro::stop_token; + auto* alloc = co_await this_coro::frame_allocator; +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/this_coro__environment.variable.cpp b/test/doc/reference/this_coro__environment.variable.cpp new file mode 100644 index 000000000..075d937b0 --- /dev/null +++ b/test/doc/reference/this_coro__environment.variable.cpp @@ -0,0 +1,70 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::this_coro::environment, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/this_coro.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task example() +{ + auto* env = co_await this_coro::environment; + // env->executor - the executor this coroutine is bound to + // env->stop_token - the stop token for cancellation + // env->frame_allocator - the frame allocator +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/this_coro__executor.variable.cpp b/test/doc/reference/this_coro__executor.variable.cpp new file mode 100644 index 000000000..9cce48fdc --- /dev/null +++ b/test/doc/reference/this_coro__executor.variable.cpp @@ -0,0 +1,67 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::this_coro::executor, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/this_coro.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task example() +{ + executor_ref ex = co_await this_coro::executor; +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/this_coro__frame_allocator.variable.cpp b/test/doc/reference/this_coro__frame_allocator.variable.cpp new file mode 100644 index 000000000..f0127327e --- /dev/null +++ b/test/doc/reference/this_coro__frame_allocator.variable.cpp @@ -0,0 +1,68 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::this_coro::frame_allocator, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/this_coro.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task example() +{ + auto* alloc = co_await this_coro::frame_allocator; + // alloc is nullptr when using the default allocator +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/this_coro__stop_token.variable.cpp b/test/doc/reference/this_coro__stop_token.variable.cpp new file mode 100644 index 000000000..9accc5976 --- /dev/null +++ b/test/doc/reference/this_coro__stop_token.variable.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::this_coro::stop_token, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/this_coro.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task cancellable_work() +{ + auto token = co_await this_coro::stop_token; + if (token.stop_requested()) + co_return; +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/thread_pool.record.cpp b/test/doc/reference/thread_pool.record.cpp new file mode 100644 index 000000000..8093cb51f --- /dev/null +++ b/test/doc/reference/thread_pool.record.cpp @@ -0,0 +1,73 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::thread_pool, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/ex/thread_pool.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +task some_task() { co_return; } + +void run_on_pool() +{ + thread_pool pool(4); // 4 worker threads + auto ex = pool.get_executor(); + run_async(ex)(some_task()); // start work; tracked so join() waits for it + pool.join(); // wait for outstanding work to complete + // pool destructor stops the pool, discarding any pending work +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/when_all.function.cpp b/test/doc/reference/when_all.function.cpp new file mode 100644 index 000000000..f5ef38be3 --- /dev/null +++ b/test/doc/reference/when_all.function.cpp @@ -0,0 +1,95 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::when_all, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/when_all.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { +namespace ex_1 { +// tag::example_1[] +io_task read_one( any_read_stream& stream, mutable_buffer buf ) +{ + co_return co_await stream.read_some(buf); +} + +task read_all_connections( + std::vector& streams, std::vector& buffers ) +{ + // One awaitable per stream: each stream is touched by exactly one + // child, so running them concurrently is safe. + std::vector> reads; + for (std::size_t i = 0; i < streams.size(); ++i) + reads.push_back(read_one(streams[i], buffers[i])); + + auto [ec, counts] = co_await when_all(std::move(reads)); + if (ec) + { + // handle error + } +} +// end::example_1[] +} // namespace ex_1 +namespace ex_2 { +// tag::example_2[] +template< class MakeJob > +task run_n_jobs( MakeJob make_job, int n ) +{ + std::vector> jobs; + for (int i = 0; i < n; ++i) + jobs.push_back(make_job(i)); // io_task<> per index + + auto [ec] = co_await when_all(std::move(jobs)); +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/when_any.function.cpp b/test/doc/reference/when_any.function.cpp new file mode 100644 index 000000000..78b8379e3 --- /dev/null +++ b/test/doc/reference/when_any.function.cpp @@ -0,0 +1,108 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::when_any, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/when_any.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { +namespace ex_1 { +// tag::example_1[] +io_task read_from( any_read_stream& stream, mutable_buffer buf ) +{ + co_return co_await stream.read_some(buf); +} + +task read_first_ready( + std::vector& streams, std::vector& buffers ) +{ + // One awaitable per stream: each stream is touched by exactly one + // child, so racing them concurrently is safe. + std::vector> reads; + for (std::size_t i = 0; i < streams.size(); ++i) + reads.push_back(read_from(streams[i], buffers[i])); + + auto result = co_await when_any(std::move(reads)); + if (result.index() == 1) + { + auto [idx, n] = std::get<1>(result); // winning stream's slot and byte count + } +} +// end::example_1[] +} // namespace ex_1 +namespace ex_2 { +// tag::example_2[] +io_task<> background_work_a() +{ + co_return {}; +} + +io_task<> background_work_b() +{ + co_return {}; +} + +task example() +{ + std::vector> jobs; + jobs.push_back(background_work_a()); + jobs.push_back(background_work_b()); + + auto result = co_await when_any(std::move(jobs)); + if (result.index() == 1) + { + auto winner = std::get<1>(result); // index of the job that succeeded first + } +} +// end::example_2[] +} // namespace ex_2 + +} // namespace diff --git a/test/doc/reference/work_guard.record.cpp b/test/doc/reference/work_guard.record.cpp new file mode 100644 index 000000000..381c0444f --- /dev/null +++ b/test/doc/reference/work_guard.record.cpp @@ -0,0 +1,55 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples injected into include/boost/capy/ex/work_guard.hpp's +// documentation by doc/addons/extensions/reference-snippets.lua. The tagged +// region is what the reference renders; scaffolding stays outside the tags. + +// Examples deliberately leave results unused; the reference explains the +// values in prose instead. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4505) // unreferenced local function removed +#endif + +#include +#include + +namespace capy = boost::capy; + +namespace { + +using namespace boost::capy; + +// tag::work_guard[] +void keep_alive_while_setting_up() +{ + thread_pool pool(1); + + // Keep the pool from completing while we set things up. Note + // make_work_guard() takes the Executor from get_executor(), not + // the thread_pool context itself. + auto guard = make_work_guard(pool.get_executor()); + + // ... post work to pool ... + + // Allow the pool to complete when work is done + guard.reset(); + + pool.join(); +} +// end::work_guard[] + +} // namespace diff --git a/test/doc/reference/write.function.cpp b/test/doc/reference/write.function.cpp new file mode 100644 index 000000000..816d906d1 --- /dev/null +++ b/test/doc/reference/write.function.cpp @@ -0,0 +1,71 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::write, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/write.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +capy::task<> send_response(capy::WriteStream auto& stream, std::string_view body) +{ + auto [ec, n] = co_await capy::write(stream, capy::make_buffer(body)); + if (ec) + throw std::system_error(ec); + + // All bytes written successfully +} +// end::example[] +} // namespace ex_1 + +} // namespace diff --git a/test/doc/reference/write_at_least.function.cpp b/test/doc/reference/write_at_least.function.cpp new file mode 100644 index 000000000..076e5590c --- /dev/null +++ b/test/doc/reference/write_at_least.function.cpp @@ -0,0 +1,72 @@ +// +// Copyright (c) 2026 Michael Vandeberg +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/capy +// + +// Reference examples for boost::capy::write_at_least, injected into its documentation by +// doc/addons/extensions/reference-snippets.lua. Declared in: +// include/boost/capy/write_at_least.hpp +// +// The tagged regions are what the reference renders; the includes, +// suppressions and namespaces around them are scaffolding. Each region gets +// its own namespace so that examples which reuse a name still compile. + +// Examples leave results unused; the reference explains them in prose. +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wunused-function" +// gcc 15 with sanitizers misattributes coroutine frame delete paths +#pragma GCC diagnostic ignored "-Wmismatched-new-delete" +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-lambda-capture" +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif +#if defined(_MSC_VER) +#pragma warning(disable: 4834) // discarding [[nodiscard]] return value +#pragma warning(disable: 4189) // local variable initialized but not referenced +#pragma warning(disable: 4100) // unreferenced formal parameter +#pragma warning(disable: 4101) // unreferenced local variable +#pragma warning(disable: 4456) // declaration hides previous local declaration +#pragma warning(disable: 4457) // declaration hides function parameter +#pragma warning(disable: 4458) // declaration hides class member +#pragma warning(disable: 4459) // declaration hides global declaration +#endif + +#include + +#include +#include +#include +#include +#include +#include + +namespace capy = boost::capy; +using namespace boost::capy; + +namespace { + +namespace ex_1 { +// tag::example[] +capy::task<> flush_at_least(capy::WriteStream auto& stream, std::string_view data) +{ + auto [ec, n] = co_await capy::write_at_least( + stream, capy::make_buffer(data), 8); + if(ec) + throw std::system_error(ec); + + // at least 8 bytes written; n may be larger +} +// end::example[] +} // namespace ex_1 + +} // namespace