123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- #![feature(proc_macro_quote)]
- extern crate proc_macro2;
- use proc_macro2::*;
- extern crate proc_quote;
- use proc_quote::quote;
- fn scrub_storage_macro(stream: TokenStream) -> TokenStream {
- let mut just_saw_hash = false;
- let mut without_storage = Vec::<TokenTree>::new();
- for item in stream.into_iter() {
- match item {
- TokenTree::Punct(ref p) if p.as_char() == '#' => just_saw_hash = true,
- TokenTree::Group(g) if just_saw_hash && g.delimiter() == Delimiter::Bracket => {
- just_saw_hash = false;
- }
- TokenTree::Group(g) => {
- let mut new_group = Group::new(g.delimiter(), scrub_storage_macro(g.stream()));
- new_group.set_span(g.span());
- without_storage.push(TokenTree::Group(new_group));
- just_saw_hash = false;
- }
- _ => {
- without_storage.push(item);
- just_saw_hash = false;
- }
- }
- }
- TokenStream::from_iter(without_storage)
- }
- #[proc_macro_attribute]
- pub fn bump(
- attr: proc_macro::TokenStream,
- stream: proc_macro::TokenStream,
- ) -> proc_macro::TokenStream {
- let attr: TokenStream = attr.into();
- let stream: TokenStream = stream.into();
- let refname = attr.into_iter().next().unwrap();
- let mut process = stream.clone().into_iter();
- if let Some(TokenTree::Ident(i)) = process.next() {
- if i.to_string() != "struct" {
- let stream = quote!(compile_error!(stringify!("The `bump` macro can only be used on `struct`s")););
- let stream = TokenStream::from_iter(stream.into_iter().map(|mut s| {
- s.set_span(i.span());
- s
- }));
- return stream.into();
- }
- }
- let struct_name = process.next().unwrap();
- let body = process.find(|s| match s {
- TokenTree::Group(g) if g.delimiter() == Delimiter::Brace => true,
- _ => false,
- });
- let body = if let Some(TokenTree::Group(b)) = body {
- b
- } else {
- return quote!(compile_error!("Unable to find the struct body");).into();
- };
- let storage_name;
- let storage_type;
- let mut body = body.stream().into_iter();
- loop {
- let item = if let Some(i) = body.next() {
- i
- } else {
- return quote!(compile_error!("Could not find `#[storage]`")).into();
- };
- if let TokenTree::Punct(p) = item {
- if p.as_char() != '#' {
- continue;
- }
- // storage macro
- // TODO: check
- let _ = body.next();
- let mut name = match body.next() {
- Some(TokenTree::Ident(i)) => i,
- _ => continue,
- };
- if name.to_string() == "pub" {
- name = match body.next() {
- Some(TokenTree::Ident(i)) => i,
- _ => continue,
- }
- }
- let _colon = body.next();
- let _vec = body.next();
- let _lbrac = body.next();
- let mut typ = Vec::new();
- while let Some(n) = body.next() {
- if let TokenTree::Punct(ref p) = n {
- if p.as_char() == '>' {
- break;
- }
- }
- typ.push(n);
- }
- storage_name = name;
- storage_type = typ[0].clone();
- break;
- } else {
- continue;
- }
- }
- let idx_def = quote! {
- #[derive(Debug, PartialEq, Eq, Clone, Copy)]
- struct #refname {
- idx: usize,
- }
- };
- let impl_def = quote! {
- impl #struct_name {
- fn insert(&mut self, item: #storage_type) -> #refname {
- let idx = self.#storage_name.len();
- self.#storage_name.push(item);
- #refname { idx }
- }
- }
- impl ::std::ops::Index<#refname> for #struct_name {
- type Output = #storage_type;
- fn index(&self, rf: #refname) -> &Self::Output {
- &self.#storage_name[rf.idx]
- }
- }
- };
- let mut stream = scrub_storage_macro(stream);
- stream.extend(idx_def);
- stream.extend(impl_def);
- stream.into()
- }
|