derive_element.rs

 1use proc_macro::TokenStream;
 2use proc_macro2::Ident;
 3use quote::quote;
 4use syn::{parse_macro_input, parse_quote, DeriveInput, GenericParam, Generics};
 5
 6use crate::derive_into_element::impl_into_element;
 7
 8pub fn derive_element(input: TokenStream) -> TokenStream {
 9    let ast = parse_macro_input!(input as DeriveInput);
10    let type_name = ast.ident;
11    let placeholder_view_generics: Generics = parse_quote! { <V: 'static> };
12
13    let (impl_generics, type_generics, where_clause, view_type_name, lifetimes) =
14        if let Some(first_type_param) = ast.generics.params.iter().find_map(|param| {
15            if let GenericParam::Type(type_param) = param {
16                Some(type_param.ident.clone())
17            } else {
18                None
19            }
20        }) {
21            let mut lifetimes = vec![];
22            for param in ast.generics.params.iter() {
23                if let GenericParam::Lifetime(lifetime_def) = param {
24                    lifetimes.push(lifetime_def.lifetime.clone());
25                }
26            }
27            let generics = ast.generics.split_for_impl();
28            (
29                generics.0,
30                Some(generics.1),
31                generics.2,
32                first_type_param,
33                lifetimes,
34            )
35        } else {
36            let generics = placeholder_view_generics.split_for_impl();
37            let placeholder_view_type_name: Ident = parse_quote! { V };
38            (
39                generics.0,
40                None,
41                generics.2,
42                placeholder_view_type_name,
43                vec![],
44            )
45        };
46
47    let lifetimes = if !lifetimes.is_empty() {
48        quote! { <#(#lifetimes),*> }
49    } else {
50        quote! {}
51    };
52
53    let impl_into_element = impl_into_element(
54        &impl_generics,
55        &view_type_name,
56        &type_name,
57        &type_generics,
58        &where_clause,
59    );
60
61    let gen = quote! {
62        impl #impl_generics gpui2::element::Element<#view_type_name> for #type_name #type_generics
63        #where_clause
64        {
65            type PaintState = gpui2::element::AnyElement<#view_type_name #lifetimes>;
66
67            fn layout(
68                &mut self,
69                view: &mut V,
70                cx: &mut gpui2::ViewContext<V>,
71            ) -> anyhow::Result<(gpui2::element::LayoutId, Self::PaintState)> {
72                let mut rendered_element = self.render(view, cx).into_element().into_any();
73                let layout_id = rendered_element.layout(view, cx)?;
74                Ok((layout_id, rendered_element))
75            }
76
77            fn paint(
78                &mut self,
79                view: &mut V,
80                parent_origin: gpui2::Vector2F,
81                _: &gpui2::element::Layout,
82                rendered_element: &mut Self::PaintState,
83                cx: &mut gpui2::ViewContext<V>,
84            ) {
85                rendered_element.paint(view, parent_origin, cx);
86            }
87        }
88
89        #impl_into_element
90    };
91
92    gen.into()
93}