mods/lib.rs
1//! Simpler module declaration, brought to you by [@NikolaiVazquez]!
2//!
3//! This library enables you to declare modules in ways the current syntax
4//! doesn't allow.
5//!
6//! # Examples
7//!
8//! To declare multiple public modules, simply place `pub` before a module list:
9//!
10//! ```rust,ignore
11//! mods::mods! {
12//! pub puppy, kitty;
13//! }
14//! ```
15//!
16//! This works for all visibility modifiers:
17//!
18//! ```rust,ignore
19//! mods::mods! {
20//! pub a, b; // Visible anywhere, even outside the module
21//! pub(crate) c, d; // Visible anywhere within the crate
22//! pub(super) e, f; // Visible to the parent module
23//! g, h; // Visible to the current module
24//! }
25//! ```
26//!
27//! Without the `mods!` macro, the same code is much less succinct. This is what
28//! the macro expands out to:
29//!
30//! ```rust,ignore
31//! pub mod a;
32//! pub mod b;
33//! pub(crate) mod c;
34//! pub(crate) mod d;
35//! pub(super) mod e;
36//! pub(super) mod f;
37//! mod g;
38//! mod h;
39//! ```
40//!
41//! # Installation
42//!
43//! This crate is available [on crates.io][crate] and can be used by adding the
44//! following to your project's [`Cargo.toml`]:
45//!
46//! ```toml
47//! [dependencies]
48//! mods = "1.0.0"
49//! ```
50//!
51//! ## Minimum Supported Rust Version (MSRV)
52//!
53//! This library requires Rust 1.9.0 as the minimum version and will work with
54//! all subsequent versions.
55//!
56//! This is because previous versions can't have `mod x;` declarations within
57//! submodules [When testing this](https://github.com/nvzqz/mods/runs/508242550)
58//! we get an error complaining that the module file is not inside the directory
59//! "src".
60//!
61//! ## Rust 2015
62//!
63//! If you're not using [Rust 2018], add this to your crate root (`main.rs` or
64//! `lib.rs`):
65//!
66//! ```rust,ignore
67//! #[macro_use]
68//! extern crate mods;
69//! ```
70//!
71//! You can then use the macro directly from anywhere:
72//!
73//! ```rust,ignore
74//! mods! {
75//! pub puppy, kitty;
76//! }
77//! ```
78//!
79//! # Wishful Thinking
80//!
81//! It would be wonderful if we could instead have:
82//!
83//! ```rust,ignore
84//! pub mod puppy, kitty;
85//! ```
86//!
87//! Or a syntax that matches `use` imports:
88//!
89//! ```rust,ignore
90//! pub mod {puppy, kitty};
91//! ```
92//!
93//! # Changes
94//!
95//! See [`CHANGELOG.md`] for an exhaustive list of what has changed from one
96//! version to another.
97//!
98//! # License
99//!
100//! This project is released under either:
101//!
102//! - [MIT License](https://github.com/nvzqz/mods/blob/master/LICENSE-MIT)
103//! - [Apache License (Version 2.0)](https://github.com/nvzqz/mods/blob/master/LICENSE-APACHE)
104//!
105//! # Donate
106//!
107//! This project is made freely available (as in free beer), but unfortunately
108//! not all beer is free! So, if you would like to buy me a beer (or coffee or
109//! *more*), then consider supporting my work that's benefited your project
110//! and thousands of others.
111//!
112//! <a href="https://www.patreon.com/nvzqz">
113//! <img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patron!" height="35">
114//! </a>
115//! <a href="https://www.paypal.me/nvzqz">
116//! <img src="https://buymecoffee.intm.org/img/button-paypal-white.png" alt="Buy me a coffee" height="35">
117//! </a>
118//!
119//! [@NikolaiVazquez]: https://twitter.com/NikolaiVazquez
120//! [`Cargo.toml`]: https://doc.rust-lang.org/cargo/reference/manifest.html
121//! [`CHANGELOG.md`]: https://github.com/nvzqz/mods/blob/master/CHANGELOG.md
122//! [crate]: https://crates.io/crates/mods
123//! [Rust 2018]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html#rust-2018
124
125#![no_std]
126#![warn(missing_docs)]
127
128/// Declares modules simply.
129///
130/// # Examples
131///
132/// To declare multiple public modules, simply place `pub` before a module list:
133///
134/// ```rust,ignore
135/// mods::mods! {
136/// pub puppy, kitty;
137/// }
138/// ```
139///
140/// This works for all visibility modifiers:
141///
142/// ```rust,ignore
143/// mods::mods! {
144/// pub a, b; // Visible anywhere, even outside the module
145/// pub(crate) c, d; // Visible anywhere within the crate
146/// pub(super) e, f; // Visible to the parent module
147/// g, h; // Visible to the current module
148/// }
149/// ```
150///
151/// Without the `mods!` macro, the same code is much less succinct. This is what
152/// the macro expands out to:
153///
154/// ```rust,ignore
155/// pub mod a;
156/// pub mod b;
157/// pub(crate) mod c;
158/// pub(crate) mod d;
159/// pub(super) mod e;
160/// pub(super) mod f;
161/// mod g;
162/// mod h;
163/// ```
164///
165/// # Wishful Thinking
166///
167/// It would be wonderful if we could instead have:
168///
169/// ```rust,ignore
170/// pub mod puppy, kitty;
171/// ```
172///
173/// Or a syntax that matches `use` imports:
174///
175/// ```rust,ignore
176/// pub mod {puppy, kitty};
177/// ```
178#[macro_export]
179macro_rules! mods {
180 () => {};
181
182 // Trailing comma
183 (pub $($module:ident,)+; $($rest:tt)*) => {
184 $(pub mod $module;)+
185 mods! { $($rest)* }
186 };
187 (pub($vis:ident) $($module:ident,)+; $($rest:tt)*) => {
188 $(pub($vis) mod $module;)+
189 mods! { $($rest)* }
190 };
191 (pub(in $vis:path) $($module:ident,)+; $($rest:tt)*) => {
192 $(pub(in $vis) mod $module;)+
193 mods! { $($rest)* }
194 };
195 ($($module:ident,)+; $($rest:tt)*) => {
196 $(mod $module;)+
197 mods! { $($rest)* }
198 };
199
200 // No trailing comma
201 (pub $($module:ident),+; $($rest:tt)*) => {
202 $(pub mod $module;)+
203 mods! { $($rest)* }
204 };
205 (pub($vis:ident) $($module:ident),+; $($rest:tt)*) => {
206 $(pub($vis) mod $module;)+
207 mods! { $($rest)* }
208 };
209 (pub(in $vis:path) $($module:ident),+; $($rest:tt)*) => {
210 $(pub(in $vis) mod $module;)+
211 mods! { $($rest)* }
212 };
213 ($($module:ident),+; $($rest:tt)*) => {
214 $(mod $module;)+
215 mods! { $($rest)* }
216 };
217}
218
219#[cfg(test)]
220mod tests;