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

Run all tests in no_std environments if std feature is disabled #269

Merged
merged 13 commits into from
Jul 5, 2023
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ jobs:

test-features:
name: test features
strategy:
fail-fast: false
matrix:
std: ["std", "no_std"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -128,7 +132,7 @@ jobs:
go install github.com/pelletier/go-toml/cmd/tomljson@latest
echo "$HOME/go/bin" >> $GITHUB_PATH
- run: ci/test_all_features.sh
- run: ci/test_all_features.sh ${{ matrix.std }}



Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
should prevent code style linters from attempting to modify the generated
code.
- Upgrade to `syn` 2.0.
- The `Error` derive now works in nightly `no_std` environments when enabling
`#![feature(error_in_core)]`.

### Fixed

Expand Down
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ members = ["impl"]
[dependencies]
derive_more-impl = { version = "=0.99.17", path = "impl" }

[build-dependencies]
rustc_version = { version = "0.4", optional = true }

[dev-dependencies]
rustversion = "1.0"
trybuild = "1.0.56"
Expand All @@ -50,7 +53,7 @@ debug = ["derive_more-impl/debug"]
deref = ["derive_more-impl/deref"]
deref_mut = ["derive_more-impl/deref_mut"]
display = ["derive_more-impl/display"]
error = ["derive_more-impl/error", "std"]
error = ["derive_more-impl/error"]
from = ["derive_more-impl/from"]
from_str = ["derive_more-impl/from_str"]
index = ["derive_more-impl/index"]
Expand Down Expand Up @@ -96,7 +99,7 @@ full = [
"try_unwrap",
]

testing-helpers = ["derive_more-impl/testing-helpers"]
testing-helpers = ["derive_more-impl/testing-helpers", "dep:rustc_version"]

[[test]]
name = "add_assign"
Expand Down Expand Up @@ -151,7 +154,7 @@ required-features = ["display"]
[[test]]
name = "error"
path = "tests/error_tests.rs"
required-features = ["error", "std"]
required-features = ["error"]

[[test]]
name = "from"
Expand Down
15 changes: 15 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#[cfg(not(feature = "testing-helpers"))]
fn detect_nightly() {}

#[cfg(feature = "testing-helpers")]
fn detect_nightly() {
use rustc_version::{version_meta, Channel};

if version_meta().unwrap().channel == Channel::Nightly {
println!("cargo:rustc-cfg=nightly");
}
}

fn main() {
detect_nightly();
}
10 changes: 8 additions & 2 deletions ci/test_all_features.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
#!/usr/bin/env bash

std=''
if [ "${1:-}" = 'std' ]; then
std=',std'
fi

set -euxo pipefail

for feature in $(tomljson Cargo.toml | jq --raw-output '.features | keys[]' | grep -v 'default\|std\|testing-helpers'); do
cargo test -p derive_more --tests --no-default-features --features "$feature,testing-helpers";
for feature in $(tomljson Cargo.toml | jq --raw-output '.features | keys[]' | grep -v 'default\|std\|full\|testing-helpers'); do
cargo +nightly test -p derive_more --tests --no-default-features --features "$feature$std,testing-helpers"
done
2 changes: 1 addition & 1 deletion impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ unicode-xid = { version = "0.2.2", optional = true }
rustc_version = { version = "0.4", optional = true }

[dev-dependencies]
derive_more = { path = "..", features = ["add", "debug", "error", "from_str", "not", "try_into", "try_unwrap"] }
derive_more = { path = "..", features = ["add", "debug", "error", "from_str", "not", "std", "try_into", "try_unwrap"] }
itertools = "0.11.0"

[badges]
Expand Down
14 changes: 13 additions & 1 deletion impl/doc/error.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,25 @@ ignored for one of these methods by using `#[error(not(backtrace))]` or
`#[error(not(source))]`.


### What works in `no_std`?

If you want to use the `Error` derive on `no_std` environments, then you need to
compile with nightly and enable this feature:
```ignore
#![feature(error_in_core)]
```

Backtraces don't work though, because the `Backtrace` type is only available in
`std`.




## Example usage

```rust
# #![cfg_attr(nightly, feature(error_generic_member_access, provide_any))]
// Nightly requires enabling this features:
// Nightly requires enabling these features:
// #![feature(error_generic_member_access, provide_any)]
# #[cfg(not(nightly))] fn main() {}
# #[cfg(nightly)] fn main() {
Expand Down
24 changes: 12 additions & 12 deletions impl/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn expand(
let state = State::with_attr_params(
input,
trait_name,
quote! { ::std::error },
quote! { ::derive_more::__private::Error },
trait_name.to_lowercase(),
allowed_attr_params(),
)?;
Expand All @@ -39,7 +39,7 @@ pub fn expand(

let source = source.map(|source| {
quote! {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
fn source(&self) -> Option<&(dyn ::derive_more::__private::Error + 'static)> {
use ::derive_more::__private::AsDynError;
#source
}
Expand All @@ -48,7 +48,7 @@ pub fn expand(

let provide = provide.map(|provide| {
quote! {
fn provide<'_demand>(&'_demand self, demand: &mut ::std::any::Demand<'_demand>) {
fn provide<'_demand>(&'_demand self, demand: &mut ::core::any::Demand<'_demand>) {
#provide
}
}
Expand All @@ -62,7 +62,7 @@ pub fn expand(
&generics,
quote! {
where
#ident #ty_generics: ::std::fmt::Debug + ::std::fmt::Display
#ident #ty_generics: ::core::fmt::Debug + ::core::fmt::Display
},
);
}
Expand All @@ -73,7 +73,7 @@ pub fn expand(
&generics,
quote! {
where
#(#bounds: ::std::fmt::Debug + ::std::fmt::Display + ::std::error::Error + 'static),*
#(#bounds: ::core::fmt::Debug + ::core::fmt::Display + ::derive_more::__private::Error + 'static),*
},
);
}
Expand All @@ -82,7 +82,7 @@ pub fn expand(

let render = quote! {
#[automatically_derived]
impl #impl_generics ::std::error::Error for #ident #ty_generics #where_clause {
impl #impl_generics ::derive_more::__private::Error for #ident #ty_generics #where_clause {
#source
#provide
}
Expand Down Expand Up @@ -207,7 +207,7 @@ impl<'input, 'state> ParsedFields<'input, 'state> {
let source_provider = self.source.map(|source| {
let source_expr = &self.data.members[source];
quote! {
::std::error::Error::provide(&#source_expr, demand);
::derive_more::__private::Error::provide(&#source_expr, demand);
}
});
let backtrace_provider = self
Expand All @@ -217,7 +217,7 @@ impl<'input, 'state> ParsedFields<'input, 'state> {
.then(|| {
let backtrace_expr = &self.data.members[backtrace];
quote! {
demand.provide_ref::<std::backtrace::Backtrace>(&#backtrace_expr);
demand.provide_ref::<::std::backtrace::Backtrace>(&#backtrace_expr);
}
});

Expand All @@ -237,7 +237,7 @@ impl<'input, 'state> ParsedFields<'input, 'state> {
let pattern = self.data.matcher(&[source], &[quote! { source }]);
Some(quote! {
#pattern => {
::std::error::Error::provide(source, demand);
::derive_more::__private::Error::provide(source, demand);
}
})
}
Expand All @@ -248,16 +248,16 @@ impl<'input, 'state> ParsedFields<'input, 'state> {
);
Some(quote! {
#pattern => {
demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
::std::error::Error::provide(source, demand);
demand.provide_ref::<::std::backtrace::Backtrace>(backtrace);
::derive_more::__private::Error::provide(source, demand);
}
})
}
None => {
let pattern = self.data.matcher(&[backtrace], &[quote! { backtrace }]);
Some(quote! {
#pattern => {
demand.provide_ref::<std::backtrace::Backtrace>(backtrace);
demand.provide_ref::<::std::backtrace::Backtrace>(backtrace);
}
})
}
Expand Down
16 changes: 10 additions & 6 deletions impl/src/fmt/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,12 +331,16 @@ impl<'a> Expansion<'a> {
/// Generates trait bounds for a struct or an enum variant.
fn generate_bounds(&self) -> Vec<syn::WherePredicate> {
let Some(fmt) = &self.attrs.fmt else {
return self.fields.iter().next().map(|f| {
let ty = &f.ty;
let trait_ident = &self.trait_ident;
vec![parse_quote! { #ty: ::core::fmt::#trait_ident }]
})
.unwrap_or_default();
return self
.fields
.iter()
.next()
.map(|f| {
let ty = &f.ty;
let trait_ident = &self.trait_ident;
vec![parse_quote! { #ty: ::core::fmt::#trait_ident }]
})
.unwrap_or_default();
};

fmt.bounded_types(self.fields)
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(all(not(feature = "std"), feature = "error"), feature(error_in_core))]
// These links overwrite the ones in `README.md`
// to become proper intra-doc links in Rust docs.
//! [`From`]: crate::From
Expand Down Expand Up @@ -77,6 +78,11 @@ mod vendor;
#[doc(hidden)]
#[cfg(feature = "error")]
pub mod __private {
#[cfg(not(feature = "std"))]
pub use ::core::error::Error;
#[cfg(feature = "std")]
pub use ::std::error::Error;

pub use crate::vendor::thiserror::aserror::AsDynError;
}

Expand Down
6 changes: 5 additions & 1 deletion src/vendor/thiserror/aserror.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#[cfg(not(feature = "std"))]
use core::error::Error;
#[cfg(feature = "std")]
use std::error::Error;
use std::panic::UnwindSafe;

use core::panic::UnwindSafe;

pub trait AsDynError<'a>: Sealed {
fn as_dyn_error(&self) -> &(dyn Error + 'a);
Expand Down
1 change: 1 addition & 0 deletions tests/add.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(dead_code)]

use derive_more::Add;
Expand Down
1 change: 1 addition & 0 deletions tests/add_assign.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(dead_code)]

use derive_more::AddAssign;
Expand Down
Loading