layered_crate/lib.rs
1#![doc = include_str!("../README.md")]
2
3use proc_macro::TokenStream;
4use syn::parse_macro_input;
5
6mod graph;
7mod import;
8mod layers;
9
10/// See [`crate documentation`](crate)
11#[proc_macro_attribute]
12pub fn layers(_attr: TokenStream, input: TokenStream) -> TokenStream {
13 let input = parse_macro_input!(input as syn::ItemMod);
14 match layers::expand(input) {
15 Ok(expanded) => expanded,
16 Err(err) => err.to_compile_error().into(),
17 }
18}
19
20/// The import attribute will transform a `use` item to use
21/// `self` and `crate` to refer to the current module and its dependencies
22/// as defined by the [`#[layers]`](crate) attribute.
23///
24/// # Example
25/// Assuming we organize our imports in the following order:
26/// - std
27/// - external dependencies
28/// - dependencies within our crate
29///
30/// ```rust,ignore
31/// use std::fs::File;
32/// // .. other std dependencies
33///
34/// use serde_json::Value;
35/// // .. other external dependencies
36///
37/// #[layered_crate::import]
38/// use my_layer::{
39/// // ^ `my_layer` refers to the current layer as defined in lib.rs
40/// super::my_dep::MyType,
41/// // ^ `super` in this context is used to refer to this layer's dependencies
42/// // the above is equivalent to `use crate::my_dep::MyType`,
43/// // but only works if `my_dep` is declared as a dependency
44/// super::{
45/// my_other_dep::MyOtherType,
46/// my_more_dep::MyMoreType,
47/// },
48/// // ^ other forms work as well
49/// MyDepInThisLayer, // ... import rest from the current layer
50///
51/// self::MyTypeInThisLayer,
52/// // ^ you can also use `self` to refer to the current module
53/// // if you prefer
54///
55/// };
56///
57/// // any item outside of the macro isn't transformed, and you can
58/// // use this to bypass the layer restrictions
59/// use crate::unchecked;
60///
61/// // if you actually need to import from `super`, also put it
62/// // outside
63/// use super::*;
64/// ```
65///
66/// # Other checks
67/// - It will make sure all of your `super` and `self` (imports from current layer) are grouped
68/// together for readability
69/// - If you actually want to group the imports in another way, consider
70/// using multiple `import` attributes
71/// - It will make sure imports from the current layer either all use `self`
72/// or not use `self` for consistency, the `self` import by itself is always allowed
73#[proc_macro_attribute]
74pub fn import(_attr: TokenStream, input: TokenStream) -> TokenStream {
75 let input = parse_macro_input!(input as syn::ItemUse);
76 match import::expand(input) {
77 Ok(expanded) => expanded,
78 Err(err) => err.to_compile_error().into(),
79 }
80}