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