| 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 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 | /// ``` |
| 84 | pub 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 | |