lib.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #![feature(proc_macro_quote)]
  2. extern crate proc_macro2;
  3. use proc_macro2::*;
  4. extern crate proc_quote;
  5. use proc_quote::quote;
  6. fn scrub_storage_macro(stream: TokenStream) -> TokenStream {
  7. let mut just_saw_hash = false;
  8. let mut without_storage = Vec::<TokenTree>::new();
  9. for item in stream.into_iter() {
  10. match item {
  11. TokenTree::Punct(ref p) if p.as_char() == '#' => just_saw_hash = true,
  12. TokenTree::Group(g) if just_saw_hash && g.delimiter() == Delimiter::Bracket => {
  13. just_saw_hash = false;
  14. }
  15. TokenTree::Group(g) => {
  16. let mut new_group = Group::new(g.delimiter(), scrub_storage_macro(g.stream()));
  17. new_group.set_span(g.span());
  18. without_storage.push(TokenTree::Group(new_group));
  19. just_saw_hash = false;
  20. }
  21. _ => {
  22. without_storage.push(item);
  23. just_saw_hash = false;
  24. }
  25. }
  26. }
  27. TokenStream::from_iter(without_storage)
  28. }
  29. #[proc_macro_attribute]
  30. pub fn bump(
  31. attr: proc_macro::TokenStream,
  32. stream: proc_macro::TokenStream,
  33. ) -> proc_macro::TokenStream {
  34. let attr: TokenStream = attr.into();
  35. let stream: TokenStream = stream.into();
  36. let refname = attr.into_iter().next().unwrap();
  37. let mut process = stream.clone().into_iter();
  38. if let Some(TokenTree::Ident(i)) = process.next() {
  39. if i.to_string() != "struct" {
  40. let stream = quote!(compile_error!(stringify!("The `bump` macro can only be used on `struct`s")););
  41. let stream = TokenStream::from_iter(stream.into_iter().map(|mut s| {
  42. s.set_span(i.span());
  43. s
  44. }));
  45. return stream.into();
  46. }
  47. }
  48. let struct_name = process.next().unwrap();
  49. let body = process.find(|s| match s {
  50. TokenTree::Group(g) if g.delimiter() == Delimiter::Brace => true,
  51. _ => false,
  52. });
  53. let body = if let Some(TokenTree::Group(b)) = body {
  54. b
  55. } else {
  56. return quote!(compile_error!("Unable to find the struct body");).into();
  57. };
  58. let storage_name;
  59. let storage_type;
  60. let mut body = body.stream().into_iter();
  61. loop {
  62. let item = if let Some(i) = body.next() {
  63. i
  64. } else {
  65. return quote!(compile_error!("Could not find `#[storage]`")).into();
  66. };
  67. if let TokenTree::Punct(p) = item {
  68. if p.as_char() != '#' {
  69. continue;
  70. }
  71. // storage macro
  72. // TODO: check
  73. let _ = body.next();
  74. let mut name = match body.next() {
  75. Some(TokenTree::Ident(i)) => i,
  76. _ => continue,
  77. };
  78. if name.to_string() == "pub" {
  79. name = match body.next() {
  80. Some(TokenTree::Ident(i)) => i,
  81. _ => continue,
  82. }
  83. }
  84. let _colon = body.next();
  85. let _vec = body.next();
  86. let _lbrac = body.next();
  87. let mut typ = Vec::new();
  88. while let Some(n) = body.next() {
  89. if let TokenTree::Punct(ref p) = n {
  90. if p.as_char() == '>' {
  91. break;
  92. }
  93. }
  94. typ.push(n);
  95. }
  96. storage_name = name;
  97. storage_type = typ[0].clone();
  98. break;
  99. } else {
  100. continue;
  101. }
  102. }
  103. let idx_def = quote! {
  104. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  105. struct #refname {
  106. idx: usize,
  107. }
  108. };
  109. let impl_def = quote! {
  110. impl #struct_name {
  111. fn insert(&mut self, item: #storage_type) -> #refname {
  112. let idx = self.#storage_name.len();
  113. self.#storage_name.push(item);
  114. #refname { idx }
  115. }
  116. }
  117. impl ::std::ops::Index<#refname> for #struct_name {
  118. type Output = #storage_type;
  119. fn index(&self, rf: #refname) -> &Self::Output {
  120. &self.#storage_name[rf.idx]
  121. }
  122. }
  123. };
  124. let mut stream = scrub_storage_macro(stream);
  125. stream.extend(idx_def);
  126. stream.extend(impl_def);
  127. stream.into()
  128. }