Skip to main content

Crate announce

Crate announce 

Source
Expand description

§announce crate Latest Version Documentation GitHub Actions MSRV

announce

Make a definition visible to proc macros in any crate.

A proc macro only sees the tokens it is applied to. Put #[announce] on a struct, enum, union, trait, type alias or inline mod, and any crate can ask for its tokens: #[announce] keeps the item and emits a macro_rules! with the item’s name, and calling that macro passes the definition to a callback macro.

#[announce::announce]
pub trait Greet { fn hi(&self) -> &'static str; }

macro_rules! show {
    (@announce_format "1" [$($list:tt)*] $($key:ident)::+ ! => [$($meta:tt)*] { $($item:tt)* } $($rest:tt)*) => {
        const SHOWN: &str = stringify!($($item)*);
    };
}
Greet! { [Greet!, show!] }
assert!(SHOWN.contains("trait Greet"));

From another crate the call reads path::to::Greet! { [path::to::Greet!, show!] REST }. The callback receives the definition, and REST unchanged:

show! {
    @announce_format "1"
    [show!]
    path::to::Greet! => [META] { pub trait Greet { fn hi(&self) -> &'static str; } }
    REST
}

META lists what the definer attached (checks, meta entries). Callers and callbacks need no dependency on announce.

Every call that announce makes to the next macro of a chain starts with @announce_format "1", the version of the wire format, before [LIST]. A macro of yours can match it to know that announce called it. A call you write by hand (Greet! { [Greet!, show!] }) needs no prefix:

#[announce::announce]
pub trait Greet { fn hi(&self) -> &'static str; }

macro_rules! who {
    // Called by announce.
    (@announce_format "1" $($call:tt)*) => { const CALLER: &str = "announce"; };
    // Called by hand.
    ($($call:tt)*) => { const CALLER: &str = "hand"; };
}
Greet! { [Greet!, who!] }
assert_eq!(CALLER, "announce");

The prefix is part of the wire format. An item and a macro built with different, incompatible versions of announce stop with one error that names both versions.

§Calling a trampoline

One callback can take many definitions. The list names the trampolines, then the callback, which runs once. A long chain may need a higher recursion_limit (details).

path::Item! { [path::Item!, other::Def!, cb!] REST }

§Features

  • Works in any position: item, statement, expression, type, pattern.
  • Evaluates #[cfg] in the defining crate; crate:: paths keep pointing there.
  • Leaves docs out of the item the callback receives (docs = true keeps them).
  • Checks at the definition, which can own attributes of their own inside the item: #[announce(my_lib::check)].
  • Metadata for consumers: #[announce(meta = my_lib::info(k = v))].
  • Types that are relative to the defining crate: repeater.
  • Transformers chosen by the caller, such as signature_only!.
  • A derive or attribute may own the name: rename the trampoline with macro_name.

All options of #[announce(..)] are in the API docs.

§Crates

crateuse it to
announceeverything below
announce-stdannounce std/core traits (announce_std::iter::Iterator!)

In announce:

  • #[announce] and the trait Announce define announced items.
  • announce::helper writes callbacks and checks, starts chains and redirects derives.
  • announce::machinery announces items that your own proc macro builds.
  • helper, machinery and type_leak need the feature proc-macro-api, on by default; a #![no_std] crate that only defines items uses default-features = false.

announce-core and announce-macros are internal; depend on announce. Minimum Rust version: 1.57.

§Performance

Traits with S methods each, K of them passed to one callback; rustc nightly, dev profile. Lines: color = S (darker is larger), solid = announced or one chain, dashed = plain or K separate calls; both axes logarithmic. Details and how to run it: bench/.

Defining crate: .rmeta size against K Defining crate: rebuild time against K Calling crate: .rmeta size against K Calling crate: rebuild time against K

  • The cost is metadata of the defining crate: about 6 KiB per definition plus copies of the item (one copy for items above about 21 trait methods). Doc comments are not recorded.
  • Executables are unaffected, and calling crates stay small (12–60 KiB of .rmeta at K = 96).
  • [profile.dev.build-override] opt-level = 3 in your workspace builds the proc macros optimized: 1,117 ms becomes 763 ms at S = 200, K = 96.
  • macro_magic has the same core idea. announce adds continuation lists, definition-side cfg evaluation and checks, and type context handling.
  • reify_types makes a definition available when compiled code runs. announce delivers it at compile time.

Re-exports§

pub use type_leak;

Modules§

helper
Helpers for proc-macro crates that use announce trampolines: announce::helper.
machinery
What #[announce(..)] does, as functions that another proc-macro crate can call.

Macros§

define_repeater
Defines the repeater trait that #[announce(repeater = ..)] needs.
signature_only
Transformer that strips the newest entry’s item down to signatures.

Traits§

Announce
Marks an announced item.

Attribute Macros§

announce
Makes an item readable by macros in any crate.