Skip to content

fix(aop): advice/pointcut macros generate valid Rust + uppercase aliases#67

Open
ViewWay wants to merge 1 commit into
mainfrom
fix/aop-macros-valid-rust
Open

fix(aop): advice/pointcut macros generate valid Rust + uppercase aliases#67
ViewWay wants to merge 1 commit into
mainfrom
fix/aop-macros-valid-rust

Conversation

@ViewWay

@ViewWay ViewWay commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes the broken hiver-aop API that made it unusable from downstream crates.

Root cause

The published 0.1.0-alpha.6 was unusable: every advice/pointcut macro emitted
impl #func_name { ... } where #func_name is a function, not a type. This
broke in every context:

  • inside an impl Aspect { #[before] ... } block →
    error: implementation is not supported in traits or impls
  • on a free #[before] fn free_advice()
    error[E0573]: expected type, found function free_advice

Additionally, the runtime type re-export was previously gated behind
#[cfg(not(proc_macro))] (now removed), so hiver_aop::JoinPoint was not
reachable downstream, and the README used uppercase Spring-style macro names
(Aspect/Before/...) that were never exported.

The fix

The macros now emit the annotated fn unchanged plus a uniquely-named
companion const recording the pointcut expression and advice kind:

#[before("execution(* *..*.*(..))")]
fn log_before(&self, jp: &JoinPoint) { ... }
// expands to:
const _HIVER_BEFORE_LOG_BEFORE_META: (&'static str, &'static str) =
    ("execution(* *..*.*(..))", "before");

A bare const (not a nested impl) is valid Rust both at module scope and
inside an impl block, so advice now works in both contexts.

Changes

Area Change
hiver-aop-macros/src/advice.rs All 5 advice macros emit fn + companion const via a shared expand_advice helper; removed invalid impl #func_name
hiver-aop-macros/src/pointcut.rs Same companion-const fix
hiver-aop/src/lib.rs Re-export uppercase aliases (Aspect/Before/After/Around/AfterReturning/AfterThrowing/Pointcut) so the README import shape compiles
hiver-aop/README.md Rewritten to the real, compiling API + a "Pointcut expressions in Rust" section (no JVM package semantics)
Doc comments advice.rs/pointcut.rs/aspect.rs/runtime.rs/lib.rs examples updated to compile-ready shape
hiver-aop/tests/ New trybuild regression suite: free-fn advice (pass), impl-block advice (pass — the original failing case), uppercase aliases (pass), wrong-macro-name (compile_fail)
examples/logging_aspect.rs Re-enabled (was .disabled) as a buildable, runnable example
hiver-aop-macros/README.md NewCargo.toml referenced ./README.md but it was missing, which blocked cargo package/publish

Verification

  • Both exact reproductions from issue hiver-aop README/API example does not compile from downstream crates #60 now cargo check from a fresh
    downstream crate (uppercase aliases inside impl block, and lowercase free fn).
  • cargo test -p hiver-aop -p hiver-aop-macros: 56 unit tests + 1 trybuild
    suite (4 cases) + 2 compiled doc-tests
    all pass.
  • cargo run -p hiver-aop --example logging_aspect runs end-to-end.
  • cargo +nightly fmt -p hiver-aop -p hiver-aop-macros -- --check: clean.
  • cargo clippy introduces no new warnings (pre-existing unwrap_used warnings
    in untouched runtime.rs registry code are out of scope).

Note on releasing

This PR does not bump the version (per discussion). The fix lives in-repo;
shipping it to crates.io is a separate tag-triggered release.yml step. Note
that hiver-aop-macros must be published before hiver-aop (the latter
declares a version dependency on the former).

Out of scope

Dependabot PRs (#64/#65/#66) and the dependency-update issue #16 are unrelated
dependency bumps and are not addressed here.

The published hiver-aop 0.1.0-alpha.6 was unusable from downstream crates
(#60, #61): every advice/pointcut macro emitted `impl #func_name { ... }`
where `#func_name` is a *function*, not a type. This produced:

  - inside an `impl` block:
      error: implementation is not supported in traits or impls
  - on a free function:
      error[E0573]: expected type, found function <name>

Fix: the macros now emit the annotated `fn` unchanged plus a uniquely-named
companion `const _HIVER_<KIND>_<NAME>_META: (&str, &str) = (pointcut, kind)`.
A bare `const` (not a nested `impl`) is valid Rust both at module scope and
inside an `impl` block, so advice now works in both contexts.

Also:
- Re-export Spring-familiar uppercase aliases (Aspect/Before/After/Around/
  AfterReturning/AfterThrowing/Pointcut) so the README import shape compiles.
- Rewrite README + doc examples to the real, compiling API (lowercase macros,
  JoinPoint/ProceedingJoinPoint in scope, Rust pointcut semantics instead of
  JVM package patterns).
- Add trybuild regression tests covering free-fn advice, impl-block advice
  (the original failing case), uppercase aliases, and a compile_fail fixture.
- Re-enable examples/logging_aspect.rs as a buildable, runnable example.
- Add hiver-aop-macros/README.md (Cargo.toml referenced it but it was missing,
  which blocked `cargo package`/publish).

Verified: both #60 reproductions now `cargo check` from a fresh downstream
crate; all 56 unit tests, 4 trybuild cases, and 2 compiled doc-tests pass;
nightly `cargo fmt --check` and clippy clean for the touched crates.

Fixes #60
Fixes #61
@github-actions

Copy link
Copy Markdown

📦 Public API Changes

No public API changes.

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.

[Bug] https://crates.io/crates/hiver-aop 用不了 hiver-aop README/API example does not compile from downstream crates

1 participant