Attribute for defining `macro_rules!` macros with proper visibility and scoping

Overview

macro-vis

This crate provides an attribute for defining macro_rules! macros that have proper visibility and scoping.

The default scoping and publicity rules of macro_rules! macros are arcane and confusing: they behave like no other item in the Rust programming language, and introduce several frustrating limitations that are hard to work around. This problem will be eventually fixed by a new kind of macro known as declarative macros 2.0, but that feature has been stuck in limbo for several years now and likely won't be seen on stable Rust for several years more.

So that's where this crate comes in. It allows you to place #[macro_vis] or #[macro_vis(VISIBILITY)] on any macro_rules! macro and have it be treated exactly like any other item that supports a visibility modifier - structs, enums, functions, et cetera. It works with both crate-local and public macros, effectively superseding both #[macro_use] and #[macro_export].

See the documentation of #[macro_vis] for examples and usage.

The uncommon_codepoints warning

You will get the uncommon_codepoints warning if you use this library, so you will probably want to place this in your crate root:

#![allow(uncommon_codepoints)]

Documenting public macros

The documentation of public macros can be slightly improved if run on a Nightly compiler. To enable this, you must first add this attribute to your crate root:

#![cfg_attr(doc_nightly, feature(decl_macro, rustc_attrs))]

Then you can build with the doc_nightly cfg set, either locally with RUSTDOCFLAGS="--cfg doc_nightly" cargo +nightly doc or on docs.rs by adding this to your Cargo.toml:

[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "doc_nightly"]

How it works

The trick to get non-pub macros working is simple; we just use the macro after its definition to get it to be treated like an item. The original macro is renamed to a randomly-generated identifier so it can't be accessed by regular code. This code:

#[macro_vis(pub(crate))]
macro_rules! example_macro { () => {}; }

Gets expanded to something like:

macro_rules! __example_macro_2994407750278293171 { () => {}; }
pub(crate) use __example_macro_2994407750278293171 as example_macro;

pub macros work the same, but apply #[macro_export] to the macro and ensure it doesn't show up in the documentation:

#[doc(hidden)]
#[macro_export]
macro_rules! __example_macro_2994407750278293171 { () => {}; }
pub use __example_macro_2994407750278293171 as example_macro;

But because a re-export of a #[doc(hidden)] item is itself #[doc(hidden)], the macro doesn't show up in the documentation at all. To solve this, the library employs two solutions depending on whether Nightly is available or not:

  • When doc_nightly is not enabled, the library emits a public function whose name is the macro name concatenated with LATIN LETTER RETROFLEX CLICK (ǃ), a character that looks nearly identical to the exclamation mark used to invoke macros. This is done to avoid name collisions between other functions of the same name and the macro's documentation double. However, it has the flaw of causing the macro to appear as a function in the docs even though it isn't, and it doesn't work well with re-exports.

  • When doc_nightly is enabled, the library instead changes the macro to be a macros 2.0-style pub macro which obeys proper visibility rules by default. Unlike the previous solution, this one displays the macro in the correct documentation section and with the correct text color, as well as it working properly with inlined re-exports. The drawback is that it doesn't work on stable, and so has a greater risk of breaking in future.

MSRV

This crate's minimum supported Rust version is 1.53, the first version to stabilize non_ascii_idents. It is currently considered a breaking change to increase this.

Credit

Most of the ideas in this crate were discovered and shown to me by Daniel Henry-Mantilla, so much of the credit goes to them.

License: MIT

You might also like...
This blog provides detailed status updates and useful information about Theseus OS and its development

The Theseus OS Blog This blog provides detailed status updates and useful information about Theseus OS and its development. Attribution This blog was

Omeglib, a portmanteau of "omegle" and "library", is a crate for interacting with omegle, simply and asynchronously

Omeglib, a portmanteau of "omegle" and "library", is a crate for interacting with omegle, simply and asynchronously. It is intended to suit one's every requirement regarding chat on omegle.

Fast and simple datetime, date, time and duration parsing for rust.

speedate Fast and simple datetime, date, time and duration parsing for rust. speedate is a lax† RFC 3339 date and time parser, in other words, it pars

