multi_structs/
lib.rs

1//! A macro for generating a merged struct from multiple sub-structs.
2//!
3//! # Example
4//!
5//! ```
6//! use multi_structs::multi_structs;
7//!
8//! multi_structs! {
9//!     /// The merged struct.
10//!     #[derive(Debug)]
11//!     pub struct Merged {
12//!         /// Foo
13//!         #[derive(Debug)]
14//!         pub foo: struct Foo {
15//!             /// a
16//!             pub a: i32,
17//!             /// b
18//!             pub b: i64,
19//!         }
20//!         /// Bar
21//!         #[derive(Debug)]
22//!         pub bar: struct Bar {
23//!             /// c
24//!             pub c: usize,
25//!             /// d
26//!             pub d: String,
27//!         }
28//!     }
29//! }
30//!
31//! fn main() {
32//!     let foo = Foo { a: 1, b: 2 };
33//!     let bar = Bar { c: 3, d: "aaa".to_string() };
34//!     println!("{:?}, {:?}", foo, bar);
35//!     let merged = Merged::new(foo, bar);
36//!     println!("{:?}", merged);
37//!     let (foo, bar) = merged.split();
38//!     println!("{:?}, {:?}", foo, bar);
39//! }
40//! ```
41//!
42//! See [`example_generated`](./example_generated/index.html) for
43//! documentation of code generated by the above `multi_structs!`
44//! expansion.
45//!
46//! # Attributes
47//!
48//! Attributes can be attached to any struct and field involved.
49//!
50//! # Methods
51//!
52//! The following methods are defined for the merged struct:
53//!
54//! - `new`: create the new merged struct from multiple sub-structs.
55//! - `split`: split the merged struct into the sub-structs.
56//!
57//! # Visibility
58//!
59//! The visibility of structs and fields is taken directly from their definitions. For the
60//! generated methods `new` and `split`, the visibility of the merged struct is assumed.
61
62#![no_std]
63
64#[cfg(feature = "example_generated")]
65extern crate std;
66
67#[macro_export]
68macro_rules! multi_structs {
69    {
70        $(#[$($meta:tt)+])*
71        $multi_vis:vis struct $name:ident {
72            $(
73                $(#[$($sub_meta:tt)+])*
74                $sub_vis:vis $var:ident: struct $sub:ident {
75                    $(
76                        $(#[$($field_meta:tt)+])*
77                        $field_vis:vis $field:ident: $ty:ty
78                    ),+ $(,)?
79                }
80            )+
81        }
82    } => {
83        $(
84            $(#[$($sub_meta)+])*
85            $sub_vis struct $sub {
86                $(
87                    $(#[$($field_meta)+])*
88                    $field_vis $field: $ty,
89                )+
90            }
91        )+
92
93        $(#[$($meta)+])*
94        $multi_vis struct $name {
95            $(
96                $(
97                    $(#[$($field_meta)+])*
98                    $field_vis $field: $ty,
99                )+
100            )+
101        }
102
103        impl $name {
104            /// Create this struct from sub-structs.
105            $multi_vis fn new(
106                $($var: $sub,)+
107            ) -> Self {
108                Self {
109                    $(
110                        $($field: $var.$field,)+
111                    )+
112                }
113            }
114
115            /// Split this struct into its sub-structs.
116            $multi_vis fn split(self) -> ($($sub,)+) {
117                (
118                    $(
119                        $sub {
120                            $($field: self.$field,)+
121                        },
122                    )+
123                )
124            }
125        }
126    }
127}
128
129#[cfg(feature = "example_generated")]
130pub mod example_generated;