Skip to content

refactor(deco,zest): make macro.h a pure macro header in both libraries - #181

Merged
16bit-ykiko merged 3 commits into
mainfrom
feat/deco-macro-header
Jul 25, 2026
Merged

refactor(deco,zest): make macro.h a pure macro header in both libraries#181
16bit-ykiko merged 3 commits into
mainfrom
feat/deco-macro-header

Conversation

@16bit-ykiko

@16bit-ykiko 16bit-ykiko commented Jul 25, 2026

Copy link
Copy Markdown
Member

Why

Upstream is modularizing, and kotatsu will be built as a module. Modules cannot export macros, so once a downstream switches to import, the Deco* / TEST_* macros are no longer reachable — they have to arrive through a textual include.

For that include to be usable it must pull in nothing. Anything a macro.h includes lands in the consumer's TU textually and duplicates declarations the module already provides. Neither library met that bar:

  • kota/deco/facade/macro.h included facade/decl.h and facade/trait.h.
  • kota/zest/macro.h included assert/check.h, assert/trace.h, runner/suite.h, snapshot/snapshot.h, plus a conditional codec/json/json.h.

What

deco — move the macros up to kota/deco/macro.h, mirroring the kota/zest/macro.h layout, with zero includes.

zest — strip the includes from kota/zest/macro.h; they move to kota/zest/zest.h, where ~90 test TUs already point.

Both headers are now verifiably include-free:

$ grep -c '#include' include/kota/deco/macro.h include/kota/zest/macro.h
0
0

Downstream usage:

import kota;                     // declarations
#include "kota/deco/macro.h"     // macros
#include "kota/zest/macro.h"

Bug found and fixed along the way

kota/zest/macro.h gated the EXPECT_SNAPSHOT_JSON family on __has_include("kota/codec/json/json.h"). That answered the wrong question. The file ships with kotatsu, so it is on disk whether or not the JSON backend was built — the gate opened unconditionally and then included a header that hard-errors:

include/kota/codec/json/type.h:11:2: error: #error "simdjson.h is required for the JSON codec backend"

Since tests/unit/zest is always compiled, KOTA_CODEC_ENABLE_SIMDJSON=OFF could not build the test suite at all on main. Under modules the probe is meaningless anyway: the consumer imports the codec rather than including it, so file existence says nothing about availability.

The fix drops the gate. The snapshot-JSON macros are now defined unconditionally, like every other macro in the header — they name ::kota::codec::json, and just as EXPECT_EQ names ::kota::meta::eq, that only has to be visible at the use site. zest.h no longer includes the JSON codec either (zest does not link it). The one suite that uses these macros includes the codec itself, behind a KOTA_TEST_HAS_JSON define that both build systems set when simdjson is enabled — an actual answer to "is the JSON codec available" instead of a guess.

Breaking changes

  • Direct includers of kota/deco/facade/macro.h must switch to kota/deco/macro.h. kota/deco/deco.h consumers are unaffected; in-repo, deco.h was the only includer.
  • TUs that included kota/zest/macro.h and relied on it to supply the zest declarations must include kota/zest/zest.h. Only 3 in-repo TUs were in that position (the other 5 already included both); all 3 are updated here.
  • Code using EXPECT_SNAPSHOT_JSON and relying on zest to auto-include the JSON codec must now include kota/codec/json/json.h itself.

Notes

  • kota::option (include/kota/deco/option/) defines no macros at all — nothing to split there.
  • The three Deco*ResultErrString macros stay in facade/trait.h on purpose: they are static_assert message strings consumed by facade/decl.h inside the library, never by a downstream.
  • kota/support/expected_try.h was already macro-only and include-free — no change needed.
  • The #ifdef __cpp_exceptions gate in zest/macro.h stays: unlike __has_include, that is a genuine property of the TU being compiled.

Testing

  • With simdjson: 943 passed, 1 skipped (+2 vs. base = the two new guard tests).
  • Without simdjson: 410 passed — a configuration that previously failed to compile.
  • Every TU that includes kota/zest/macro.h directly was compile-checked, including the http ones outside the local build config.
  • Compile-checked orderings for deco: macro.h alone, deco.h alone, and macro.h before deco.h.
  • Two new guard tests — tests/unit/deco/macro_standalone.cc and tests/unit/zest/macro_standalone_tests.cpp — each include their macro.h as the very first header, #error if the public macro set is not defined by that header alone, then exercise the macros with the declarations pulled in afterwards.

Possible follow-up (not in this PR)

KOTA_CODEC_TRY lives in kota/codec/visit/context.h, which has 8 includes. If codec is consumed as a module it will need the same treatment.

…macro.h

