1use proc_macro::TokenStream;
2use std::collections::HashSet;
3use std::hash::Hash;
4
5use proc_macro2::Span;
6use quote::quote;
7use syn::Type;
8use syn::braced;
9use syn::Ident;
10use syn::parse::{Parse, ParseStream};
11use syn::punctuated::Punctuated;
12use syn::Result;
13use syn::token::{Brace};
14use syn::Token;
15
16struct Syntax {
17 ident: Ident,
18 _brace_token: Brace,
19 brace_fields: Punctuated<Type, Token![,]>,
20}
21
22struct Structure {
23 name: Ident,
24 tys: Vec<Type>
25}
26
27
28impl Parse for Structure {
29
30 fn parse(stream: ParseStream) -> Result<Self> {
31 let content;
32 let syntax = Syntax {
33 ident: stream.parse().unwrap(),
34 _brace_token: braced!(content in stream),
35 brace_fields: content.parse_terminated(Type::parse).unwrap()
36 };
37
38 let type_vec: Vec<Type> = syntax.brace_fields.into_iter().collect();
39
40 Ok(Structure {
41 name: syntax.ident,
42 tys: type_vec
43 })
44 }
45}
46
47fn has_unique_elements<T>(iter: T) -> bool
48 where
49 T: IntoIterator,
50 T::Item: Eq + Hash,
51{
52 let mut unique = HashSet::new();
53 iter.into_iter().all(move |x| unique.insert(x))
54}
55
56#[proc_macro]
57pub fn container(input: TokenStream) -> TokenStream {
58 let container_structure = syn::parse_macro_input!(input as Structure);
59 let container_name = container_structure.name;
60
61 if !has_unique_elements(container_structure.tys.clone()) {
62 panic!("duplicate type exist")
63 }
64
65 let field_types: Vec<Type> = container_structure.tys.clone();
66 let field_names: Vec<Ident> = field_types
67 .clone()
68 .into_iter()
69 .enumerate()
70 .map(|(i, _t)| Ident::new(format!("_com_{}_", i).as_str(), Span::call_site()))
71 .collect();
72
73 let struct_def = quote!{
74 #[derive(Default)]
75 pub struct #container_name {
76 #(#field_names: std::collections::HashMap<String, bean::component::Arc<#field_types>>),*
77 }
78 };
79
80 let comp_trait_impl = quote!{
81 #(
82 impl bean::component::HasComponent<#field_types> for #container_name {
83 fn put(&mut self, name: &str, component: bean::component::Arc<#field_types>) -> &mut Self{
84 self.#field_names.insert(name.to_owned(), component);
85 self
86 }
87
88 fn get(&self, name: &str) -> Option<bean::component::Arc<#field_types>> {
89 self.#field_names.get(name).map(|c| c.clone())
90 }
91
92 fn get_all(&self) -> Vec<(&str, bean::component::Arc<#field_types>)> {
93 self.#field_names.iter().map(|(k,v)| (k.as_str(), v.clone())).collect()
94 }
95 }
96 )*
97 };
98
99 let static_var = Ident::new(format!("__CONTAINER_{}__", container_name).as_str(), Span::call_site());
100
101 let container_def = quote!{
102 static mut #static_var: Option<#container_name> = Option::None;
103 impl #container_name {
104
105 fn init() -> &'static mut #container_name{
106 unsafe {
107 #static_var = Some(#container_name::default());
108 #static_var.as_mut().unwrap()
109 }
110 }
111
112 pub fn borrow() -> &'static #container_name {
113 unsafe { #static_var.as_ref().unwrap() }
114 }
115 }
116 };
117
118
119 let tokens = quote! {
120 #struct_def
121 #comp_trait_impl
122 #container_def
123 };
124
125 TokenStream::from(tokens)
126}