nesting/
lib.rs

1//! # Nested Structs & Enums
2//! This crate allows you to nest structs, enums, and impls, in a way that is similar to how it's done in Zig.
3//!
4//! # Examples
5//!
6//! ```rust
7//!
8//! nesting::nest! {
9//!     // #![] attributes apply to all structs and enums in the nest!{} block.
10//!     #![derive(Debug)]
11//!     // Becomes:
12//!     // #![structs(allow(dead_code))]
13//!     // #![enums(allow(dead_code))]
14//!
15//!     // You can also scope the attributes like so:
16//!     #![all(allow(dead_code))] // using `all` means it will also apply to `impl`s!
17//!     // Which is the same as:
18//!     // #![structs(allow(dead_code))]
19//!     // #![enums(allow(dead_code))]
20//!     // #![impls(allow(dead_code))]
21//!
22//!     pub struct MarkerStruct;
23//!
24//!     struct TupleStruct(String, u32);
25//!
26//!     struct FieldStruct {
27//!         field1: String,
28//!         field2: u32
29//!         child: ChildStruct,
30//!         my_enum: Enum
31//!
32//!         // Loose functions get put into impl StructName {} blocks.
33//!         // i.e. this would be impl FieldStruct { pub fn my_fn() {} }
34//!         pub fn some_struct_fn(&self) {
35//!             println!("This function is nested inside the struct!");
36//!         }
37//!
38//!         // You can add attributes to individual structs/enums/impls as usual
39//!         #[derive(Clone, Hash)]
40//!         struct ChildStruct {
41//!             field1: String,
42//!             field2: u32,
43//!             child: ChildChildStruct
44//!
45//!             // You can nest infinitely...
46//!             #[derive(Clone, Hash)]
47//!             struct ChildChildStruct;
48//!         }
49//!
50//!         impl ChildStruct {
51//!             pub fn some_impl_fn(&self) {
52//!                 println!("This function is nested inside struct->impl");
53//!             }
54//!         }
55//!
56//!         // We can impl Foo for Bar
57//!         impl std::fmt::Display for ChildStruct {
58//!             fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59//!                 write!(f, "{}: {}", &self.field1, self.field2)
60//!             }
61//!         }
62//!
63//!         // We can make enums too
64//!         enum Enum {
65//!             A,
66//!             B(String),
67//!             C {
68//!                 a: String,
69//!                 b: u64,
70//!             }
71//!
72//!             // Nesting works just fine in enums
73//!             #[derive(Default)]
74//!             struct StructInsideEnum(String);
75//!
76//!             enum Enum2 { A, B, C }
77//!
78//!             pub fn some_enum_fn(&self) {
79//!                 println!("This is a function inside an enum!");
80//!             }
81//!         }
82//!     }
83//! }
84//! ```
85
86mod parser;
87
88use proc_macro::TokenStream;
89use quote::quote;
90use syn::parse_macro_input;
91
92/// Create nested structs, enums, and impls.
93///
94/// # Examples
95///
96/// ```rust
97/// nesting::nest! {
98///     struct MyStruct {
99///         child: MyChildStruct
100///
101///         struct MyChildStruct {
102///             is_nested: bool,
103///
104///             impl Default for MyChildStruct {
105///                 fn default() -> Self {
106///                     Self { is_nested: true}
107///                 }
108///             }
109///         }
110///     }
111/// }
112/// ```
113#[proc_macro]
114pub fn nest(input: TokenStream) -> TokenStream {
115    let nest_input = parse_macro_input!(input as parser::NestInput);
116
117    let mut all_items = Vec::new();
118
119    for item_def in nest_input.items {
120        all_items.extend(item_def.flatten());
121    }
122
123    let generated_code = all_items.iter().map(|s| {
124        let global_attrs = &nest_input.global_attrs;
125
126        s.render(global_attrs)
127    });
128
129    let result = quote! {
130        #(#generated_code)*
131    };
132
133    result.into()
134}