1 use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; 2 use std::fmt::Display; 3 use std::iter::FromIterator; 4 5 pub type Result<T, E = Error> = std::result::Result<T, E>; 6 7 pub struct Error { 8 begin: Span, 9 end: Span, 10 msg: String, 11 } 12 13 impl Error { new(span: Span, msg: impl Display) -> Self14 pub fn new(span: Span, msg: impl Display) -> Self { 15 Self::new2(span, span, msg) 16 } 17 new2(begin: Span, end: Span, msg: impl Display) -> Self18 pub fn new2(begin: Span, end: Span, msg: impl Display) -> Self { 19 Error { 20 begin, 21 end, 22 msg: msg.to_string(), 23 } 24 } 25 group(group: Group, msg: impl Display) -> Self26 pub fn group(group: Group, msg: impl Display) -> Self { 27 let mut iter = group.stream().into_iter(); 28 let delimiter = group.span(); 29 let begin = iter.next().map_or(delimiter, |t| t.span()); 30 let end = iter.last().map_or(begin, |t| t.span()); 31 Self::new2(begin, end, msg) 32 } 33 into_compile_error(self) -> TokenStream34 pub fn into_compile_error(self) -> TokenStream { 35 // compile_error! { $msg } 36 TokenStream::from_iter(vec![ 37 TokenTree::Ident(Ident::new("compile_error", self.begin)), 38 TokenTree::Punct({ 39 let mut punct = Punct::new('!', Spacing::Alone); 40 punct.set_span(self.begin); 41 punct 42 }), 43 TokenTree::Group({ 44 let mut group = Group::new(Delimiter::Brace, { 45 TokenStream::from_iter(vec![TokenTree::Literal({ 46 let mut string = Literal::string(&self.msg); 47 string.set_span(self.end); 48 string 49 })]) 50 }); 51 group.set_span(self.end); 52 group 53 }), 54 ]) 55 } 56 } 57