Initial Commit

This commit is contained in:
Andrey Tkachenko 2023-03-06 20:53:49 +04:00
commit 4cb572f64c
6 changed files with 140 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/Cargo.lock

19
Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "ctxerr"
version = "0.2.0"
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
repository = "https://github.com/andreytkachenko/ctxerr.git"
keywords = ["error", "handling", "thiserror", "context", "backtrace"]
categories = ["error-handling"]
description = "Tiny wrapper on thiserror embedding backtrace and location"
license = "MIT OR Apache-2.0"
exclude = [".gitignore", ".cargo/config", ".github/**", "codecov.yml"]
edition = "2021"
resolver = "2"
[workspace]
members = ["derive"]
[dependencies]
ctxerr_derive = {version = "0.3.0", path = "derive"}
thiserror = "1.0.39"

19
derive/Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "ctxerr_derive"
version = "0.3.0"
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
repository = "https://github.com/andreytkachenko/ctxerr.git"
keywords = ["error", "handling", "thiserror", "context", "backtrace"]
categories = ["error-handling"]
description = "Tiny wrapper on thiserror embedding backtrace and location"
license = "MIT OR Apache-2.0"
exclude = [".gitignore", ".cargo/config", ".github/**", "codecov.yml"]
edition = "2021"
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1"
quote = "1"
syn = {version = "1", features = ["full"]}

76
derive/src/lib.rs Normal file
View File

@ -0,0 +1,76 @@
#![recursion_limit = "128"]
extern crate proc_macro;
extern crate proc_macro2;
use proc_macro2::Ident;
use syn::DeriveInput;
use quote::quote;
#[proc_macro_attribute]
pub fn ctxerr(
_metadata: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let ast: DeriveInput = syn::parse(input).unwrap();
let name = ast.ident.to_string();
if !name.ends_with("Kind") {
panic!("Ttypename should ends with `Kind`!");
}
let name_ident = &ast.ident;
let base_name = Ident::new(&name[0..name.len() - 4], ast.ident.span());
let tokens = quote! {
#[derive(Debug, ctxerr::thiserror::Error)]
#ast
#[derive(ctxerr::thiserror::Error)]
pub struct #base_name {
kind: #name_ident,
backtrace: Option<std::backtrace::Backtrace>,
location: Option<&'static core::panic::Location<'static>>,
}
impl std::fmt::Debug for #base_name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{:?}: {}", self.kind, self.kind)?;
if let Some(b) = &self.backtrace {
writeln!(f, "backtrace: \n{}", b)?;
}
Ok(())
}
}
impl std::fmt::Display for #base_name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}: {}", self.kind, self.kind)?;
if let Some(loc) = self.location {
writeln!(f, " file: {}:{}:{}", loc.file(), loc.line(), loc.column())?;
} else {
writeln!(f)?;
}
if let Some(b) = &self.backtrace {
writeln!(f, "backtrace: \n{}", b)?;
}
Ok(())
}
}
impl<T: Into<ErrorKind>> From<T> for #base_name {
#[track_caller]
fn from(val: T) -> Self {
let b = std::backtrace::Backtrace::capture();
Self{
kind: val.into(),
backtrace: Some(std::backtrace::Backtrace::capture()),
location: Some(core::panic::Location::caller()),
}
}
}
};
tokens.into()
}

22
examples/demo.rs Normal file
View File

@ -0,0 +1,22 @@
use ctxerr_derive::ctxerr;
#[ctxerr]
pub enum ErrorKind {
#[error("Some error {0}")]
Error1(#[from] std::io::Error),
}
fn operation() -> Result<(), std::io::Error> {
std::fs::File::open("")?;
Ok(())
}
fn test() -> Result<(), Error> {
Ok(operation()?)
}
fn main() {
if let Err(err) = test() {
println!("{}", err);
}
}

2
src/lib.rs Normal file
View File

@ -0,0 +1,2 @@
pub use ctxerr_derive::*;
pub use thiserror;