1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! Compiled examples are in the [repository](https://github.com/tigerros/dry-mods/tree/master/examples).

#![warn(clippy::cargo)]
#![warn(clippy::pedantic)]
#![warn(clippy::style)]
#![warn(clippy::nursery)]
#![no_std]
#![no_main]

/// Flexible and powerful module declarations.
///
/// # Syntax
/// There's three different patterns the macro matches against:
/// - Define modules and use the contents (`::*`).
/// - Define modules.
/// - Use the contents of modules that are already in scope.
/// - Use the contents of modules that are in a root module.
/// For example, `crate::{mod1, mod2}` instead of `crate::mod1, crate::mod2`.
///
/// After each pattern, you can type a semicolon (`;`) and make another one!
///
/// # Examples
/// This showcases each of the three patterns:
/// ```rust,ignore
/// dry_mods::mods! {
///     // `foo` and `bar` will be defined with the `pub(crate)` visibility but the contents will be completely public.
///     pub(crate) mod pub use foo, bar;
///     // `baz` is totally private, but the contents are exposed in the module where `mods!` was called.
///     use baz;
///     // `my_mod` is now a public module.
///     pub mod my_mod;
///     // Use the root module for crate internals.
///     pub(crate) use crate::{int1, int2, int3, int4, int5};
/// }
///
/// // Generates:
///
/// pub(crate) mod foo;
/// pub(crate) mod bar;
/// pub use foo::*;
/// pub use bar::*;
/// use baz::*;
/// pub mod my_mod;
/// pub(crate) crate::{int1::*, int2::*, int3::*, int4::*, int5::*};
/// ```
#[macro_export]
macro_rules! mods {
    () => {};

    ($mod_vis:vis mod $use_vis:vis use $($module:ident),+; $($rest:tt)*) => {
        $($mod_vis mod $module;)+
        $($use_vis use $module::*;)+
        ::dry_mods::mods! { $($rest)* }
    };

    ($mod_vis:vis mod $($module:ident),+; $($rest:tt)*) => {
        $($mod_vis mod $module;)+
        ::dry_mods::mods! { $($rest)* }
    };

    // No root.
    ($use_vis:vis use $($mod_path:path),+; $($rest:tt)*) => {
        $($use_vis use $mod_path::*;)+
        ::dry_mods::mods! { $($rest)* }
    };

    // Yes root.
    ($use_vis:vis use $root:ident::{$($mod_path:path),+}; $($rest:tt)*) => {
        $($use_vis use $root::{$mod_path::*};)+
        ::dry_mods::mods! { $($rest)* }
    };
}

/// Generates a `prelude` module with some uses.
///
/// # Syntax
/// At the start of each pattern, you can add attributes that will then be added to the `prelude`
/// module. You can also write documentation!
///
/// There's three different patterns the macro matches against.
/// "use" means "use in the `mod prelude`".
/// - Define modules in the file and use the contents (`::*`).
/// This will use `super::mod_name` to get the modules in the file.
/// - Use the contents of modules that are already in scope.
/// - Use the contents of modules that are in a root module.
/// For example, `crate::{mod1, mod2}` instead of `crate::mod1, crate::mod2`.
///
/// After each pattern, you can type a semicolon (`;`) and make another one!
///
/// # Examples
/// This showcases each of the three patterns:
/// ```rust,ignore
/// mod internal1 {
///     pub(crate) fn int1() {}
/// }
///
/// mod internal2 {
///     pub(crate) fn int2() {}
/// }
///
/// dry_mods::prelude! {
///     // `foo` and `bar` will be public modules and their contents will also be public.
///     /// Re-exports some commonly used modules.
///     pub mod pub use foo, bar;
///     // `internal1` and `internal2` will only be visible within the crate.
///     // We don't use `mod` here, because they are already defined.
///     pub(crate) use crate::{internal1, internal2};
/// }
///
/// // Generates:
///
/// pub mod foo;
/// pub mod bar;
/// #[doc = " Re-exports some commonly used modules."]
/// pub mod prelude {
///     pub use super::foo::*;
///     pub use super::bar::*;
///     pub(crate) use crate::{internal1::*, internal2::*};
/// }
/// ```
#[macro_export]
macro_rules! prelude {
    () => {};

    // Using modules in the prelude by prepending "U="
    (U=) => {};

    // No use root.
    (U=$vis:vis use $($mod_path:path),+; $($rest:tt)*) => {
        $($vis use $mod_path::*;)+
        ::dry_mods::prelude! { U=$($rest)* }
    };

    // Yes use root.
    (U=$vis:vis use $root:ident::{$($mod_path:path),+}; $($rest:tt)*) => {
        $vis use $root::{$($mod_path::*,)+};
        ::dry_mods::prelude! { U=$($rest)* }
    };

    // Prelude, mod and use.
    ($(#[$attr:meta])* $mod_vis:vis mod $use_vis:vis use $($module:ident),+; $($rest:tt)*) => {
        $($mod_vis mod $module;)*
        $(#[$attr])
        *
        $use_vis mod prelude {
            $($use_vis use super::$module::*;)*
            ::dry_mods::prelude! { U=$($rest)* }
        }
    };

    // Prelude, use without root.
    ($(#[$attr:meta])* $use_vis:vis use $($mod_path:path),+; $($rest:tt)*) => {
        $(#[$attr])
        *
        $use_vis mod prelude {
            $($use_vis use $mod_path::*;)+
            ::dry_mods::prelude! { U=$($rest)* }
        }
    };

    // Prelude, use with root.
    ($(#[$attr:meta])* $use_vis:vis use $root:ident::{$($mod_path:path),+}; $($rest:tt)*) => {
        $(#[$attr])
        *
        $use_vis mod prelude {
            $($use_vis use $root::{$mod_path::*};)+
            ::dry_mods::prelude! { U=$($rest)* }
        }
    };
}