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}