gtk3_macros/
composite_template_derive.rs1use proc_macro2::TokenStream;
4use proc_macro_error::{abort, abort_call_site};
5use quote::quote;
6use syn::Data;
7
8use std::string::ToString;
9
10use crate::attribute_parser::*;
11use crate::util::*;
12
13fn gen_set_template(source: TemplateSource) -> TokenStream {
14 match source {
15 TemplateSource::File(file) => quote! {
16 let t = include_bytes!(#file);
17 klass.set_template(t);
18 },
19 TemplateSource::Resource(resource) => quote! {
20 klass.set_template_from_resource(&#resource);
21 },
22 TemplateSource::String(template) => quote! {
23 klass.set_template(&#template);
24 },
25 }
26}
27
28fn gen_template_child_bindings(fields: &syn::Fields) -> TokenStream {
29 let crate_ident = crate_ident_new();
30 let attributed_fields = match parse_fields(fields) {
31 Ok(fields) => fields,
32 Err(err) => abort!(err.span(), err.to_string()),
33 };
34
35 let recurse = attributed_fields.iter().map(|field| match field.attr.ty {
36 FieldAttributeType::TemplateChild => {
37 let mut value_id = &field.ident.to_string();
38 let ident = &field.ident;
39 field.attr.args.iter().for_each(|arg| match arg {
40 FieldAttributeArg::Id(value) => {
41 value_id = value;
42 }
43 });
44
45 quote! {
46 klass.bind_template_child_with_offset(
47 &#value_id,
48 #crate_ident::offset_of!(Self => #ident),
49 );
50 }
51 }
52 });
53
54 quote! {
55 #(#recurse)*
56 }
57}
58
59pub fn impl_composite_template(input: &syn::DeriveInput) -> TokenStream {
60 let name = &input.ident;
61 let crate_ident = crate_ident_new();
62
63 let source = match parse_template_source(input) {
64 Ok(v) => v,
65 Err(e) => abort_call_site!(
66 "{}: derive(CompositeTemplate) requires #[template(...)] to specify 'file', 'resource', or 'string'",
67 e
68 ),
69 };
70
71 let set_template = gen_set_template(source);
72
73 let fields = match input.data {
74 Data::Struct(ref s) => &s.fields,
75 _ => abort_call_site!("derive(CompositeTemplate) only supports structs"),
76 };
77
78 let template_children = gen_template_child_bindings(fields);
79
80 quote! {
81 impl #crate_ident::subclass::widget::CompositeTemplate for #name {
82 fn bind_template(klass: &mut Self::Class) {
83 #set_template
84
85 unsafe {
86 #template_children
87 }
88 }
89 }
90 }
91}