Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no_std support on nightly #211

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
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
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
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
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
@@ -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
@@ -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
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
@@ -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