Skip to content

Commit

Permalink
no_std support on nightly
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianUekermann committed Feb 19, 2023
1 parent 0010b0f commit 49fe623
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 45 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ rust-version = "1.31"
[dependencies]
thiserror-impl = { version = "=1.0.38", path = "impl" }

[features]
default = ["std"]
std = ["thiserror-impl/std"]

[dev-dependencies]
anyhow = "1.0.65"
ref-cast = "1.0"
Expand Down
3 changes: 3 additions & 0 deletions impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0.45"

[features]
std = []

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
2 changes: 1 addition & 1 deletion impl/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,6 @@ impl ToTokens for Display<'_> {
impl ToTokens for Trait {
fn to_tokens(&self, tokens: &mut TokenStream) {
let trait_name = format_ident!("{}", format!("{:?}", self));
tokens.extend(quote!(std::fmt::#trait_name));
tokens.extend(quote!(core::fmt::#trait_name));
}
}
91 changes: 51 additions & 40 deletions impl/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ fn impl_struct(input: Struct) -> TokenStream {
let source_body = if input.attrs.transparent.is_some() {
let only_field = &input.fields[0];
if only_field.contains_generic {
error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error));
error_inferred_bounds.insert(only_field.ty, quote!(thiserror::__private::error::Error));
}
let member = &only_field.member;
Some(quote! {
std::error::Error::source(self.#member.as_dyn_error())
thiserror::__private::error::Error::source(self.#member.as_dyn_error())
})
} else if let Some(source_field) = input.source_field() {
let source = &source_field.member;
if source_field.contains_generic {
let ty = unoptional_type(source_field.ty);
error_inferred_bounds.insert(ty, quote!(std::error::Error + 'static));
error_inferred_bounds.insert(ty, quote!(thiserror::__private::error::Error + 'static));
}
let asref = if type_is_option(source_field.ty) {
Some(quote_spanned!(source.span()=> .as_ref()?))
Expand All @@ -45,14 +45,14 @@ fn impl_struct(input: Struct) -> TokenStream {
};
let dyn_error = quote_spanned!(source.span()=> self.#source #asref.as_dyn_error());
Some(quote! {
std::option::Option::Some(#dyn_error)
core::option::Option::Some(#dyn_error)
})
} else {
None
};
let source_method = source_body.map(|body| {
quote! {
fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
fn source(&self) -> core::option::Option<&(dyn thiserror::__private::error::Error + 'static)> {
use thiserror::__private::AsDynError;
#body
}
Expand All @@ -66,7 +66,7 @@ fn impl_struct(input: Struct) -> TokenStream {
let source = &source_field.member;
let source_provide = if type_is_option(source_field.ty) {
quote_spanned! {source.span()=>
if let std::option::Option::Some(source) = &self.#source {
if let core::option::Option::Some(source) = &self.#source {
source.thiserror_provide(#demand);
}
}
Expand All @@ -79,7 +79,7 @@ fn impl_struct(input: Struct) -> TokenStream {
None
} else if type_is_option(backtrace_field.ty) {
Some(quote! {
if let std::option::Option::Some(backtrace) = &self.#backtrace {
if let core::option::Option::Some(backtrace) = &self.#backtrace {
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
}
})
Expand All @@ -95,7 +95,7 @@ fn impl_struct(input: Struct) -> TokenStream {
}
} else if type_is_option(backtrace_field.ty) {
quote! {
if let std::option::Option::Some(backtrace) = &self.#backtrace {
if let core::option::Option::Some(backtrace) = &self.#backtrace {
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
}
}
Expand All @@ -105,7 +105,7 @@ fn impl_struct(input: Struct) -> TokenStream {
}
};
quote! {
fn provide<'_demand>(&'_demand self, #demand: &mut std::any::Demand<'_demand>) {
fn provide<'_demand>(&'_demand self, #demand: &mut core::any::Demand<'_demand>) {
#body
}
}
Expand All @@ -116,15 +116,12 @@ fn impl_struct(input: Struct) -> TokenStream {
let only_field = &input.fields[0].member;
display_implied_bounds.insert((0, Trait::Display));
Some(quote! {
std::fmt::Display::fmt(&self.#only_field, __formatter)
core::fmt::Display::fmt(&self.#only_field, __formatter)
})
} else if let Some(display) = &input.attrs.display {
display_implied_bounds = display.implied_bounds.clone();
let use_as_display = if display.has_bonus_display {
Some(quote! {
#[allow(unused_imports)]
use thiserror::__private::{DisplayAsDisplay, PathAsDisplay};
})
Some(use_as_display())
} else {
None
};
Expand All @@ -149,9 +146,9 @@ fn impl_struct(input: Struct) -> TokenStream {
let display_where_clause = display_inferred_bounds.augment_where_clause(input.generics);
quote! {
#[allow(unused_qualifications)]
impl #impl_generics std::fmt::Display for #ty #ty_generics #display_where_clause {
impl #impl_generics core::fmt::Display for #ty #ty_generics #display_where_clause {
#[allow(clippy::used_underscore_binding)]
fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
fn fmt(&self, __formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
#body
}
}
Expand All @@ -164,7 +161,7 @@ fn impl_struct(input: Struct) -> TokenStream {
let body = from_initializer(from_field, backtrace_field);
quote! {
#[allow(unused_qualifications)]
impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
impl #impl_generics core::convert::From<#from> for #ty #ty_generics #where_clause {
#[allow(deprecated)]
fn from(source: #from) -> Self {
#ty #body
Expand Down Expand Up @@ -203,18 +200,22 @@ fn impl_enum(input: Enum) -> TokenStream {
if variant.attrs.transparent.is_some() {
let only_field = &variant.fields[0];
if only_field.contains_generic {
error_inferred_bounds.insert(only_field.ty, quote!(std::error::Error));
error_inferred_bounds
.insert(only_field.ty, quote!(thiserror::__private::error::Error));
}
let member = &only_field.member;
let source = quote!(std::error::Error::source(transparent.as_dyn_error()));
let source = quote!(thiserror::__private::error::Error::source(
transparent.as_dyn_error()
));
quote! {
#ty::#ident {#member: transparent} => #source,
}
} else if let Some(source_field) = variant.source_field() {
let source = &source_field.member;
if source_field.contains_generic {
let ty = unoptional_type(source_field.ty);
error_inferred_bounds.insert(ty, quote!(std::error::Error + 'static));
error_inferred_bounds
.insert(ty, quote!(thiserror::__private::error::Error + 'static));
}
let asref = if type_is_option(source_field.ty) {
Some(quote_spanned!(source.span()=> .as_ref()?))
Expand All @@ -224,16 +225,16 @@ fn impl_enum(input: Enum) -> TokenStream {
let varsource = quote!(source);
let dyn_error = quote_spanned!(source.span()=> #varsource #asref.as_dyn_error());
quote! {
#ty::#ident {#source: #varsource, ..} => std::option::Option::Some(#dyn_error),
#ty::#ident {#source: #varsource, ..} => core::option::Option::Some(#dyn_error),
}
} else {
quote! {
#ty::#ident {..} => std::option::Option::None,
#ty::#ident {..} => core::option::Option::None,
}
}
});
Some(quote! {
fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
fn source(&self) -> core::option::Option<&(dyn thiserror::__private::error::Error + 'static)> {
use thiserror::__private::AsDynError;
#[allow(deprecated)]
match self {
Expand All @@ -258,7 +259,7 @@ fn impl_enum(input: Enum) -> TokenStream {
let varsource = quote!(source);
let source_provide = if type_is_option(source_field.ty) {
quote_spanned! {source.span()=>
if let std::option::Option::Some(source) = #varsource {
if let core::option::Option::Some(source) = #varsource {
source.thiserror_provide(#demand);
}
}
Expand All @@ -269,7 +270,7 @@ fn impl_enum(input: Enum) -> TokenStream {
};
let self_provide = if type_is_option(backtrace_field.ty) {
quote! {
if let std::option::Option::Some(backtrace) = backtrace {
if let core::option::Option::Some(backtrace) = backtrace {
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
}
}
Expand Down Expand Up @@ -297,7 +298,7 @@ fn impl_enum(input: Enum) -> TokenStream {
let varsource = quote!(source);
let source_provide = if type_is_option(source_field.ty) {
quote_spanned! {backtrace.span()=>
if let std::option::Option::Some(source) = #varsource {
if let core::option::Option::Some(source) = #varsource {
source.thiserror_provide(#demand);
}
}
Expand All @@ -317,7 +318,7 @@ fn impl_enum(input: Enum) -> TokenStream {
let backtrace = &backtrace_field.member;
let body = if type_is_option(backtrace_field.ty) {
quote! {
if let std::option::Option::Some(backtrace) = backtrace {
if let core::option::Option::Some(backtrace) = backtrace {
#demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
}
}
Expand All @@ -338,7 +339,7 @@ fn impl_enum(input: Enum) -> TokenStream {
}
});
Some(quote! {
fn provide<'_demand>(&'_demand self, #demand: &mut std::any::Demand<'_demand>) {
fn provide<'_demand>(&'_demand self, #demand: &mut core::any::Demand<'_demand>) {
#[allow(deprecated)]
match self {
#(#arms)*
Expand All @@ -357,10 +358,7 @@ fn impl_enum(input: Enum) -> TokenStream {
.as_ref()
.map_or(false, |display| display.has_bonus_display)
}) {
Some(quote! {
#[allow(unused_imports)]
use thiserror::__private::{DisplayAsDisplay, PathAsDisplay};
})
Some(use_as_display())
} else {
None
};
Expand All @@ -382,7 +380,7 @@ fn impl_enum(input: Enum) -> TokenStream {
Member::Unnamed(index) => format_ident!("_{}", index),
};
display_implied_bounds.insert((0, Trait::Display));
quote!(std::fmt::Display::fmt(#only_field, __formatter))
quote!(core::fmt::Display::fmt(#only_field, __formatter))
}
};
for (field, bound) in display_implied_bounds {
Expand All @@ -401,8 +399,8 @@ fn impl_enum(input: Enum) -> TokenStream {
let display_where_clause = display_inferred_bounds.augment_where_clause(input.generics);
Some(quote! {
#[allow(unused_qualifications)]
impl #impl_generics std::fmt::Display for #ty #ty_generics #display_where_clause {
fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
impl #impl_generics core::fmt::Display for #ty #ty_generics #display_where_clause {
fn fmt(&self, __formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
#use_as_display
#[allow(unused_variables, deprecated, clippy::used_underscore_binding)]
match #void_deref self {
Expand All @@ -423,7 +421,7 @@ fn impl_enum(input: Enum) -> TokenStream {
let body = from_initializer(from_field, backtrace_field);
Some(quote! {
#[allow(unused_qualifications)]
impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
impl #impl_generics core::convert::From<#from> for #ty #ty_generics #where_clause {
#[allow(deprecated)]
fn from(source: #from) -> Self {
#ty::#variant #body
Expand Down Expand Up @@ -469,19 +467,19 @@ fn fields_pat(fields: &[Field]) -> TokenStream {
fn from_initializer(from_field: &Field, backtrace_field: Option<&Field>) -> TokenStream {
let from_member = &from_field.member;
let some_source = if type_is_option(from_field.ty) {
quote!(std::option::Option::Some(source))
quote!(core::option::Option::Some(source))
} else {
quote!(source)
};
let backtrace = backtrace_field.map(|backtrace_field| {
let backtrace_member = &backtrace_field.member;
if type_is_option(backtrace_field.ty) {
quote! {
#backtrace_member: std::option::Option::Some(std::backtrace::Backtrace::capture()),
#backtrace_member: core::option::Option::Some(std::backtrace::Backtrace::capture()),
}
} else {
quote! {
#backtrace_member: std::convert::From::from(std::backtrace::Backtrace::capture()),
#backtrace_member: core::convert::From::from(std::backtrace::Backtrace::capture()),
}
}
});
Expand Down Expand Up @@ -540,7 +538,20 @@ fn spanned_error_trait(input: &DeriveInput) -> TokenStream {
};
let first_span = vis_span.unwrap_or(data_span);
let last_span = input.ident.span();
let path = quote_spanned!(first_span=> std::error::);
let path = quote_spanned!(first_span=> thiserror::__private::error::);
let error = quote_spanned!(last_span=> Error);
quote!(#path #error)
}

fn use_as_display() -> TokenStream {
#[cfg(feature = "std")]
quote! {
#[allow(unused_imports)]
use thiserror::__private::{DisplayAsDisplay, PathAsDisplay};
}
#[cfg(not(feature = "std"))]
quote! {
#[allow(unused_imports)]
use thiserror::__private::DisplayAsDisplay;
}
}
5 changes: 4 additions & 1 deletion src/aserror.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::error::Error;
use crate::__private::error::Error;
#[cfg(not(feature = "std"))]
use core::panic::UnwindSafe;
#[cfg(feature = "std")]
use std::panic::UnwindSafe;

pub trait AsDynError<'a>: Sealed {
Expand Down
6 changes: 5 additions & 1 deletion src/display.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fmt::Display;
use core::fmt::Display;
#[cfg(feature = "std")]
use std::path::{self, Path, PathBuf};

pub trait DisplayAsDisplay {
Expand All @@ -11,16 +12,19 @@ impl<T: Display> DisplayAsDisplay for &T {
}
}

#[cfg(feature = "std")]
pub trait PathAsDisplay {
fn as_display(&self) -> path::Display<'_>;
}

#[cfg(feature = "std")]
impl PathAsDisplay for Path {
fn as_display(&self) -> path::Display<'_> {
self.display()
}
}

#[cfg(feature = "std")]
impl PathAsDisplay for PathBuf {
fn as_display(&self) -> path::Display<'_> {
self.display()
Expand Down
13 changes: 12 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@
clippy::wildcard_imports,
)]
#![cfg_attr(provide_any, feature(provide_any))]
#![cfg_attr(not(feature = "std"), feature(error_in_core))]
#![no_std]
#[cfg(feature = "std")]
extern crate std;

mod aserror;
mod display;
Expand All @@ -247,8 +251,15 @@ pub use thiserror_impl::*;
// Not public API.
#[doc(hidden)]
pub mod __private {
#[cfg(not(feature = "std"))]
pub use core::error;
#[cfg(feature = "std")]
pub use std::error;

pub use crate::aserror::AsDynError;
pub use crate::display::{DisplayAsDisplay, PathAsDisplay};
pub use crate::display::DisplayAsDisplay;
#[cfg(feature = "std")]
pub use crate::display::PathAsDisplay;
#[cfg(provide_any)]
pub use crate::provide::ThiserrorProvide;
}
2 changes: 1 addition & 1 deletion src/provide.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::any::{Demand, Provider};
use core::any::{Demand, Provider};

pub trait ThiserrorProvide: Sealed {
fn thiserror_provide<'a>(&'a self, demand: &mut Demand<'a>);
Expand Down

0 comments on commit 49fe623

Please sign in to comment.