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
// 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 struct and
/// implementations of `Downgrade` and `Upgrade` traits.
///
/// # Example
///
/// ```rust,ignore
/// #[derive(glib::Downgrade)]
/// struct Unnamed(X, Y);
///
/// #[derive(glib::Downgrade)]
/// struct Named {
/// x: X,
/// y: Y,
/// }
/// ```
///
/// Here is what will be derived:
///
/// ```rust,ignore
/// pub struct UnnamedWeak(<X as Downgrade>::Weak, <Y as Downgrade>::Weak);
///
/// impl glib::clone::Downgrade for Unnamed {
/// type Weak = UnnamedWeak;
///
/// fn downgrade(&self) -> Self::Weak {
/// let Self (ref _0, ref _1) = self;
/// UnnamedWeak (
/// glib::clone::Downgrade::downgrade(_0),
/// glib::clone::Downgrade::downgrade(_1),
/// )
/// }
/// }
///
/// impl glib::clone::Upgrade for UnnamedWeak {
/// type Strong = Unnamed;
///
/// fn upgrade(&self) -> Option<Self::Strong> {
/// let Self (ref _0, ref _1) = self;
/// Some(Unnamed (
/// glib::clone::Upgrade::upgrade(_0)?,
/// glib::clone::Upgrade::upgrade(_1)?,
/// ))
/// }
/// }
///
/// pub struct NamedWeak {
/// x: <X as Downgrade>::Weak,
/// y: <Y as Downgrade>::Weak,
/// }
///
/// impl glib::clone::Downgrade for Named {
/// type Weak = NamedWeak;
///
/// fn downgrade(&self) -> Self::Weak {
/// let Self { ref x, ref y } = self;
/// NamedWeak {
/// glib::clone::Downgrade::downgrade(x),
/// glib::clone::Downgrade::downgrade(y),
/// }
/// }
/// }
///
/// impl glib::clone::Upgrade for NamedWeak {
/// type Strong = Named;
///
/// fn upgrade(&self) -> Option<Self::Strong> {
/// let Self { ref x, ref y } = self;
/// Some(Named {
/// glib::clone::Upgrade::upgrade(x)?,
/// glib::clone::Upgrade::upgrade(y)?,
/// })
/// }
/// }
/// ```
pub fn derive_downgrade_for_struct(
ident: Ident,
generics: Generics,
data_struct: syn::DataStruct,
) -> TokenStream {
let glib = crate_ident_new();
let weak_type = format_ident!("{}Weak", ident);
let DowngradeStructParts {
weak_fields,
end_of_struct,
destruct,
downgrade,
upgrade,
} = derive_downgrade_fields(data_struct.fields);
let derived = quote! {
pub struct #weak_type #generics #weak_fields #end_of_struct
impl #generics #glib::clone::Downgrade for #ident #generics {
type Weak = #weak_type #generics;
fn downgrade(&self) -> Self::Weak {
let Self #destruct = self;
#weak_type #downgrade
}
}
impl #generics #glib::clone::Upgrade for #weak_type #generics {
type Strong = #ident #generics;
fn upgrade(&self) -> ::core::option::Option<Self::Strong> {
let Self #destruct = self;
Some(#ident #upgrade)
}
}
};
derived.into()
}