mirror of
https://github.com/dtolnay/thiserror.git
synced 2025-04-06 06:17:39 +03:00
Add backtrace() method for structs
This commit is contained in:
parent
4cdeec15e5
commit
c86452cc68
1 changed files with 44 additions and 1 deletions
|
@ -3,7 +3,7 @@ use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{
|
use syn::{
|
||||||
Data, DataEnum, DataStruct, DeriveInput, Error, Fields, FieldsNamed, FieldsUnnamed, Index,
|
Data, DataEnum, DataStruct, DeriveInput, Error, Fields, FieldsNamed, FieldsUnnamed, Index,
|
||||||
Member, Result,
|
Member, Result, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn derive(input: &DeriveInput) -> Result<TokenStream> {
|
pub fn derive(input: &DeriveInput) -> Result<TokenStream> {
|
||||||
|
@ -27,6 +27,12 @@ fn struct_error(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream> {
|
||||||
Fields::Unit => None,
|
Fields::Unit => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let backtrace = match &data.fields {
|
||||||
|
Fields::Named(fields) => braced_struct_backtrace(fields)?,
|
||||||
|
Fields::Unnamed(fields) => tuple_struct_backtrace(fields)?,
|
||||||
|
Fields::Unit => None,
|
||||||
|
};
|
||||||
|
|
||||||
let source_method = source.map(|source| {
|
let source_method = source.map(|source| {
|
||||||
quote! {
|
quote! {
|
||||||
fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
@ -35,9 +41,18 @@ fn struct_error(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let backtrace_method = backtrace.map(|backtrace| {
|
||||||
|
quote! {
|
||||||
|
fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
|
||||||
|
std::option::Option::Some(&self.#backtrace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
impl #impl_generics std::error::Error for #ident #ty_generics #where_clause {
|
impl #impl_generics std::error::Error for #ident #ty_generics #where_clause {
|
||||||
#source_method
|
#source_method
|
||||||
|
#backtrace_method
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -60,6 +75,34 @@ fn tuple_struct_source(fields: &FieldsUnnamed) -> Result<Option<Member>> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn braced_struct_backtrace(fields: &FieldsNamed) -> Result<Option<Member>> {
|
||||||
|
for field in &fields.named {
|
||||||
|
if type_is_backtrace(&field.ty) {
|
||||||
|
return Ok(Some(Member::Named(field.ident.as_ref().unwrap().clone())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_struct_backtrace(fields: &FieldsUnnamed) -> Result<Option<Member>> {
|
||||||
|
for (i, field) in fields.unnamed.iter().enumerate() {
|
||||||
|
if type_is_backtrace(&field.ty) {
|
||||||
|
return Ok(Some(Member::Unnamed(Index::from(i))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_is_backtrace(ty: &Type) -> bool {
|
||||||
|
let path = match ty {
|
||||||
|
Type::Path(ty) => &ty.path,
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let last = path.segments.last().unwrap();
|
||||||
|
last.ident == "Backtrace" && last.arguments.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
fn enum_error(input: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
|
fn enum_error(input: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
|
||||||
let _ = input;
|
let _ = input;
|
||||||
let _ = data;
|
let _ = data;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue