1use std::iter::FromIterator;
4
5use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
6
7use crate::to_tokens::ToTokens;
8
9macro_rules! format_err {
10 ($span:expr, $msg:expr $(,)*) => {
11 crate::error::Error::new(&$span, String::from($msg))
12 };
13 ($span:expr, $($tt:tt)*) => {
14 format_err!($span, format!($($tt)*))
15 };
16}
17
18macro_rules! bail {
19 ($($tt:tt)*) => {
20 return Err(format_err!($($tt)*))
21 };
22}
23
24pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;
25
26#[derive(Debug)]
27pub(crate) struct Error {
28 start_span: Span,
29 end_span: Span,
30 msg: String,
31}
32
33impl Error {
34 pub(crate) fn new(tokens: &dyn ToTokens, msg: String) -> Self {
35 let mut iter = tokens.to_token_stream().into_iter();
36 let start_span = iter.next().map_or_else(Span::call_site, |t| t.span());
40 let end_span = iter.last().map_or(start_span, |t| t.span());
41
42 Self { start_span, end_span, msg }
43 }
44
45 pub(crate) fn into_compile_error(self) -> TokenStream {
47 TokenStream::from_iter(vec![
49 TokenTree::Ident(Ident::new("compile_error", self.start_span)),
50 TokenTree::Punct({
51 let mut punct = Punct::new('!', Spacing::Alone);
52 punct.set_span(self.start_span);
53 punct
54 }),
55 TokenTree::Group({
56 let mut group = Group::new(Delimiter::Brace, {
57 TokenStream::from_iter(vec![TokenTree::Literal({
58 let mut string = Literal::string(&self.msg);
59 string.set_span(self.end_span);
60 string
61 })])
62 });
63 group.set_span(self.end_span);
64 group
65 }),
66 ])
67 }
68}