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