In this repository you can find modules with code and comments that explain rust syntax and all about Rust lang.
In this repository you can find modules with code and comments that explain rust syntax and all about Rust lang.

Learn Rust What is this? In this repository you can find modules with code and comments that explain rust syntax and all about Rust lang. This is usef

A tool and library to losslessly join multiple .mp4 files shot with same camera and settings

mp4-merge A tool and library to losslessly join multiple .mp4 files shot with same camera and settings. This is useful to merge multiple files that ar

A tray application for Windows that gives you push notifications and instant downloads of new posts, messages and stories posted by models you subscribe to on Onlyfans.

OF-notifier A tray application for Windows that gives you push notifications and instant downloads of new posts, messages and stories posted by models

A simpler and 5x faster alternative to HashMap in Rust, which doesn't use hashing and doesn't use heap

At least 5x faster alternative of HashMap, for very small maps. It is also faster than FxHashMap, hashbrown, ArrayMap, and nohash-hasher. The smaller

A comprehensive and FREE Online Rust hacking tutorial utilizing the x64, ARM64 and ARM32 architectures going step-by-step into the world of reverse engineering Rust from scratch.
A comprehensive and FREE Online Rust hacking tutorial utilizing the x64, ARM64 and ARM32 architectures going step-by-step into the world of reverse engineering Rust from scratch.

FREE Reverse Engineering Self-Study Course HERE Hacking Rust A comprehensive and FREE Online Rust hacking tutorial utilizing the x64, ARM64 and ARM32

Leetcode Solutions in Rust, Advent of Code Solutions in Rust and more

RUST GYM Rust Solutions Leetcode Solutions in Rust AdventOfCode Solutions in Rust This project demostrates how to create Data Structures and to implem

Owner
null
A Rust attribute macro that adds memoization to a function (rhymes with Mickey)

michie (sounds like Mickey) — an attribute macro that adds memoization to a function. Table of contents Features Non-features key_expr key_type store_

Mobus Operandi 16 Dec 20, 2022
A Rust crate providing utility functions and macros.

介绍 此库提供四类功能:异常处理、http post收发对象、格式转换、语法糖。 在 Cargo.toml 里添加如下依赖项 [dependencies.xuanmi_base_support] git = "https://github.com/taiyi-research-institute/x

null 17 Mar 22, 2023
Linux daemon to bind keys and macros to your controller's buttons

makima Makima is a daemon for Linux to bind your controller's buttons to key sequences and macros. Features: Configure your keybindings through a simp

null 48 Jun 14, 2023
Learn to write Rust procedural macros [Rust Latam conference, Montevideo Uruguay, March 2019]

Rust Latam: procedural macros workshop This repo contains a selection of projects designed to learn to write Rust procedural macros — Rust code that g

David Tolnay 2.5k Dec 29, 2022
Lightweight parsing for Rust proc macros

Lightweight parsing for Rust proc macros Venial is a WIP parser for Rust proc macros. When writing proc macros that need to parse Rust code (such as a

Olivier FAURE 148 Dec 30, 2022
Proc-macros for generating icons from the Iconify API

iconify-rs This crate provides a macro to embed SVGs from Iconify. For a list of icons, see Iconify Icon Sets. ?? Usage let svg = iconify::svg!("mdi:h

Matthew Taylor 5 Jul 9, 2023
Tiny macros for bailing on failure

tiny_bail Bailing is an error-handling pattern that takes the middle path between unwrap and ?: Compared to unwrap: Bail will return, continue, or bre

Ben Frankel 22 Sep 10, 2024
An API for getting questions from http://either.io implemented fully in Rust, using reqwest and some regex magic. Provides asynchronous and blocking clients respectively.

eithers_rust An API for getting questions from http://either.io implemented fully in Rust, using reqwest and some regex magic. Provides asynchronous a

null 2 Oct 24, 2021
Safe, efficient, and ergonomic bindings to Wolfram LibraryLink and the Wolfram Language

wolfram-library-link Bindings to the Wolfram LibraryLink interface, making it possible to call Rust code from the Wolfram Language. This library is us

Wolfram Research, Inc. 28 Dec 6, 2022