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