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}