rustversion/
error.rs

1use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
2use std::fmt::Display;
3use std::iter::FromIterator;
4
5pub type Result<T, E = Error> = std::result::Result<T, E>;
6
7pub struct Error {
8    begin: Span,
9    end: Span,
10    msg: String,
11}
12
13impl Error {
14    pub fn new(span: Span, msg: impl Display) -> Self {
15        Self::new2(span, span, msg)
16    }
17
18    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
26    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
34    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}