1#![recursion_limit = "256"]
2
3use proc_macro::TokenStream;
4use quote::{format_ident, quote};
5use syn::parse::Parser;
6use syn::DeriveInput;
7use syn::{parse_macro_input, ItemStruct};
8mod field_setter;
9
10#[proc_macro_derive(FieldSetter, attributes(field_setter))]
11pub fn field_setter(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
12 let input = syn::parse::<DeriveInput>(input).unwrap();
13 field_setter::field_setter_impl(input)
14}
15
16#[proc_macro_attribute]
17pub fn layout_structs(_attr: TokenStream, item: TokenStream) -> TokenStream {
18 let input = parse_macro_input!(item as ItemStruct);
19 let vis = &input.vis;
20 let fields = &input.fields;
21 let attrs = &input.attrs;
22
23 let template_struct_name = format_ident!("LayoutTemplate");
26 let template_struct = quote! {
27 #(#attrs)*
28 #[serde_with::skip_serializing_none]
29 #[derive(Serialize, Debug, Clone, FieldSetter)]
30 #vis struct #template_struct_name #fields
31 };
32
33 let layout_struct_name = format_ident!("Layout");
35 let mut layout_fields = fields.clone();
36 if let syn::Fields::Named(ref mut named) = layout_fields {
38 named.named.push(
39 syn::Field::parse_named
40 .parse2(quote! {
41 #[field_setter(skip)]
42 template: Option<Box<std::borrow::Cow<'static, Template>>>
43 })
44 .unwrap(),
45 );
46 }
47 let layout_struct = quote! {
48 #(#attrs)*
49 #[serde_with::skip_serializing_none]
50 #[derive(Serialize, Debug, Clone, FieldSetter)]
51 #[field_setter(kind = "layout")]
52 #vis struct #layout_struct_name #layout_fields
53 };
54
55 let template_impl = quote! {
57 impl #template_struct_name {
58 pub fn new() -> Self { Default::default() }
59 pub fn add_annotation(&mut self, annotation: Annotation) {
60 if self.annotations.is_none() { self.annotations = Some(Vec::new()); }
61 self.annotations.as_mut().unwrap().push(annotation);
62 }
63 pub fn add_shape(&mut self, shape: Shape) {
64 if self.shapes.is_none() { self.shapes = Some(Vec::new()); }
65 self.shapes.as_mut().unwrap().push(shape);
66 }
67 }
68 };
69 let layout_impl = quote! {
70 impl #layout_struct_name {
71 pub fn new() -> Self { Default::default() }
72 pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap() }
73 pub fn add_annotation(&mut self, annotation: Annotation) {
74 if self.annotations.is_none() { self.annotations = Some(Vec::new()); }
75 self.annotations.as_mut().unwrap().push(annotation);
76 }
77 pub fn add_shape(&mut self, shape: Shape) {
78 if self.shapes.is_none() { self.shapes = Some(Vec::new()); }
79 self.shapes.as_mut().unwrap().push(shape);
80 }
81 pub fn template<T>(mut self, template: T) -> Self
82 where T: Into<std::borrow::Cow<'static, Template>> {
83 self.template = Some(Box::new(template.into()));
84 self
85 }
86 }
87 };
88
89 let expanded = quote! {
90 #template_struct
91 #layout_struct
92 #template_impl
93 #layout_impl
94 };
95 TokenStream::from(expanded)
96}