Skip to content

Repository files navigation

Macroonz

Macroonz — Bake. Build. Delight.

Code generation that can prove what it made, and a test harness that tries to break it.

Ferris bakes macaroons here. Every batch starts from a written recipe, every tray is checked against that recipe before it leaves the oven, and a taste tester with no loyalty to the baker gets the first bite.

Macroonz knows nothing about your domain. Your types, your errors, your identities, your bounds — all yours. It only knows how to bake exactly what you asked for, and how to find out whether it's any good.


Why

Writing a derive macro means parsing a token stream, emitting another one, and hoping. Nobody can say afterwards what was generated, why, or what would change it. Testing a library means writing the examples you thought of. The bug is in the one you didn't.

Macroonz replaces both hopes with records.

You have You get
A derive that emits tokens An expansion that names every unit it produced, proves the set matches its plan, and explains each decision — before a byte reaches rustc
A handful of example tests Generated inputs, injected faults, a controlled clock, mutants of your own code, and the reproduction material each road earns — generation keeps its seed when generation drove the run, reduction mints the smallest witness it reached, and the replay capsule carries it

The bakery

One storefront opens onto the oven, the hand that loads it, and the taste tester without pouring their vocabularies into one bowl.

Crate Directory What it is
macroonz / The storefront exposing the one recipe! workflow entrance while preserving the expert owners as compiler, macros, and feature-gated harness modules; this is the crate you add.
macroonz-compiler macros/compiler/ The ordinary callable compiler that informs structural declarations, projects requested ordinary Rust or evidence material, then plans, renders, closes, explains, binds, and emits.
macroonz-macros macros/proc/ The grammar-free procedural host carrying the recipe entrance and built-in declarations through compiler-owned doors with token conversion, span custody, diagnostic placement, and emission.
macroonz-harness harness/ The judge. Descriptors, generation, properties, oracles, faults, corpus, fuzz composition, mutation, benches, reports, replay. The default storefront includes it; the diet posture removes it from a shipping graph.
flowchart LR
    accTitle: Macroonz package dependencies
    accDescr: The macroonz facade depends on the compiler and procedural macro crates, the procedural macro crate also depends on the compiler, and the optional harness feature adds the harness crate.

    YOU["your crate"] --> F["macroonz"]
    F --> C["macroonz-compiler"]
    F --> PROC["macroonz-macros"]
    PROC --> C
    F -. harness feature .-> H["macroonz-harness"]
Loading

Arrows point at dependencies. The compiler depends on nothing in this workspace. The proc crate reaches the harness only from its tests, and the harness reaches the compiler only from its tests.


Your recipe, your kinds

macroonz::recipe! is the one workflow entrance for declaring ordinary Rust ingredients, structural relationships and postures, effects, and requested projections. The recipe vocabulary describes only the structure Macroonz must account over; complete authored Rust items remain authored Rust rather than becoming a parallel framework AST.

You own every name, item, vocabulary, relation, effect, policy, lawful answer, exact Rust fragment, requested projection, and independent behavioral claim. Macroonz owns bounded capture, structural informing, exact accounting, mechanical projection, and the generation road that proves the requested output set was delivered whole. Rustc remains the authority for paths, visibility, types, ownership, borrowing, lifetimes, coherence, exhaustiveness, const evaluation, and the final legality of the emitted Rust.

An ordinary Rust path is enough when Macroonz only needs to refer to a type, trait, function, effect, constructor, constant, module, associated item, or earlier generated item. An explicit roster is required only when Macroonz must enumerate members or prove that every member received one disposition.

Authored items remain where they were written. Generated companions remain inside the recipe module, private support remains in one hidden child, and public names, visibility, destinations, reexports, and unsafe boundaries remain explicit caller choices. Within one recipe, Macroonz preflights every generated name it can derive from the declaration in the Rust namespace where that name will live: the baked module, companion constants and dispatch functions, relation-table and evidence modules, codec and transition refusal types, typestate, and an explicitly addressed support macro. A collision inside that declared universe refuses the request before partial output, while imports, glob results, downstream macro output, and names generated by another recipe invocation remain ordinary rustc name-resolution authority. No ambient scan or cross-recipe registry is performed, and no ordinary generated item is sprayed into the crate root or reexported automatically.

An evidence bake may carry an explicitly named support macro because Rust exports such macros at the declaring crate root. That caller-authored address is the exception rather than an automatic reexport: its cargo stays inert until the external test or bench target invokes it with the declaring-crate path. The root macroonz::support! entrance selects the facade's harness gate; the explicit carrier entrance also accepts a target-selected gate path.

The compiler's recipe home owns the exact contract for declaration_conformance; and compile_contract;. Use a caller-authored harness property, oracle, or model comparison when judgment must be independent of the declaration.

