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
use crate::error::{Error, Result}; use proc_macro::{Ident, Span, TokenStream, TokenTree}; use std::iter; #[derive(PartialOrd, PartialEq)] enum Qualifiers { None, Async, Unsafe, Extern, Abi, } impl Qualifiers { fn from_ident(ident: &Ident) -> Self { match ident.to_string().as_str() { "async" => Qualifiers::Async, "unsafe" => Qualifiers::Unsafe, "extern" => Qualifiers::Extern, _ => Qualifiers::None, } } } pub(crate) fn insert_const(input: TokenStream, const_span: Span) -> Result<TokenStream> { let ref mut input = crate::iter::new(input); let mut out = TokenStream::new(); let mut qualifiers = Qualifiers::None; let mut pending = Vec::new(); while let Some(token) = input.next() { match token { TokenTree::Ident(ref ident) if ident.to_string() == "fn" => { let const_ident = Ident::new("const", const_span); out.extend(iter::once(TokenTree::Ident(const_ident))); out.extend(pending); out.extend(iter::once(token)); out.extend(input); return Ok(out); } TokenTree::Ident(ref ident) if Qualifiers::from_ident(ident) > qualifiers => { qualifiers = Qualifiers::from_ident(ident); pending.push(token); } TokenTree::Literal(_) if qualifiers == Qualifiers::Extern => { qualifiers = Qualifiers::Abi; pending.push(token); } _ => { qualifiers = Qualifiers::None; out.extend(pending.drain(..)); out.extend(iter::once(token)); } } } Err(Error::new(const_span, "only allowed on a fn item")) }