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}