The generic shape is ordinary Rust plus only the accounts a projection needs:

macroonz::recipe! {
    pub mod access {
        pub enum Stage { Draft, Published }
        pub enum Capability { Read, Write }

        bake! {
            vocabularies { Stage; Capability; };
            relations {
                policy(Stage, Capability) {
                    (Draft, Read);
                    (Published, Read);
                };
            };
            postures {
                policy { repetition(refused); };
            };
            projections {
                companions;
                relation_tables { policy; };
                typestate(Stage);
            };
        }
    }
}

The relation remains a structural account: Macroonz knows that each endpoint belongs to its declared roster and that repetition is refused, but it does not know what a stage, capability, or allowed policy means. The preset relation table projects baked::policy::contains(&Stage, &Capability), so ordinary code can use that checked account without rebuilding its membership loop. Payload-bearing relations require an exact caller-authored lookup signature because the payload type remains caller authority; Macroonz supplies only the row-accounted Some or None body. A same-roster evolution graph, a labeled many-to-many matrix, and a codec-only record use this same recipe entrance without pretending to be transitions. When a recipe names codecs, those declarations select the existing compiler codec owner and its canonical methods rather than a parallel recipe encoding system. When the ergonomic transition spelling is used, it lowers into one typed generic relation and unlocks the transition-specific dispatch projector.

One bake request admits progressively more precision without changing semantic models:

  • A conventional bake supplies documented mechanical choices.
  • A configured bake replaces named mechanical seats.
  • An exact bake supplies caller-authored Rust for those same seats.
  • A caller-owned projector consumes the same informed account and constrained output protocol through the callable compiler or a caller-owned proc host.

Projection syntax follows one grammar across the catalog:

dispatch; // documented conventional mechanics
dispatch(apply); // one flat configured name
dispatch {
    /// Applies one caller-declared transition or returns typed absence.
    pub fn advance(
        current: State,
        event: Event,
    ) -> Result<State, TransitionRefusal>;
}; // exact caller-authored Rust; Macroonz supplies only the checked body

Parentheses carry flat configuration names; braced seats carry the role's explicit bindings or exact Rust material. An exact dispatch signature remains caller-authored Rust, including additional parameters when dispatch(state_binding, event_binding) { exact signature }; selects the two bindings consumed by the generated match. The compiler's projection disclosure contract owns the exact-signature rules. The standard projector owns the complete row-accounted match; individual rows may carry exact behavior through with(target) { exact Rust }, while a custom whole-function body belongs on the custom-projector road.

Two values for one seat refuse. Semantic postures are stated once in the structural account and consumed by every projector that needs them. Safe presets emit safe Rust, while an exact caller-authored unsafe boundary may be preserved or repeated only as explicit caller authority.

The callable compiler module remains the raw road for defining a new kind, grammar, or projection algorithm. Its Kind and Request vocabulary exposes the same plan, render, closure, explanation, and expansion owners beneath the paved recipe surface rather than a second compiler model.


The road

Every request walks the same eight steps, whatever the kind. Each step hands the next a value it cannot forge.

flowchart LR
    accTitle: Compiler request road
    accDescr: Every request proceeds from account through intent, context, plan, render, close, explain, and bind in that order.

    A["1 · account"] --> I["2 · intent"] --> X["3 · context"] --> P["4 · plan"]
    P --> R["5 · render"] --> CL["6 · close"] --> E["7 · explain"] --> B["8 · bind"]
Loading
  1. Account. The kind-specific content bound to its exact captured declaration and owner-qualified kind, plus every independent captured dependency it declares.
  2. Intent. What it means: an identity over the owner-qualified kind and content commitment. Two callers who meant the same thing derive the same intent.
  3. Context. Which profile and which generator version are answering.
  4. Plan. The complete output set, named before a byte of syntax exists — each unit's role, semantic key, destination, origin, expected profile, and digest contract — plus the invalidation set, the decision trace, and the nonclaims.
  5. Render. Typed tokens into rendered units, each digested over its own canonical bytes.
  6. Close. The membership is rebuilt from what was rendered and proved equal to the plan, role by role. The units are partitioned by the destination each one declared.
  7. Explain. Every question the kind owes is answered once, over that plan and that closure, under an identity derived from both.
  8. Bind. Plan, closure, and explanation are sealed together, after the compiler establishes that the three name one another.

The sealed expansion is the one value emission is read from. emit() hands a proc macro its tokens; a test carrier, a bench carrier, or a publication step reads its own partition from the same value.

A request that cannot walk the whole road is refused whole. There is no partial output. A refusal is never a smaller success.

Expansion is a function of its declared input. No network, no filesystem scan, no environment, no clock, no entropy — there is no seat where one could enter.


The taste test

