1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use proc_macro2::TokenStream; |
4 | use quote::{format_ident, quote}; |
5 | use syn::{Fields, FieldsNamed, FieldsUnnamed, Ident, Type}; |
6 | |
7 | use crate::utils::crate_ident_new; |
8 | |
9 | /// Parts needed to derive Downgrade and Upgrade implementation. |
10 | pub struct DowngradeStructParts { |
11 | /// Inner part of weak type declaration |
12 | pub weak_fields: TokenStream, |
13 | /// Term needed to finish declaration. It is usually blank but is `;` for tuple structs. |
14 | pub end_of_struct: TokenStream, |
15 | /// Destructuring pattern |
16 | pub destruct: TokenStream, |
17 | /// Downgrade code |
18 | pub downgrade: TokenStream, |
19 | /// Upgrade code |
20 | pub upgrade: TokenStream, |
21 | } |
22 | |
23 | /// This function generates parts needed to derive Downgrade and Upgrade |
24 | /// implementations. |
25 | /// |
26 | /// # Example |
27 | /// |
28 | /// Let's assume following types are declared. |
29 | /// |
30 | /// ```rust,ignore |
31 | /// struct Unnamed(X, Y); |
32 | /// |
33 | /// struct Named { |
34 | /// x: X, |
35 | /// y: Y, |
36 | /// } |
37 | /// |
38 | /// enum Choice { |
39 | /// This(X, Y), |
40 | /// That { x: X, y: Y }, |
41 | /// } |
42 | /// ``` |
43 | /// |
44 | /// ## weak_fields |
45 | /// |
46 | /// For the struct `Unnamed` and for a enum's variant `Choice::This` |
47 | /// it will be `(<X as Downgrade>::Weak, <Y as Downgrade>::Weak)`. |
48 | /// For the struct `Named` and for a enum's variant `Choice::That` |
49 | /// it will be `{ x: <X as Downgrade>::Weak, y: <Y as Downgrade>::Weak, }`. |
50 | /// |
51 | /// ## end_of_struct |
52 | /// |
53 | /// It is a semicolon (`;`) for an `Unnamed` and is blank for the rest. |
54 | /// |
55 | /// ## destruct |
56 | /// |
57 | /// For the struct `Unnamed` and for a enum's variant `Choice::This` |
58 | /// it will be `(ref _0, ref _1)`. |
59 | /// For the struct `Named` and for a enum's variant `Choice::That` |
60 | /// it will be `{ ref x, ref y }`. |
61 | /// So it can be used as a destructuring pattern for values of both types, |
62 | /// strong and weak. |
63 | /// |
64 | /// ```rust,ignore |
65 | /// let Unnamed (ref _0, ref _1) = <expression>; |
66 | /// let Named { ref x, ref y } = <expression>; |
67 | /// |
68 | /// match <expression> { |
69 | /// Choise::This (ref _0, ref _1) => ... , |
70 | /// Choise::That { ref x, ref y } => ... , |
71 | /// } |
72 | /// ``` |
73 | /// |
74 | /// # downgrade |
75 | /// |
76 | /// ```rust,ignore |
77 | /// ( |
78 | /// glib::clone::Downgrade::downgrade(_0), |
79 | /// glib::clone::Downgrade::downgrade(_1), |
80 | /// ) |
81 | /// |
82 | /// { |
83 | /// x: glib::clone::Downgrade::downgrade(x), |
84 | /// y: glib::clone::Downgrade::downgrade(y), |
85 | /// } |
86 | /// ``` |
87 | /// |
88 | /// # upgrade |
89 | /// |
90 | /// ```rust,ignore |
91 | /// ( |
92 | /// glib::clone::Upgrade::upgrade(_0)?, |
93 | /// glib::clone::Upgrade::upgrade(_1)?, |
94 | /// ) |
95 | /// |
96 | /// { |
97 | /// x: glib::clone::Upgrade::upgrade(x)?, |
98 | /// y: glib::clone::Upgrade::upgrade(y)?, |
99 | /// } |
100 | /// ``` |
101 | pub fn derive_downgrade_fields(fields: syn::Fields) -> DowngradeStructParts { |
102 | let glib = crate_ident_new(); |
103 | match fields { |
104 | Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => { |
105 | let fields: Vec<Type> = unnamed |
106 | .into_pairs() |
107 | .map(|pair| pair.into_value()) |
108 | .map(|field| field.ty) |
109 | .collect(); |
110 | |
111 | let weak_fields: Vec<_> = fields |
112 | .iter() |
113 | .map(|ty| { |
114 | quote! { |
115 | <#ty as #glib::clone::Downgrade>::Weak |
116 | } |
117 | }) |
118 | .collect(); |
119 | |
120 | let field_ident: Vec<Ident> = |
121 | (0..fields.len()).map(|i| format_ident!("_ {}" , i)).collect(); |
122 | |
123 | DowngradeStructParts { |
124 | weak_fields: quote! { |
125 | (#( |
126 | #weak_fields |
127 | ),*) |
128 | }, |
129 | end_of_struct: quote!(;), |
130 | destruct: quote! { |
131 | (#( |
132 | ref #field_ident |
133 | ),*) |
134 | }, |
135 | downgrade: quote! { |
136 | (#( |
137 | #glib::clone::Downgrade::downgrade(#field_ident) |
138 | ),*) |
139 | }, |
140 | upgrade: quote! { |
141 | (#( |
142 | #glib::clone::Upgrade::upgrade(#field_ident)? |
143 | ),*) |
144 | }, |
145 | } |
146 | } |
147 | Fields::Named(FieldsNamed { named, .. }) => { |
148 | let fields: Vec<(Ident, Type)> = named |
149 | .into_pairs() |
150 | .map(|pair| pair.into_value()) |
151 | .map(|field| (field.ident.expect("Field ident is specified" ), field.ty)) |
152 | .collect(); |
153 | |
154 | let weak_fields: Vec<_> = fields |
155 | .iter() |
156 | .map(|(ident, ty)| { |
157 | quote! { |
158 | #ident: <#ty as #glib::clone::Downgrade>::Weak |
159 | } |
160 | }) |
161 | .collect(); |
162 | |
163 | let field_ident: Vec<_> = fields.iter().map(|(ident, _ty)| ident).collect(); |
164 | |
165 | DowngradeStructParts { |
166 | weak_fields: quote! { |
167 | {#( |
168 | #weak_fields |
169 | ),*} |
170 | }, |
171 | end_of_struct: quote!(), |
172 | destruct: quote! { |
173 | {#( |
174 | ref #field_ident |
175 | ),*} |
176 | }, |
177 | downgrade: quote! { |
178 | {#( |
179 | #field_ident: #glib::clone::Downgrade::downgrade(#field_ident) |
180 | ),*} |
181 | }, |
182 | upgrade: quote! { |
183 | {#( |
184 | #field_ident: #glib::clone::Upgrade::upgrade(#field_ident)? |
185 | ),*} |
186 | }, |
187 | } |
188 | } |
189 | Fields::Unit => DowngradeStructParts { |
190 | weak_fields: quote! {}, |
191 | end_of_struct: quote! { ; }, |
192 | destruct: quote! {}, |
193 | downgrade: quote! {}, |
194 | upgrade: quote! {}, |
195 | }, |
196 | } |
197 | } |
198 | |