1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
// Take a look at the license at the top of the repository in the LICENSE file.
use super::fields::{derive_downgrade_fields, DowngradeStructParts};
use crate::utils::crate_ident_new;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{Generics, Ident};
/// This function derives a weak type for a given strong enum and
/// implementations of `Downgrade` and `Upgrade` traits.
///
/// # Example
///
/// ```rust,ignore
/// #[derive(glib::Downgrade)]
/// enum Choice {
/// This(X, Y),
/// That { x: X, y: Y },
/// }
/// ```
///
/// Here is what will be derived:
///
/// ```rust,ignore
/// enum ChoiceWeak {
/// This(<X as Downgrade>::Weak, <Y as Downgrade>::Weak),
/// That {
/// x: <X as Downgrade>::Weak,
/// y: <Y as Downgrade>::Weak,
/// },
/// }
///
/// impl glib::clone::Downgrade for Choice {
/// type Weak = ChoiceWeak;
///
/// fn downgrade(&self) -> Self::Weak {
/// match self {
/// Self::This(ref _0, ref _1) => Self::Weak::This(
/// glib::clone::Downgrade::downgrade(_0),
/// glib::clone::Downgrade::downgrade(_1),
/// ),
/// Self::That { ref x, ref y } => Self::Weak::That(
/// glib::clone::Downgrade::downgrade(x),
/// glib::clone::Downgrade::downgrade(y),
/// ),
/// }
/// }
/// }
///
/// impl glib::clone::Upgrade for ChoiceWeak {
/// type Strong = Choice;
///
/// fn upgrade(&self) -> Option<Self::Strong> {
/// Some(match self {
/// Self::This(ref _0, ref _1) => Self::Strong::This(
/// glib::clone::Upgrade::upgrade(_0)?,
/// glib::clone::Upgrade::upgrade(_1)?,
/// ),
/// Self::That { ref x, ref y } => Self::Strong::That(
/// glib::clone::Upgrade::upgrade(x)?,
/// glib::clone::Upgrade::upgrade(y)?,
/// ),
/// })
/// }
/// }
/// ```
pub fn derive_downgrade_for_enum(
ident: Ident,
generics: Generics,
data_enum: syn::DataEnum,
) -> TokenStream {
let glib = crate_ident_new();
let weak_type = format_ident!("{}Weak", ident);
let variants: Vec<(Ident, DowngradeStructParts)> = data_enum
.variants
.into_iter()
.map(|variant| (variant.ident, derive_downgrade_fields(variant.fields)))
.collect();
let weak_variants: Vec<_> = variants
.iter()
.map(|(ident, parts)| {
let weak_fields = &parts.weak_fields;
quote! {
#ident #weak_fields
}
})
.collect();
let downgrade_variants: Vec<_> = variants
.iter()
.map(|(ident, parts)| {
let destruct = &parts.destruct;
let downgrade = &parts.downgrade;
quote! {
Self::#ident #destruct => Self::Weak::#ident #downgrade
}
})
.collect();
let upgrade_variants: Vec<_> = variants
.iter()
.map(|(ident, parts)| {
let destruct = &parts.destruct;
let upgrade = &parts.upgrade;
quote! {
Self::#ident #destruct => Self::Strong::#ident #upgrade
}
})
.collect();
let derived = quote! {
pub enum #weak_type #generics {#(
#weak_variants
),*}
impl #generics #glib::clone::Downgrade for #ident #generics {
type Weak = #weak_type #generics;
fn downgrade(&self) -> Self::Weak {
match self {#(
#downgrade_variants
),*}
}
}
impl #generics #glib::clone::Upgrade for #weak_type #generics {
type Strong = #ident #generics;
fn upgrade(&self) -> ::core::option::Option<Self::Strong> {
Some(match self {#(
#upgrade_variants
),*})
}
}
};
derived.into()
}