You describe a subject once: what it takes, what it returns, what it refuses, what must hold. The harness hands you the instruments — each independently callable, composed by your own tests rather than by one button:

  • Generates inputs against the description, structure-aware, from a seed it records.
  • Injects faults on a declared schedule, and measures against a clock the caller declares, so the subject is judged under pressure and not on a sunny day.
  • Reduces a failure to the smallest witness reached under the declared reducers and budget, and mints a replay capsule over it.
  • Observes stable-Rust targets compiled with rustc coverage instrumentation through the pinned toolchain's matching LLVM tools, retains coverage-novel bytes, and hands them into that same reduction and replay road.
  • Mutates the subject's own code and runs the trials against each mutant, to prove the trials can tell right from wrong.
  • Benchmarks with the same receiver and the same pinned profile, so a number means the same thing tomorrow.
  • Reports each verdict with its standing, its site, and its complete denominator — joined to its replay capsule, where a reduction earned one, on one execution key.

Descriptors, trials, mutations, and benches live in your tests — written through the generic macroonz::macros attributes, through your own attributes, or by hand. The harness owns how they are judged, never what they mean. The stable coverage path remains one-package usage through macroonz::harness::fuzz; its fuzz home owns the runnable facade example and command.


Getting started

  1. Pick a posture from The three postures.
  2. Add macroonz with that command.
  3. Start with macroonz::recipe!, or follow the compiler README when you need a caller-owned projection algorithm.
  4. Use the harness directly or through an evidence bake when an independent judgment is part of the recipe.

Runnable examples cross distinct public roads:

Journey Command What it establishes
First recipe cargo run --example recipe --no-default-features Generated lookups, codecs and dispatch execute independent expected values and absent-case controls.
Structural posture choices cargo run --example recipe_postures --no-default-features Every relation posture admits lawful rows and refuses contradictions through the callable facade.
Declared codecs cargo run --example codec_workflow --no-default-features Member shapes, direction choices and checked assembly agree with independent bytes and refuse malformed input.
Declared network and command orders cargo run --example schedule_workflow --no-default-features --features harness Network faults and concurrency execute exact deliveries, expose and replay a caller-owned counterexample, and preserve sampled and exhaustive evidence.
Ordinary and shadow synchronization Build and run the same adopter under both configurations Generated imports connect caller-owned increments to ordinary execution and bounded Loom exploration, exposing a lost update and checking a separate repair.
Consuming transitions cargo run --example consuming_workflow --no-default-features Owned resources and checked restoration through caller-declared runtime validation and effects.
Reusable admitted types cargo run --example admitted_types --no-default-features Reusable patterns render nominal wrappers with caller-owned admission, bounds, visibility and encoding choices.
Declared typed trials cargo run --example trial_workflow --features harness Co-located bindings and typed input execute through table-derived selection and versioned mechanical defaults, displaying complete results and an independent disagreement in JSON, Markdown and HTML.
Job declarations and independent checks cargo run --example job_workflow --no-default-features --features harness Structural methods and unit-input trials share one recipe while caller-authored checks and text suite selection retain the complete denominator.
Retained input and fresh replay cargo run --example retained_workflow --features native-tooling with explicit stdin actions An independent failure reduces to a reached witness, crosses bounded storage, and is replayed against separately selected current code.
Job work-count replay cargo run --example job_retained --no-default-features --features native-tooling with explicit stdin actions The Job count law reduces to a retained witness and executes it in a fresh process without reduction, preserving a separate lawful control.
Callable compiler cargo run -p macroonz-compiler --example callable_compiler One public compiler request plans, renders, closes, explains, binds, and emits a unit.
Direct handwritten property cargo run -p macroonz-harness --example temporal_property Caller-owned state and transitions enter a temporal contract without a macro or subject trait.
Exact compile contract cargo run --example compile_contract A caller-stated compiler observation is compared with an independently declared exact outcome.
Real compiler and read-back cargo run --example compiler_workflow --features native-tooling with explicit stdin configuration A selected rustc builds a binary whose actual read-back is compared with an independent expected count.
Job compiler fixtures cargo run --example job_compiler --no-default-features --features native-tooling with explicit Cargo configuration The Job declaration crosses a caller crate boundary, executes an independent lawful assertion and refuses a wrong state at an exact diagnostic anchor.
Job reader coverage cargo run --example job_coverage --no-default-features --features native-tooling with explicit Cargo configuration The record reader retains independently expected novel inputs, refuses exhausted budgets and attributes every reported point to the selected fixture.
Stable coverage composition cargo run --example rustc_coverage Stable rustc instrumentation supplies source-region novelty to corpus, reduction, and replay composition.
Bounded native coverage cargo run --example coverage_workflow --features native-tooling with explicit stdin configuration Instrumented compilation, matching LLVM execution and corpus replay use bounded native processes.
Retained native mutation cargo run --example mutation_workflow --features native-tooling with explicit stdin configuration A selected backend executes, retains its original command/source manifest and compares historical source claims with current files.
Independent mutation assessment cargo run --example mutation_assessment --features native-tooling with explicit stdin actions Actual unchanged and mutated programs supply observations for independent weak and strong witnesses, followed by an unadmitted proposal, bounded historical retention and current-binding replay of the saved result.
Generated structural mutations Generate a selected source, then execute compiler_workflow Codec, transition and effect alternatives compile and disagree with unchanged, independently authored checks.
Declared enum mutation Run the library-and-consumer example Attribute and recipe carriers preserve generated order alternatives and withhold an unpermitted discovered point.
Generated publication cargo run --example publication_workflow --features native-tooling with explicit stdin configuration One registered generator prepares, optionally formats, privately compiles, installs and checks its complete owned output.
Shared definition publication cargo run --example job_publication --no-default-features --features native-tooling with explicit stdin configuration A shared macro and its sites retain complete destination checks while independent compiled assertions expose changed values.
Retained benchmark cargo run --example benchmark_workflow --features native-tooling Real counted work and an executed worse control enter a complete benchmark report and bounded historical storage.

