Skip to content

Commit e4b163e

Browse files
Gaëtan Schwartzgaetschwartz
authored andcommitted
feat: add From trait implementations for boxed types
1 parent 45e5388 commit e4b163e

File tree

4 files changed

+79
-3
lines changed

4 files changed

+79
-3
lines changed

impl/src/expand.rs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,23 @@ fn impl_struct(input: Struct) -> TokenStream {
175175
#ty #body
176176
}
177177
};
178-
let from_impl = quote_spanned! {span=>
178+
let mut from_impl = quote_spanned! {span=>
179179
#[automatically_derived]
180180
impl #impl_generics ::core::convert::From<#from> for #ty #ty_generics #where_clause {
181181
#from_function
182182
}
183183
};
184+
if let Some(from) = type_parameter_of_box(from_field.ty) {
185+
let body = from_some_source(from_field, backtrace_field, quote!(::thiserror::#private::Box::new(#source_var)));
186+
from_impl.extend(quote_spanned! {span=>
187+
#[automatically_derived]
188+
impl #impl_generics ::core::convert::From<#from> for #ty #ty_generics #where_clause {
189+
fn from(#source_var: #from) -> Self {
190+
#ty #body
191+
}
192+
}
193+
});
194+
}
184195
Some(quote! {
185196
#[allow(
186197
deprecated,
@@ -450,12 +461,23 @@ fn impl_enum(input: Enum) -> TokenStream {
450461
#ty::#variant #body
451462
}
452463
};
453-
let from_impl = quote_spanned! {span=>
464+
let mut from_impl = quote_spanned! {span=>
454465
#[automatically_derived]
455466
impl #impl_generics ::core::convert::From<#from> for #ty #ty_generics #where_clause {
456467
#from_function
457468
}
458469
};
470+
if let Some(boxed) = type_parameter_of_box(from_field.ty) {
471+
let body = from_some_source(from_field, backtrace_field, quote!(::thiserror::#private::Box::new(#source_var)));
472+
from_impl.extend(quote_spanned! {span=>
473+
#[automatically_derived]
474+
impl #impl_generics ::core::convert::From<#boxed> for #ty #ty_generics #where_clause {
475+
fn from(#source_var: #boxed) -> Self {
476+
#ty::#variant #body
477+
}
478+
}
479+
});
480+
}
459481
Some(quote! {
460482
#[allow(
461483
deprecated,
@@ -524,12 +546,20 @@ fn from_initializer(
524546
backtrace_field: Option<&Field>,
525547
source_var: &Ident,
526548
) -> TokenStream {
527-
let from_member = &from_field.member;
528549
let some_source = if type_is_option(from_field.ty) {
529550
quote!(::core::option::Option::Some(#source_var))
530551
} else {
531552
quote!(#source_var)
532553
};
554+
from_some_source(from_field, backtrace_field, some_source)
555+
}
556+
557+
fn from_some_source(
558+
from_field: &Field,
559+
backtrace_field: Option<&Field<'_>>,
560+
some_source: TokenStream,
561+
) -> TokenStream {
562+
let from_member = &from_field.member;
533563
let backtrace = backtrace_field.map(|backtrace_field| {
534564
let backtrace_member = &backtrace_field.member;
535565
if type_is_option(backtrace_field.ty) {
@@ -582,3 +612,29 @@ fn type_parameter_of_option(ty: &Type) -> Option<&Type> {
582612
_ => None,
583613
}
584614
}
615+
616+
fn type_parameter_of_box(ty: &Type) -> Option<&Type> {
617+
let path = match ty {
618+
Type::Path(ty) => &ty.path,
619+
_ => return None,
620+
};
621+
622+
let last = path.segments.last().unwrap();
623+
if last.ident != "Box" {
624+
return None;
625+
}
626+
627+
let bracketed = match &last.arguments {
628+
PathArguments::AngleBracketed(bracketed) => bracketed,
629+
_ => return None,
630+
};
631+
632+
if bracketed.args.len() != 1 {
633+
return None;
634+
}
635+
636+
match &bracketed.args[0] {
637+
GenericArgument::Type(arg) => Some(arg),
638+
_ => None,
639+
}
640+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@
273273
#[cfg(all(thiserror_nightly_testing, not(error_generic_member_access)))]
274274
compile_error!("Build script probe failed to compile.");
275275

276+
#[cfg(not(feature = "std"))]
277+
extern crate alloc;
276278
#[cfg(feature = "std")]
277279
extern crate std;
278280
#[cfg(feature = "std")]

src/private.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ pub use crate::display::AsDisplay;
77
pub use crate::provide::ThiserrorProvide;
88
#[doc(hidden)]
99
pub use crate::var::Var;
10+
#[cfg(not(feature = "std"))]
11+
#[doc(hidden)]
12+
pub use alloc::boxed::Box;
1013
#[doc(hidden)]
1114
pub use core::error::Error;
1215
#[cfg(all(feature = "std", not(thiserror_no_backtrace_type)))]
1316
#[doc(hidden)]
1417
pub use std::backtrace::Backtrace;
18+
#[cfg(feature = "std")]
19+
#[doc(hidden)]
20+
pub use std::boxed::Box;

tests/test_from.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ pub enum ErrorEnumOptional {
4343
},
4444
}
4545

46+
#[derive(Error, Debug)]
47+
#[error("...")]
48+
pub enum ErrorEnumBox {
49+
Test {
50+
#[from]
51+
source: Box<io::Error>,
52+
},
53+
}
54+
4655
#[derive(Error, Debug)]
4756
#[error("...")]
4857
pub enum Many {
@@ -51,6 +60,7 @@ pub enum Many {
5160
}
5261

5362
fn assert_impl<T: From<io::Error>>() {}
63+
fn assert_impl_box<T: From<Box<io::Error>>>() {}
5464

5565
#[test]
5666
fn test_from() {
@@ -60,5 +70,7 @@ fn test_from() {
6070
assert_impl::<ErrorTupleOptional>();
6171
assert_impl::<ErrorEnum>();
6272
assert_impl::<ErrorEnumOptional>();
73+
assert_impl::<ErrorEnumBox>();
74+
assert_impl_box::<ErrorEnumBox>();
6375
assert_impl::<Many>();
6476
}

0 commit comments

Comments
 (0)