auto_delegate_macros/
lib.rs

1use proc_macro::TokenStream;
2
3use ::syn::__private::TokenStream2;
4
5use crate::delegate_trait::expand_delegate_trait;
6use crate::derive_delegate::expand_derive_delegate;
7
8mod derive_delegate;
9mod delegate_trait;
10mod ident;
11mod macro_marker;
12mod span;
13mod syn;
14mod trait_item;
15mod attribute;
16
17
18/// The trait given this attribute are eligible for delegation.
19///
20/// ```rust
21/// use auto_delegate::delegate;
22///
23/// #[delegate]
24/// pub trait Readable{
25///     fn read(&self) -> String;
26/// }
27/// ```
28#[proc_macro_attribute]
29pub fn delegate(attr: TokenStream, input: TokenStream) -> TokenStream {
30    let output: proc_macro2::TokenStream = expand_delegate_trait(attr, input.clone());
31    expand_join(input, output)
32}
33
34
35/// Implement the specified trait and delegate its processing to the children.
36///
37///
38/// ## Note
39///
40/// The trait to be delegated must be given a 'delegate'.
41///
42///
43/// ## Example1:
44///
45/// ```rust
46/// use auto_delegate::*;
47///
48/// #[delegate]
49/// trait Calc {
50///     fn calc(&self, x1: usize, x2: usize) -> usize;
51/// }
52///
53/// #[derive(Default)]
54/// struct CalcAdd;
55///
56/// impl Calc for CalcAdd {
57///     fn calc(&self, x1: usize, x2: usize) -> usize {
58///         x1 + x2
59///     }
60/// }
61///
62/// #[derive(Delegate, Default)]
63/// struct Parent {
64///     #[to(Calc)]
65///     child: CalcAdd
66/// }
67///
68/// let parent =  Parent::default();
69///
70/// assert_eq!(parent.calc(3, 2), 5);
71/// ```
72///
73///
74/// ## Example2: Generics-type Child
75///
76/// It is possible to use generic type for member types
77///
78/// ```rust
79/// use auto_delegate::*;
80///
81/// #[delegate]
82/// trait Calc {
83///     fn calc(&self, x1: usize, x2: usize) -> usize;
84/// }
85///
86/// #[derive(Default)]
87/// struct CalcAdd;
88///
89///
90/// impl Calc for CalcAdd {
91///     fn calc(&self, x1: usize, x2: usize) -> usize {
92///         x1 + x2
93///     }
94/// }
95///
96///
97/// #[derive(Default, Delegate)]
98/// struct Parent<T: Default + Calc>{
99///     #[to(Calc)]
100///     child: T
101/// }
102///
103///
104/// let parent = Parent::<CalcAdd>::default();
105///
106/// assert_eq!(parent.calc(3, 2), 5);
107/// ```
108///
109/// ## Example3: Multiple traits and fields
110///
111/// It is possible to use generic param for member types
112///
113/// ```rust
114/// use auto_delegate::*;
115///
116/// #[delegate]
117/// trait Calc {
118///     fn calc(&self, x1: usize, x2: usize) -> usize;
119/// }
120///
121///
122/// #[derive(Default)]
123/// struct CalcAdd;
124///
125///
126/// impl Calc for CalcAdd {
127///     fn calc(&self, x1: usize, x2: usize) -> usize {
128///         x1 + x2
129///     }
130/// }
131///
132///
133/// #[delegate]
134/// trait Movable{
135///     fn move_to(&mut self, pos: (usize, usize));
136///
137///     fn pos(&self) -> (usize, usize);
138/// }
139///
140///
141/// #[delegate]
142/// trait Resizable{
143///     fn resize(&mut self, width: usize, height: usize);
144///
145///     fn size(&self) -> (usize, usize);
146/// }
147///
148///
149/// #[derive(Default)]
150/// struct Transform2D{
151///     pos: (usize, usize),
152///     width: usize,
153///     height: usize
154/// }
155///
156///
157/// impl Movable for Transform2D {
158///     fn move_to(&mut self, pos: (usize, usize)) {
159///         self.pos = pos;
160///     }
161///
162///     fn pos(&self) -> (usize, usize) {
163///         self.pos
164///     }
165/// }
166///
167///
168/// impl Resizable for Transform2D{
169///     fn resize(&mut self, width: usize, height: usize) {
170///         self.width = width;
171///         self.height = height;
172///     }
173///
174///     fn size(&self) -> (usize, usize){
175///         (self.width, self.height)
176///     }
177/// }
178///
179/// #[derive(Default, Delegate)]
180/// struct Parent<T: Default + Calc>{
181///     #[to(Movable, Resizable)]
182///     transform: Transform2D,
183///
184///     #[to(Calc)]
185///     calculator: T
186/// }
187///
188///
189/// let mut parent = Parent::<CalcAdd>::default();
190///
191/// assert_eq!(parent.calc(3, 2), 5);
192///
193/// parent.move_to((10, 11));
194/// assert_eq!(parent.pos(), (10, 11));
195///
196/// parent.resize(100, 120);
197/// assert_eq!(parent.size(), (100, 120));
198/// ```
199///
200/// ## Example4: Enum
201///
202///
203/// ```rust
204/// use auto_delegate::{delegate, Delegate};
205///
206/// #[delegate]
207/// trait Calc {
208///     fn calc(&self, x1: usize, x2: usize) -> usize;
209/// }
210///
211///
212/// #[derive(Default)]
213/// struct CalcAdd;
214///
215///
216/// impl Calc for CalcAdd {
217///     fn calc(&self, x1: usize, x2: usize) -> usize {
218///         x1 + x2
219///     }
220/// }
221///
222///
223/// #[derive(Default)]
224/// struct CalcSub;
225///
226///
227/// impl Calc for CalcSub {
228///     fn calc(&self, x1: usize, x2: usize) -> usize {
229///         x1 - x2
230///     }
231/// }
232///
233///
234/// #[derive(Delegate)]
235/// #[to(Calc)]
236/// enum EnumCalc {
237///     Add(CalcAdd),
238///     Sub(CalcSub),
239/// }
240///
241///
242/// let c = EnumCalc::Add(CalcAdd::default());
243/// assert_eq!(c.calc(3, 5), 8);
244///
245/// let c = EnumCalc::Sub(CalcSub::default());
246/// assert_eq!(c.calc(3, 2), 1);
247/// ```
248///
249#[proc_macro_derive(Delegate, attributes(to))]
250pub fn derive_delegate(input: TokenStream) -> TokenStream {
251    expand_derive_delegate(input).into()
252}
253
254
255fn expand_join(input: TokenStream, output: proc_macro2::TokenStream) -> TokenStream {
256    let input = proc_macro2::TokenStream::from(input);
257
258    let expand = quote::quote! {
259        #input
260        #output
261    };
262
263    expand.into()
264}
265
266
267pub(crate) fn intersperse(
268    separator: TokenStream2,
269    iter: impl Iterator<Item=TokenStream2>) -> Vec<TokenStream2> {
270    let mut tokens = Vec::<TokenStream2>::new();
271    for token in iter{
272        tokens.push(token);
273        tokens.push(separator.clone());
274    }
275
276    if !tokens.is_empty() {
277        tokens.remove(tokens.len() - 1);
278    }
279
280    tokens
281}