The compile-contract example is intentionally the pure comparison half. The optional native compiler host executes explicitly configured rustc or Cargo fixtures, extracts structured diagnostics and connects compiled read-back to those same comparators.

For a specific task, start at its owner:

Task Start here
Write a recipe clause or configure a projection Recipe clause forms
Generate consuming phase methods over caller-owned resources Consuming transitions
Reuse checked newtype construction or typed fixture registration Source patterns
Replace a projection algorithm Callable projector
Define a kind, role or complete disposition set Kind
Publish a shared macro definition and its adoption sites Runnable publication
Compose generated tokens or preserve exact authored Rust Token generation
Generate canonical encode and decode methods Codec
Declare trial, benchmark or mutation material Descriptor adapter
Invoke deferred test or benchmark cargo through macroonz::support! Support carrier
Add an independent judgment Handwritten property or Oracle
Replay a retained witness against current code Saved-witness execution and Historical comparison
Execute declared input, retain a complete run and replay saved witnesses Root workflow
Inspect or override versioned resource defaults Mechanical configuration
Display complete results and owner-specific failures as JSON, Markdown or HTML Presentation and Executable trial display
Run a benchmark and retain every reached outcome Benchmark workflow
Execute compiler fixtures and compare exact diagnostics or compiled values Native compiler fixtures
Execute coverage campaigns with bounded native tools and declared source roots Native coverage
Execute mutations and retain source/version/command custody Native mutation
Generate, format, check or recover owned published files Publication commands
Interpret a refusal and its location Diagnostic

The shipped Macroonz agent skill is a one-page routing surface for agents authoring recipes from the packaged facade.

Contribution procedure lives in CONTRIBUTING.md. Security reporting lives in SECURITY.md.


The three postures

Cargo features are additive, so the lighter postures are selected by turning off the default before adding back only the door wanted.

Posture Command Surface
full cargo add macroonz Recipe entrance, compiler, proc declarations, harness, and the target-qualified preemption backend as the default posture.
diet-lite cargo add macroonz --no-default-features --features harness Recipe entrance, compiler, proc declarations, and harness without Loom.
diet cargo add macroonz --no-default-features Recipe entrance, compiler, and proc declarations; harness-owned evidence bakes are typed unavailable.

The preemption feature always implies harness. The harness feature also supplies macroonz::support!, root input execution, composing the existing decoder and complete-table runner, and record presentation. On a native target supported by the pinned Loom backend, enabling preemption installs that backend. On every other target, including Wasm, the same harness result plane remains available and reports typed backend unavailability instead of trying to compile Loom.

The optional native-tooling feature adds the root native clock source, bounded native storage, native process execution, compiler fixtures, native coverage, native mutation and publication commands, and implies harness without enabling preemption. It is independent of the default full posture. Pass macroonz::native_clock::source() to an existing harness runner or benchmark when native measurement is wanted; the harness retains its existing clock and measurement contracts.


Working here

AGENTS.md is the working law for anyone — person, model, or agent — who edits this repository, and it owns what enforcement means here. CONTRIBUTING.md owns the exact local wall rather than duplicating a second command surface here. That wall exercises every feature together, including the target-qualified Loom-backed preemption exploration, and crosses the supported Wasm posture separately. The pinned stable Rust 1.98 toolchain also installs llvm-tools-preview, whose matching llvm-profdata and llvm-cov binaries read profiles for the safe-Rust fuzz composition road.


License

Licensed under either of Apache License, Version 2.0 or MIT license, at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

Safe Rust metaprogramming and adversarial testing: typed code generation with receipts, proc macros, generated trials, mutation, replay, and reproducible evidence.

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages