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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//! This crate is meant to be used inside a proc macro lib.
//!
//! This crate provides a trait [`ErrorSpanned`]
//! and a derive macro [`error_spanned_derive::ErrorSpanned`].
//! The trait enforces that the error type supports conversion
//! to [`syn::Error`] and [`proc_macro2::TokenStream`].
//!
//! This trait is implemented for a wrapper struct generated by the
//! `#[derive(ErrorSpanned)]`. The struct generated by it stores line, file and span info.
//!
//! # Example
//!
//! For a file named `error_spanned.rs`:
//!
//! ```
//! use std::fmt::Display;
//! use error_spanned::{ErrorSpanned as _, ErrorSpanned};
//! use proc_macro2::Span;
//!
//! // Deriving ErrorSpanned generates a struct named `CustomErrorSpanned`
//! // and a function-like macro named custom_error!().
//! #[derive(Debug, ErrorSpanned)]
//! enum CustomError {
//!     Error1,
//!     Error2(String),
//!     Error3 {
//!         x: i32,
//!         y: i32,
//!     },
//! }
//!
//! impl Display for CustomError {
//!     fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
//!         match self {
//!             CustomError::Error1 => write!(f, "Error1"),
//!             CustomError::Error2(string) => write!(f, "Error2({})", string),
//!             CustomError::Error3 {x, y} => write!(f, "Error3 {{ x = {}, y = {} }}",x, y),
//!         }
//!     }
//! }
//! impl std::error::Error for CustomError {}
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // Printing the following errors will also print line and file
//!     println!("{}", custom_error!(Error1, Span::call_site()));
//!     println!("{}", custom_error!(Error2("Hello world".into()), Span::call_site()));
//!     println!("{}", custom_error!(Error3{x: 1, y: 2}, Span::call_site()));
//!     Ok(())
//! }
//! ```
//!
//! Output is as follows:
//! ```text
//! Line: 31, File: /Users/mihir/rust_crates/error_spanned/tests/error_spanned.rs:
//! Error1
//! Line: 32, File: /Users/mihir/rust_crates/error_spanned/tests/error_spanned.rs:
//! Error2(Hello world)
//! Line: 33, File: /Users/mihir/rust_crates/error_spanned/tests/error_spanned.rs:
//! Error3 { x = 1, y = 2 }
//! ```
//! As shown in the above example, errors should be propagated by the generated macro
//! (like `custom_error!()`). The generated macro is the snake cased version of the error enum.
//!
//! The generated macro accepts the error variant (not complete path) as the first arg
//! and span as the second arg.
//!
//! The type returned by the macro is `<enum_named>Spanned`. This type can be converted to
//! [`proc_macro2::TokenStream`] or [`syn::Error`] as it implements [`ErrorSpanned`].
//! On conversion to [`proc_macro2::TokenStream`] or [`syn::Error`] it preseves span information.
//!

pub use error_spanned_derive::ErrorSpanned;

use std::{
    error::Error,
    fmt::{Debug, Display},
    ops::{Deref, DerefMut},
};

pub trait ErrorSpanned:
    Display + Debug + Error + Deref + DerefMut + Into<syn::Error> + Into<proc_macro2::TokenStream>
{
}