Modules cannot export macros, so once kotatsu is consumed as a module the
Deco* declaration macros stop being reachable through `import`. They have to
come from a textual include — but the old home, kota/deco/facade/macro.h,
pulled in facade/decl.h and facade/trait.h, which would duplicate the very
declarations the module already provides.

Move the macros up to kota/deco/macro.h, mirroring the kota/zest/macro.h
layout, and drop the deco includes. The expansions only need those names at
the point of use, which either kota/deco/deco.h or the imported module
supplies. The std headers the expansions name (<cstdint>, <string>,
<type_traits>, <vector>) are kept so the header stands on its own next to a
module import.

Downstreams that included kota/deco/facade/macro.h directly must switch to
kota/deco/macro.h; kota/deco/deco.h consumers are unaffected.

kota::option has no macros of its own, so it needs no equivalent header.
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The deco macro header no longer includes internal declaration headers, adds required standard-library includes, and is tested independently. The build publishes the header, while facade include ordering is adjusted.

Changes

Deco macro contract

Layer / File(s) Summary
Macro header contract
include/kota/deco/macro.h, tests/unit/deco/macro_standalone.cc
macro.h now contains only macro definitions and standard-library includes; the standalone test verifies macro availability and CLI parsing with StandaloneCfg.
Facade integration and publication
include/kota/deco/deco.h, xmake.lua
Facade includes are reordered, and kota/deco/macro.h is added to the deco target’s exported headers.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: making kota/deco/macro.h a standalone macro-only header.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/deco-macro-header

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/deco/macro_standalone.cc`:
- Around line 1-16: Make the standalone guard translation unit include only
kota/deco/macro.h before validating the Deco* macro definitions, removing
<string>, <vector>, and kota/deco/deco.h from that guard path. Move macro
expansion/parser behavior into a separate compile-only test that explicitly
includes kota/deco/deco.h.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: aa339b30-2422-4f5b-a884-c4e8ada8262f

📥 Commits

Reviewing files that changed from the base of the PR and between febb730 and 2c92183.

📒 Files selected for processing (4)
  • include/kota/deco/deco.h
  • include/kota/deco/macro.h
  • tests/unit/deco/macro_standalone.cc
  • xmake.lua

Comment thread tests/unit/deco/macro_standalone.cc
Same rationale as the deco split, applied to the header that already had the
layout: a macro header only earns its keep in a module world if it includes
nothing at all. kota/zest/macro.h still pulled in check.h, trace.h, suite.h
and snapshot.h, so a downstream that did `import kota;` alongside it would get
the module's declarations textually duplicated.

Move those four to kota/zest/zest.h, which is where the ~90 test TUs already
point. The conditional codec/json include moves there too; macro.h keeps the
__has_include gate so the snapshot-JSON macros are still defined exactly when
they were, it just no longer performs the include itself.

The three TUs that included kota/zest/macro.h without kota/zest/zest.h now
include the latter. Both macro headers are verified include-free, and a zest
counterpart to the deco guard test locks the contract in.
@16bit-ykiko 16bit-ykiko changed the title refactor(deco): split declaration macros into a standalone kota/deco/macro.h refactor(deco,zest): make macro.h a pure macro header in both libraries Jul 25, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b39f0e01b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread include/kota/deco/macro.h
Comment thread include/kota/zest/macro.h
__has_include("kota/codec/json/json.h") answered the wrong question. That file
ships with kotatsu, so it is on disk whether or not the JSON backend was
actually built — the gate opened unconditionally and then pulled in a header
that hard-errors with "simdjson.h is required for the JSON codec backend".
KOTA_CODEC_ENABLE_SIMDJSON=OFF therefore could not build the test suite at all,
since tests/unit/zest is always compiled. And under modules the probe is
meaningless anyway: the consumer imports the codec rather than including it,
so file existence says nothing about availability.

Drop the gate. The snapshot-JSON macros are now defined unconditionally, like
every other macro in the header — they name ::kota::codec::json, and as with
::kota::meta::eq in EXPECT_EQ, that name only has to be visible where the macro
is used. Using them without the codec is a name-lookup error at the use site,
which is the honest failure.

zest.h no longer includes the JSON codec either; zest does not link it, so
auto-supplying it on the strength of a file-existence probe was the bug. The
one suite that uses these macros now includes the codec itself, behind a
KOTA_TEST_HAS_JSON define that the build systems set when simdjson is enabled —
an actual answer to "is the JSON codec available" rather than a guess.

Verified both ways: with simdjson 943 tests pass (unchanged), and without it
the suite now configures, builds and runs 410 tests where it previously failed
to compile.
@16bit-ykiko
16bit-ykiko merged commit c516e3a into main Jul 25, 2026
33 checks passed
@16bit-ykiko
16bit-ykiko deleted the feat/deco-macro-header branch July 25, 2026 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant