| 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 | |