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