use crate::Payload;
use crate::ResultExt;
use proc_macro2::{Span, TokenStream};
use quote::quote_spanned;
use std::convert::{AsMut, AsRef};
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct MacroError {
pub(crate) span: Span,
pub(crate) msg: String,
}
impl MacroError {
pub fn new(span: Span, msg: String) -> Self {
MacroError { span, msg }
}
pub fn call_site(msg: String) -> Self {
MacroError::new(Span::call_site(), msg)
}
pub fn into_compile_error(self) -> TokenStream {
let MacroError { span, msg } = self;
quote_spanned! { span=> compile_error!(#msg); }
}
pub fn set_span(&mut self, span: Span) {
self.span = span;
}
pub fn span(&self) -> Span {
self.span.clone()
}
pub fn trigger(self) -> ! {
panic!(Payload(self))
}
}
impl From<syn::Error> for MacroError {
fn from(e: syn::Error) -> Self {
MacroError::new(e.span(), e.to_string())
}
}
impl From<String> for MacroError {
fn from(msg: String) -> Self {
MacroError::call_site(msg)
}
}
impl From<&str> for MacroError {
fn from(msg: &str) -> Self {
MacroError::call_site(msg.into())
}
}
impl Display for MacroError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
Display::fmt(&self.msg, f)
}
}
impl<T, E: Into<MacroError>> ResultExt for Result<T, E> {
type Ok = T;
fn unwrap_or_exit(self) -> T {
match self {
Ok(res) => res,
Err(e) => e.into().trigger(),
}
}
fn expect_or_exit(self, message: &str) -> T {
match self {
Ok(res) => res,
Err(e) => {
let MacroError { msg, span } = e.into();
let msg = format!("{}: {}", message, msg);
MacroError::new(span, msg).trigger()
}
}
}
}
impl From<MacroError> for TokenStream {
fn from(err: MacroError) -> Self {
err.into_compile_error()
}
}
impl From<MacroError> for proc_macro::TokenStream {
fn from(err: MacroError) -> Self {
err.into_compile_error().into()
}
}
impl AsRef<String> for MacroError {
fn as_ref(&self) -> &String {
&self.msg
}
}
impl AsMut<String> for MacroError {
fn as_mut(&mut self) -> &mut String {
&mut self.msg
}
}