Migrate remaining macro implementations and polish up cgp-macro-core#243
Merged
Conversation
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.
AI Summary
This PR consolidates how CGP's procedural macros are organized and how the code they generate is written, on the branch
migrate-macros-to-core(29 commits). The headline change is that the real code-generation logic for several macros moves out of the thin entrypoint crate (cgp-macro-lib) and into the shared core crate (cgp-macro-core), where the rest of CGP's macro machinery already lives. Alongside that move, the PR retires the Greek-letter type aliases that CGP used to shorten compiler error messages, switches generated code to fully-qualified construct paths, and replaces a large body of hand-written runtime tests with golden snapshot tests.None of these changes alter the public CGP surface that users write against. The macros you invoke —
#[cgp_component],#[cgp_type],#[derive(HasField)],delegate_components!, and the rest — keep the same names and behavior. What changes is the internal structure of the macro implementation, the spelling of the types that appear in compiler output, and the way the generated code references CGP's own constructs.High-Level Concepts
The work is best understood as four parallel threads: relocating macro logic, flattening the entrypoint crate, removing the Greek aliases, and rebuilding the test suite around snapshots. They are independent in intent but were carried out together because they all touch the boundary between
cgp-macro-libandcgp-macro-core.Macro logic moves into
cgp-macro-core. Previously, the generation logic for the data macros (#[derive(HasField)],#[derive(HasFields)],#[derive(CgpData)], the builder and extractor derives) and for#[cgp_type]lived insidecgp-macro-lib. This PR moves that logic intocgp-macro-coreunder new modules —types/cgp_data(withrecord,variant, anditemsubmodules),types/cgp_type,types/product, andtypes/sum. The move is built around two new abstractions,ItemCgpTypeandItemCgpRecord, that model a parsed macro input as a structured item that knows how to emit its own generated items. After the move,cgp-macro-libkeeps only a thin wrapper per macro that forwards to the core implementation.The entrypoint crate is flattened.
cgp-macro-libused to nest every macro entry point under anentrypoints/subdirectory and re-export them through a singlepub use crate::entrypoints::*. This PR dissolves that subdirectory: each macro now lives in a top-level module (cgp_component,cgp_fn,delegate_components, and so on) re-exported directly fromlib.rs. The crate's role narrows to being the proc-macro-facing veneer overcgp-macro-core.Greek-letter aliases are removed. CGP historically defined its type-level constructs under Greek names —
Consasπ,Nilasε,Symbolasψ,Charsasζ,Eitherasσ,Voidasθ,Indexasδ, and others — so that deeply nested type-level lists and strings would print more compactly in compiler errors. This PR deletes those aliases and defines each construct directly under its real, readable name. The prelude stops re-exporting the Greek symbols, and the macros now emit the plain names. Error messages get longer but immediately legible, trading compactness for clarity.Generated code becomes fully qualified. The macros now refer to CGP's own constructs through fully-qualified paths rather than relying on whichever names happen to be imported at the call site. To support this, the macro core's
export_constructs!list is expanded substantially — addingVoid,Either,Field, the full family of data traits (HasFields,FromFields,ExtractField,HasBuilder, and so on), and theUseType/TypeProvider/WithProviderproviders — so every construct the generated code might reference has a canonical export to point at.Structural Changes
The crate layout gains one new crate and reorganizes two existing macro crates. A new
cgp-base-extracrate is added to the workspace (registered in both the rootCargo.tomlmembers list and the workspace dependency table). It re-exportsbase_types,component, and thecgp-typeconstructs, and exposes amacro_preludemodule that gathers the type-level exports macros need to resolve their fully-qualified references. The existingcgp-basecrate is extended to re-exportcgp-base-typesasbase_typesandcgp-componentascomponent, giving the generated code stable module paths to anchor on.Within
cgp-macro-core, the newtypes/cgp_data,types/cgp_type,types/product, andtypes/summodules absorb the migrated logic, andtypes/mod.rsis updated to declare them. TheSymbolparser in the macro core is reworked to parse a string literal directly (storing the value as aStringplus aSpan) instead of consuming anIdent, which makesSymbol!("...")parsing more robust. Withincgp-macro-lib, theentrypoints/andtype_component/directories are deleted and their surviving contents promoted to top-level modules.The test suite is restructured from runtime assertions into golden snapshots. The
HasFieldandHasFieldstests are removed fromcrates/tests/cgp-tests/src/tests/and reborn undercrates/tests/cgp-tests/tests/extensible_data_tests/, where they capture the macros' generated output inline via theinstasnapshot crate. This is backed by three new snapshot macros in the test-util crate —snapshot_derive_has_field!,snapshot_derive_has_fields!, andsnapshot_derive_cgp_data!— documented in an expandedcgp-macro-test-utilREADME. The growth in test line counts (for example, thehas_field/chaintests expand from roughly 300 to 600+ lines) reflects the golden output now being checked in alongside each test.Impacts
The changes are overwhelmingly internal, but they ripple outward in a few visible ways. The list below frames each impact and who it affects; nothing here requires action from code that simply uses CGP through the documented macros.
Cons,Nil,Symbol,Chars,Either,Index) instead of Greek letters. Errors become more readable but visually longer. Anyone who had learned to recognizeπ/ε/ψin diagnostics will see the spelled-out forms instead.δ,ε,ζ,θ,π,σ,ψ,ω) will no longer find them. This is the one change that could break downstream code, though such direct use was always unusual — these were display conveniences, not the documented API.cgp-base-extracrate joins the workspace. It is a small re-export and macro-prelude crate that underpins the fully-qualified code generation. Workspace builds will compile one additional crate.cgp_preset,cgp_inherit,re_export_imports,replace_with, andtype_componentmodules are deleted fromcgp-macro-lib. These were not exposed as public proc macros on either branch, so their removal is dead-code cleanup with no user-facing effect.cgp-macro-corebeside the rest of the machinery, future changes touch one crate rather than two, andcgp-macro-libshrinks to a predictable set of thin forwarding wrappers.Symbol!parsing is sturdier. Parsing a string literal directly removes the previous dependency on the input tokenizing as an identifier, which makes symbol construction more predictable for unusual field names.