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
126
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, bean::component::Arc<#field_types>>),*
        }
    };

    let comp_trait_impl = quote!{
        #(
            impl bean::component::HasComponent<#field_types> for #container_name {
                fn put(&mut self, name: &str, component: bean::component::Arc<#field_types>) -> &mut Self{
                    self.#field_names.insert(name.to_owned(), component);
                    self
                }

                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)
}