glib_macros/downgrade_derive/
enums.rs

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}