1 | use crate::error::{Error, Result}; |
2 | use proc_macro::{Ident, Span, TokenStream, TokenTree}; |
3 | use std::iter; |
4 | |
5 | #[derive (PartialOrd, PartialEq)] |
6 | enum Qualifiers { |
7 | None, |
8 | Async, |
9 | Unsafe, |
10 | Extern, |
11 | Abi, |
12 | } |
13 | |
14 | impl Qualifiers { |
15 | fn from_ident(ident: &Ident) -> Self { |
16 | match ident.to_string().as_str() { |
17 | "async" => Qualifiers::Async, |
18 | "unsafe" => Qualifiers::Unsafe, |
19 | "extern" => Qualifiers::Extern, |
20 | _ => Qualifiers::None, |
21 | } |
22 | } |
23 | } |
24 | |
25 | pub(crate) fn insert_const(input: TokenStream, const_span: Span) -> Result<TokenStream> { |
26 | let ref mut input = crate::iter::new(input); |
27 | let mut out = TokenStream::new(); |
28 | let mut qualifiers = Qualifiers::None; |
29 | let mut pending = Vec::new(); |
30 | |
31 | while let Some(token) = input.next() { |
32 | match token { |
33 | TokenTree::Ident(ref ident) if ident.to_string() == "fn" => { |
34 | let const_ident = Ident::new("const" , const_span); |
35 | out.extend(iter::once(TokenTree::Ident(const_ident))); |
36 | out.extend(pending); |
37 | out.extend(iter::once(token)); |
38 | out.extend(input); |
39 | return Ok(out); |
40 | } |
41 | TokenTree::Ident(ref ident) if Qualifiers::from_ident(ident) > qualifiers => { |
42 | qualifiers = Qualifiers::from_ident(ident); |
43 | pending.push(token); |
44 | } |
45 | TokenTree::Literal(_) if qualifiers == Qualifiers::Extern => { |
46 | qualifiers = Qualifiers::Abi; |
47 | pending.push(token); |
48 | } |
49 | _ => { |
50 | qualifiers = Qualifiers::None; |
51 | out.extend(pending.drain(..)); |
52 | out.extend(iter::once(token)); |
53 | } |
54 | } |
55 | } |
56 | |
57 | Err(Error::new(const_span, "only allowed on a fn item" )) |
58 | } |
59 | |