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 struct and
11/// implementations of `Downgrade` and `Upgrade` traits.
12///
13/// # Example
14///
15/// ```rust,ignore
16/// #[derive(glib::Downgrade)]
17/// struct Unnamed(X, Y);
18///
19/// #[derive(glib::Downgrade)]
20/// struct Named {
21/// x: X,
22/// y: Y,
23/// }
24/// ```
25///
26/// Here is what will be derived:
27///
28/// ```rust,ignore
29/// pub struct UnnamedWeak(<X as Downgrade>::Weak, <Y as Downgrade>::Weak);
30///
31/// impl glib::clone::Downgrade for Unnamed {
32/// type Weak = UnnamedWeak;
33///
34/// fn downgrade(&self) -> Self::Weak {
35/// let Self (ref _0, ref _1) = self;
36/// UnnamedWeak (
37/// glib::clone::Downgrade::downgrade(_0),
38/// glib::clone::Downgrade::downgrade(_1),
39/// )
40/// }
41/// }
42///
43/// impl glib::clone::Upgrade for UnnamedWeak {
44/// type Strong = Unnamed;
45///
46/// fn upgrade(&self) -> Option<Self::Strong> {
47/// let Self (ref _0, ref _1) = self;
48/// Some(Unnamed (
49/// glib::clone::Upgrade::upgrade(_0)?,
50/// glib::clone::Upgrade::upgrade(_1)?,
51/// ))
52/// }
53/// }
54///
55/// pub struct NamedWeak {
56/// x: <X as Downgrade>::Weak,
57/// y: <Y as Downgrade>::Weak,
58/// }
59///
60/// impl glib::clone::Downgrade for Named {
61/// type Weak = NamedWeak;
62///
63/// fn downgrade(&self) -> Self::Weak {
64/// let Self { ref x, ref y } = self;
65/// NamedWeak {
66/// glib::clone::Downgrade::downgrade(x),
67/// glib::clone::Downgrade::downgrade(y),
68/// }
69/// }
70/// }
71///
72/// impl glib::clone::Upgrade for NamedWeak {
73/// type Strong = Named;
74///
75/// fn upgrade(&self) -> Option<Self::Strong> {
76/// let Self { ref x, ref y } = self;
77/// Some(Named {
78/// glib::clone::Upgrade::upgrade(x)?,
79/// glib::clone::Upgrade::upgrade(y)?,
80/// })
81/// }
82/// }
83/// ```
84pub fn derive_downgrade_for_struct(
85 ident: Ident,
86 generics: Generics,
87 data_struct: syn::DataStruct,
88) -> TokenStream {
89 let glib = crate_ident_new();
90 let weak_type = format_ident!("{}Weak", ident);
91
92 let DowngradeStructParts {
93 weak_fields,
94 end_of_struct,
95 destruct,
96 downgrade,
97 upgrade,
98 } = derive_downgrade_fields(data_struct.fields);
99
100 let derived = quote! {
101 pub struct #weak_type #generics #weak_fields #end_of_struct
102
103 impl #generics #glib::clone::Downgrade for #ident #generics {
104 type Weak = #weak_type #generics;
105
106 fn downgrade(&self) -> Self::Weak {
107 let Self #destruct = self;
108 #weak_type #downgrade
109 }
110 }
111
112 impl #generics #glib::clone::Upgrade for #weak_type #generics {
113 type Strong = #ident #generics;
114
115 fn upgrade(&self) -> ::core::option::Option<Self::Strong> {
116 let Self #destruct = self;
117 ::core::option::Option::Some(#ident #upgrade)
118 }
119 }
120 };
121
122 derived.into()
123}
124