dry_mods/
lib.rs

1#![doc = include_str!("../README.md")]
2
3#![warn(clippy::cargo)]
4#![warn(clippy::pedantic)]
5#![warn(clippy::style)]
6#![warn(clippy::nursery)]
7#![no_std]
8#![no_main]
9
10/// Flexible and powerful module declarations.
11///
12/// # Syntax
13/// There's three different patterns the macro matches against:
14/// - Define modules and use the contents (`::*`).
15/// - Define modules.
16/// - Use the contents of modules that are already in scope.
17/// - Use the contents of modules that are in a root module.
18/// For example, `crate::{mod1, mod2}` instead of `crate::mod1, crate::mod2`.
19///
20/// After each pattern, you can type a semicolon (`;`) and make another one!
21///
22/// # Examples
23/// This showcases each of the three patterns:
24/// ```rust,ignore
25/// dry_mods::mods! {
26///     // `foo` and `bar` will be defined with the `pub(crate)` visibility but the contents will be completely public.
27///     pub(crate) mod pub use foo, bar;
28///     // `baz` is totally private, but the contents are exposed in the module where `mods!` was called.
29///     use baz;
30///     // `my_mod` is now a public module.
31///     pub mod my_mod;
32///     // Use the root module for crate internals.
33///     pub(crate) use crate::{int1, int2, int3, int4, int5};
34/// }
35///
36/// // Generates:
37///
38/// pub(crate) mod foo;
39/// pub(crate) mod bar;
40/// pub use foo::*;
41/// pub use bar::*;
42/// use baz::*;
43/// pub mod my_mod;
44/// pub(crate) crate::{int1::*, int2::*, int3::*, int4::*, int5::*};
45/// ```
46#[macro_export]
47macro_rules! mods {
48    () => {};
49
50    ($mod_vis:vis mod $use_vis:vis use $($module:ident),+; $($rest:tt)*) => {
51        $($mod_vis mod $module;)+
52        $($use_vis use $module::*;)+
53        ::dry_mods::mods! { $($rest)* }
54    };
55
56    ($mod_vis:vis mod $($module:ident),+; $($rest:tt)*) => {
57        $($mod_vis mod $module;)+
58        ::dry_mods::mods! { $($rest)* }
59    };
60
61    // No root.
62    ($use_vis:vis use $($mod_path:path),+; $($rest:tt)*) => {
63        $($use_vis use $mod_path::*;)+
64        ::dry_mods::mods! { $($rest)* }
65    };
66
67    // Yes root.
68    ($use_vis:vis use $root:ident::{$($mod_path:path),+}; $($rest:tt)*) => {
69        $($use_vis use $root::{$mod_path::*};)+
70        ::dry_mods::mods! { $($rest)* }
71    };
72}
73
74/// Generates a `prelude` module with some uses.
75///
76/// # Syntax
77/// At the start of each pattern, you can add attributes that will then be added to the `prelude`
78/// module. You can also write documentation!
79///
80/// There's three different patterns the macro matches against.
81/// "use" means "use in the `mod prelude`".
82/// - Define modules in the file and use the contents (`::*`).
83/// This will use `super::mod_name` to get the modules in the file.
84/// - Use the contents of modules that are already in scope.
85/// - Use the contents of modules that are in a root module.
86/// For example, `crate::{mod1, mod2}` instead of `crate::mod1, crate::mod2`.
87///
88/// After each pattern, you can type a semicolon (`;`) and make another one!
89///
90/// # Examples
91/// This showcases each of the three patterns:
92/// ```rust,ignore
93/// mod internal1 {
94///     pub(crate) fn int1() {}
95/// }
96///
97/// mod internal2 {
98///     pub(crate) fn int2() {}
99/// }
100///
101/// dry_mods::prelude! {
102///     // `foo` and `bar` will be public modules and their contents will also be public.
103///     /// Re-exports some commonly used modules.
104///     pub mod pub use foo, bar;
105///     // `internal1` and `internal2` will only be visible within the crate.
106///     // We don't use `mod` here, because they are already defined.
107///     pub(crate) use crate::{internal1, internal2};
108/// }
109///
110/// // Generates:
111///
112/// pub mod foo;
113/// pub mod bar;
114/// #[doc = " Re-exports some commonly used modules."]
115/// pub mod prelude {
116///     pub use super::foo::*;
117///     pub use super::bar::*;
118///     pub(crate) use crate::{internal1::*, internal2::*};
119/// }
120/// ```
121#[macro_export]
122macro_rules! prelude {
123    () => {};
124
125    // Using modules in the prelude by prepending "U="
126    (U=) => {};
127
128    // No use root.
129    (U=$vis:vis use $($mod_path:path),+; $($rest:tt)*) => {
130        $($vis use $mod_path::*;)+
131        ::dry_mods::prelude! { U=$($rest)* }
132    };
133
134    // Yes use root.
135    (U=$vis:vis use $root:ident::{$($mod_path:path),+}; $($rest:tt)*) => {
136        $vis use $root::{$($mod_path::*,)+};
137        ::dry_mods::prelude! { U=$($rest)* }
138    };
139
140    // Prelude, mod and use.
141    ($(#[$attr:meta])* $mod_vis:vis mod $use_vis:vis use $($module:ident),+; $($rest:tt)*) => {
142        $($mod_vis mod $module;)*
143        $(#[$attr])
144        *
145        $use_vis mod prelude {
146            $($use_vis use super::$module::*;)*
147            ::dry_mods::prelude! { U=$($rest)* }
148        }
149    };
150
151    // Prelude, use without root.
152    ($(#[$attr:meta])* $use_vis:vis use $($mod_path:path),+; $($rest:tt)*) => {
153        $(#[$attr])
154        *
155        $use_vis mod prelude {
156            $($use_vis use $mod_path::*;)+
157            ::dry_mods::prelude! { U=$($rest)* }
158        }
159    };
160
161    // Prelude, use with root.
162    ($(#[$attr:meta])* $use_vis:vis use $root:ident::{$($mod_path:path),+}; $($rest:tt)*) => {
163        $(#[$attr])
164        *
165        $use_vis mod prelude {
166            $($use_vis use $root::{$mod_path::*};)+
167            ::dry_mods::prelude! { U=$($rest)* }
168        }
169    };
170}