1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use super::fields::{derive_downgrade_fields, DowngradeStructParts};
4 use proc_macro::TokenStream;
5 use quote::{format_ident, quote};
6 use syn::{Generics, Ident};
7 
8 /// This function derives a weak type for a given strong enum and
9 /// implementations of `Downgrade` and `Upgrade` traits.
10 ///
11 /// # Example
12 ///
13 /// ```rust,ignore
14 /// #[derive(glib::Downgrade)]
15 /// enum Choice {
16 ///     This(X, Y),
17 ///     That { x: X, y: Y },
18 /// }
19 /// ```
20 ///
21 /// Here is what will be derived:
22 ///
23 /// ```rust,ignore
24 /// enum ChoiceWeak {
25 ///     This(<X as Downgrade>::Weak, <Y as Downgrade>::Weak),
26 ///     That {
27 ///         x: <X as Downgrade>::Weak,
28 ///         y: <Y as Downgrade>::Weak,
29 ///     },
30 /// }
31 ///
32 /// impl glib::clone::Downgrade for Choice {
33 ///     type Weak = ChoiceWeak;
34 ///
35 ///     fn downgrade(&self) -> Self::Weak {
36 ///         match self {
37 ///             Self::This(ref _0, ref _1) => Self::Weak::This(
38 ///                 glib::clone::Downgrade::downgrade(_0),
39 ///                 glib::clone::Downgrade::downgrade(_1),
40 ///             ),
41 ///             Self::That { ref x, ref y } => Self::Weak::That(
42 ///                 glib::clone::Downgrade::downgrade(x),
43 ///                 glib::clone::Downgrade::downgrade(y),
44 ///             ),
45 ///         }
46 ///     }
47 /// }
48 ///
49 /// impl glib::clone::Upgrade for ChoiceWeak {
50 ///     type Strong = Choice;
51 ///
52 ///     fn upgrade(&self) -> Option<Self::Strong> {
53 ///         Some(match self {
54 ///             Self::This(ref _0, ref _1) => Self::Strong::This(
55 ///                 glib::clone::Upgrade::upgrade(_0)?,
56 ///                 glib::clone::Upgrade::upgrade(_1)?,
57 ///             ),
58 ///             Self::That { ref x, ref y } => Self::Strong::That(
59 ///                 glib::clone::Upgrade::upgrade(x)?,
60 ///                 glib::clone::Upgrade::upgrade(y)?,
61 ///             ),
62 ///         })
63 ///     }
64 /// }
65 /// ```
derive_downgrade_for_enum( ident: Ident, generics: Generics, data_enum: syn::DataEnum, ) -> TokenStream66 pub fn derive_downgrade_for_enum(
67     ident: Ident,
68     generics: Generics,
69     data_enum: syn::DataEnum,
70 ) -> TokenStream {
71     let weak_type = format_ident!("{}Weak", ident);
72 
73     let variants: Vec<(Ident, DowngradeStructParts)> = data_enum
74         .variants
75         .into_iter()
76         .map(|variant| (variant.ident, derive_downgrade_fields(variant.fields)))
77         .collect();
78 
79     let weak_variants: Vec<_> = variants
80         .iter()
81         .map(|(ident, parts)| {
82             let weak_fields = &parts.weak_fields;
83             quote! {
84                 #ident #weak_fields
85             }
86         })
87         .collect();
88 
89     let downgrade_variants: Vec<_> = variants
90         .iter()
91         .map(|(ident, parts)| {
92             let destruct = &parts.destruct;
93             let downgrade = &parts.downgrade;
94             quote! {
95                 Self::#ident #destruct => Self::Weak::#ident #downgrade
96             }
97         })
98         .collect();
99 
100     let upgrade_variants: Vec<_> = variants
101         .iter()
102         .map(|(ident, parts)| {
103             let destruct = &parts.destruct;
104             let upgrade = &parts.upgrade;
105             quote! {
106                 Self::#ident #destruct => Self::Strong::#ident #upgrade
107             }
108         })
109         .collect();
110 
111     let derived = quote! {
112         pub enum #weak_type #generics {#(
113             #weak_variants
114         ),*}
115 
116         impl #generics glib::clone::Downgrade for #ident #generics {
117             type Weak = #weak_type #generics;
118 
119             fn downgrade(&self) -> Self::Weak {
120                 match self {#(
121                     #downgrade_variants
122                 ),*}
123             }
124         }
125 
126         impl #generics glib::clone::Upgrade for #weak_type #generics {
127             type Strong = #ident #generics;
128 
129             fn upgrade(&self) -> Option<Self::Strong> {
130                 Some(match self {#(
131                     #upgrade_variants
132                 ),*})
133             }
134         }
135     };
136 
137     derived.into()
138 }
139