1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use proc_macro::TokenStream;
4use quote::{format_ident, quote};
5use syn::{Generics, Ident};
6
7use super::fields::{derive_downgrade_fields, DowngradeStructParts};
8use 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/// ```
68pub 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