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 {
from_ident(ident: &Ident) -> Self15     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 
insert_const(input: TokenStream, const_span: Span) -> Result<TokenStream>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