quoted! covers all three recording vocabularies - #766
Closed
0-jake-0 wants to merge 2 commits into
Closed
Conversation
The previous arms handled a plain closure. That left the *interesting*
case — a per-instrument parameter — needing the manual three-line form,
which is exactly backwards: the shorthand worked for the easy case and not
for the one the generator exists to serve.
One rule now covers everything, marked in the argument list:
map(|x| ..) records the closure
map([fee] move |x| ..) the closure and the captured value
ticker(cfg period) the data config
fold(cfg 0u64, |a, v| ..) both
join(&other, |x, y| ..) the closure; `&other` is an edge
So a per-instrument leg reads without leaving the macro:
let ticks = quoted!(g => ticker(cfg inst.tick)).count();
let px = quoted!(ticks => map(|n: &u64| *n as f64));
let net = quoted!(px => map([fee] move |p: &f64| p - fee));
`cfg` also removes a redundancy worth naming: `ticker(p).with_cfg(&p)`
wrote the value twice, so it could be forgotten in one place or — worse —
changed in one place.
Two implementation notes:
- **Arm order is load-bearing.** Each arm is discriminated by a *literal*
token (`cfg`, `[`) before any fragment is parsed, and the arms are
ordered most-specific first. `macro_rules!` falls through cleanly on a
literal mismatch, but a failed `$x:expr` parse is a hard error rather
than a fallthrough — so an arm that could swallow another's input has to
come second.
- A `cfg`-marked argument is **cloned** into the call so the original can
be rendered. Every `EmitLiteral` type is `Clone`, and for the common
`Copy` ones (`Duration`, numbers) the clone is free.
Still not detected: an *undeclared* capture. `map(move |p| p - fee)`
without `[fee]` records a body that will not resolve in an artifact. It
surfaces as a generator refusal — or, if the name happens to resolve to
something else at the splice site, as a pass-2 compile error.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X4eojqRWBJ6uK5v5JDzmkd
`ticker`'s parameter is `period: Duration` — an interval between synthetic ticks. In a trading context a "tick" is a price increment (tick size) or a single market-data update, and neither is a `Duration`, so an `Instrument` field called `tick` reads as the wrong thing entirely to the audience most likely to read these tests. The doc comment also records why the field exists at all, which is the more useful correction: it is there because `ticker` stands in for a market-data feed. A real instrument config carries a symbol and a subscription, and data arrives when it arrives. `external`/`channel` sources are still excluded from compiled graphs, so the placeholder is load-bearing for the test rather than representative of the domain — worth saying, so nobody reads these fixtures as a suggested config shape. Test-only rename plus a doc example; no behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X4eojqRWBJ6uK5v5JDzmkd
This was referenced Aug 8, 2026
Contributor
Author
|
Superseded by #769, and like #765 not carried forward — Closing. Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #765 → #764 → #763 → #762 → #761 → #760 → #759. Base is
quoted-macro; this diff is only the top commit.What this changes
quoted!previously handled a plain closure. That left the interesting case — a per-instrument parameter — needing the manual three-linefunc!+.with_src()form, which is exactly backwards: the shorthand worked for the easy case and not for the one the generator exists to serve.One rule now covers everything, marked in the argument list:
map(|x| ..)map([fee] move |x| ..)ticker(cfg period)fold(cfg 0u64, |a, v| ..)join(&other, |x, y| ..)&otheris an edge, left aloneSo a per-instrument leg reads without leaving the macro:
cfgalso removes a redundancy worth naming on its own:ticker(p).with_cfg(&p)wrote the value twice, so it could be forgotten in one place or — worse — changed in one place.How it was verified
cargo fmt --allcargo lint✅ —cargo lint-allnot run:--all-featurescannot build here (aeron needs CMake ≥3.30, box has 3.28; etcd needs protoc). Documented prerequisites, unrelated to this diff; CI is the first real check on that feature set.--all-featuresblocked as above. Full default suite plusbench,async,csv,cache,augurs,market,ws,redis,postgres,kafka,web,kdb,prometheus,fix,dynamic-graph,tracing— green. Doctests green (16 passed).Twelve tests, one per arm plus the composite. Two assert the shorthand records byte-identically to the manual form, so it stays a convenience rather than a second mechanism. The last one builds a two-instrument desk and asserts no node with a closure config is left unrecorded — which is the property a user actually cares about, rather than any individual arm working.
Notes for the reviewer
Arm order is load-bearing, and the reason is a
macro_rules!sharp edge. Each arm is discriminated by a literal token (cfg,[) before any fragment is parsed, and arms run most-specific first.macro_rules!falls through cleanly on a literal mismatch, but a failed$x:exprparse is a hard error, not a fallthrough — so an arm that could swallow another's input has to come second. The comment in the macro says this, because the ordering looks arbitrary otherwise and would be "tidied" into breakage.A
cfg-marked argument is cloned into the call so the original survives to be rendered. EveryEmitLiteraltype isClone, and for the commonCopyones (Duration, numbers) the clone compiles away.Still not detected: an undeclared capture.
map(move |p| p - fee)without[fee]records a body that will not resolve in an artifact. It surfaces as a generator refusal — or, if the name happens to resolve to something else at the splice site, as a pass-2 compile error. That is the one remaining hole in the quotation story, and closing it needs the fn-pointer coercion §3 specifies, which cannot be written arity-generically.One doctest caught me: the markdown pipe-escaping (
\|) needed for the table leaked into the adjacent code block, so the example was invalid Rust until the doctest run caught it. Worth knowing if you add rows to that table.Stack: nine PRs, none reviewed, eight chained on #759.
Generated by Claude Code