glib_macros/downgrade_derive/
fields.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use proc_macro2::TokenStream;
4use quote::{format_ident, quote};
5use syn::{Fields, FieldsNamed, FieldsUnnamed, Ident, Type};
6
7use crate::utils::crate_ident_new;
8
9/// Parts needed to derive Downgrade and Upgrade implementation.
10pub 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///     Choice::This (ref _0, ref _1) => ... ,
70///     Choice::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/// ```
101pub 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}