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

Support no_std Usage #47

Open
ZackPierce opened this issue Apr 23, 2018 · 18 comments
Open

Support no_std Usage #47

ZackPierce opened this issue Apr 23, 2018 · 18 comments
Labels
feature-request This issue is requesting new functionality partial-fix Workaround available, or issue partially addressed

Comments

@ZackPierce
Copy link
Contributor

It would be excellent to be able to use proptest in no_std environments like embedded development and wasm-land. Some features of proptest are not likely to be viable in no_std, but a meaningful subset should be possible.

In the long run, this would likely stratify into three tiers of capability: std, no_std + alloc, and finally no_std without access to a heap allocator. Feature flags should be sufficient to provide users a means of selecting the features available in their environment. Default feature flags would allow a no-effort transition for extant users.

Accomplishing this would likely require us to:

  • Identify which capabilities are feasible in which environment, and conditionally compile modules using feature flags. This may require reorganization of some files to avoid overly broad restrictions.
  • Reduce dependency on external crates which must use the standard library (e.g. quick-error) .
  • Use the no_std related feature flag options for crates that support such (e.g. lazy_static ) .
  • Replace current internal uses of std library bits with core-based alternatives or convert into optional capabilities.
  • Come up with a plan to conditionally export core-flavored variants of the arbitrary/_std submodules where the types in question are simple re-exposures of core types.

I'm sure there's more to do that I haven't yet pointed out, or mistakes in the above analysis.

From a practical standpoint, in order to show good faith and "skin in the game", I've started working on getting to the first additional tier of capability (no_std + alloc) working, beginning with adding or exposing no_std modes for dependencies ( see: contain-rs/bit-vec#49 and contain-rs/bit-set#15).

I'd be very happy to receive any guidance or corrections possible.

@AltSysrq AltSysrq added the feature-request This issue is requesting new functionality label Apr 24, 2018
@AltSysrq
Copy link
Collaborator

Possibly a dumb question (as I have no no_std experience), but is it not possible to set a project up so that the main build is no_std but tests have the stdlib?

I'm not sure about the possibility of supporting running without heap allocation. There's certainly a subset of the API that could work there, but I'm not sure how useful it'd be.

As for core + alloc, off hand it does seem fairly viable. There's three main things I can think of that would be excluded:

  • Obviously anything in arbitrary/_std that doesn't have a core/alloc component.
  • Failure case persistence.
  • Handling panics.

The last one seems like a possibly big deal, since it means that proptest can't really do its job on a test that can fail in any way other than returning a failure code normally. But I guess it could still be useful.

In any case, thanks for being willing to assist with this!

@ZackPierce
Copy link
Contributor Author

Thank you for the encouragement, @AltSysrq .

Yep, it is often possible to arrange a project such that the tests are run with access to the standard library (e.g. whilst running on a local linux/windows/osx dev machine), even though the main project is geared for an embedded use case.

However, this is not always the case -- sometimes the capabilities that need to be exercised are only truly available when being run in a context without access to the standard library at all. For example, when running on an esoteric device with custom (sometimes black-box) features and no prayer of a full stdlib in sight.

That sort of "in-vivo" testing is what I'm hoping to cover with this effort.

I think persistence can be handled conventionally enough by being made optional -- perhaps factoring it into a trait with a few implementations (noop, filesystem, manual piping, etc), the present filesystem-based variant of which could be made std-only.

As for panics, you're right that we'd be pushed into a returned-failure-signifying style. There is an alternative available, which utest uses, that overrides panic! in order to flip some global static bits that the test runner probes. However, I'm not keen on spooky action at a distance or fragile single-package-level macro overloads. I'd rather give the return-value based approach a shot first, since it seems more Rustic how.

@memoryruins
Copy link

Related issue rust-embedded/wg#47

@AltSysrq
Copy link
Collaborator

AltSysrq commented May 3, 2018

no_std + alloc support is available in 0.7.0 via #48

@jparris
Copy link

jparris commented Jul 31, 2018

@ZackPierce can you add an example or more documentation on setting up proptest in a #![no_std] environment. I don't want to disrail this bug for support but addingproptest = {version="0.7", features = ["alloc", "nightly"]} to my Cargo.toml doesn't work because the dependencies are still wanting to use std.

-Jon

@AltSysrq
Copy link
Collaborator

@jparris A couple pointers to get you started:

  • You additionally need default-features=false to opt out of the std default feature.

  • Only version 0.8.4 (the latest as of writing) is compatible with the latest nightly rust build.

I think there may be a bit more fiddling necessary for actually writing the tests, and unfortunately I don't have any examples handy.

@Lokathor
Copy link

Definitely an example is needed for how to no_std the crate.

I also attempted to use it:

proptest = { version = "0.8", defatult-features = false, features = [] }

but then it pulled in many std using things. There should just be an example of every dependency you have to list out with default-features off

@AltSysrq
Copy link
Collaborator

[dev-dependencies.proptest]
version = "0.8"
default-features = false
features = ["alloc", "unstable"]

This works for me, assuming I'm testing it correctly. I will add documenting this to my to do list for the next release.

@Lokathor
Copy link

Lokathor commented Dec 31, 2018

When using that configuration, I get a problem with the transitive lazy_static dependency:

   Compiling num-traits v0.2.6
   Compiling rand_core v0.3.0
   Compiling lazy_static v1.2.0
   Compiling gba-proc-macro v0.5.0
error[E0463]: can't find crate for `std`
 --> C:\Users\Daniel\.cargo\registry\src\gh.neting.cc-1ecc6299db9ec823\lazy_static-1.2.0\src\inline_lazy.rs:9:1
  |
9 | extern crate std;
  | ^^^^^^^^^^^^^^^^^ can't find crate
  |
  = note: the `thumbv4-none-agb-15848137922264977313` target may not be installed

error: aborting due to previous error

@AltSysrq
Copy link
Collaborator

Oh, we have a separate nightly feature you also need for lazy_static to work until #112 is released.

Do you know of a way to ensure nothing brings std in short of compiling for a target that doesn't have std? Clearly the way I was testing that (a #![no_std] bin crate) doesn't work.

@Lokathor
Copy link

I don't.

In my particularly strange use case, I don't need proptest to run on the device, I just need it for tests that run on the local machine. However, [dev-dependences] is for both tests and examples, so if I want my examples to target the device I can't have proptest as a dev-dependency :/

@nivkner
Copy link
Contributor

nivkner commented Jan 8, 2019

@AltSysrq to test that no_std works you can use the fact that Cortex-M targets ship only with core and use cargo check --target thumbv7em-none-eabihf since checking only requires getting the target with rustup, and not an actual ARM machine

@goral09
Copy link

goral09 commented Jan 8, 2019

@AltSysrq It fails to compile in my case as well. This is my configuration:

[dev-dependencies.proptest]
version = "0.8"
default-features = false
features = ["alloc", "unstable"]  

and the error:

error[E0277]: the trait bound `str: proptest::strategy::Strategy` is not satisfied
  --> tests/bytesrepr_test.rs:3:1
   |
3  | / proptest! {
4  | |   #[test]
5  | |   fn test_addition(a in 0..10, b in 0..10) {
6  | |     prop_assert!(a + b <= 18);
...  |
13 | |   }
14 | | }
   | |_^ the trait `proptest::strategy::Strategy` is not implemented for `str`
   |
   = note: required because of the requirements on the impl of `proptest::strategy::Strategy` for `&str`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

@nivkner
Copy link
Contributor

nivkner commented Jan 8, 2019

@goral09 as mentioned previously you also need the nightly feature for now, so it should be:

[dev-dependencies.proptest]
version = "0.8"
default-features = false
features = ["alloc", "unstable", "nightly"]

@goral09
Copy link

goral09 commented Jan 8, 2019

Thanks @nivkner but this doesn't solve my problem. Still getting the same errors.

@AltSysrq
Copy link
Collaborator

AltSysrq commented Feb 4, 2019

@nivkner Thanks for that cargo test suggestion. I believe 0.9.0 should work for you.

@AltSysrq
Copy link
Collaborator

AltSysrq commented Feb 4, 2019

@goral09 I'm not entirely sure what's going on in your case. The error message itself suggests you're trying to use a regex-based String strategy, which is only supported on std. Is there such a usage between lines 6 and 13?

@AltSysrq
Copy link
Collaborator

AltSysrq commented Feb 4, 2019

Also, there's now documentation on using no_std with proptest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request This issue is requesting new functionality partial-fix Workaround available, or issue partially addressed
Projects
None yet
Development

No branches or pull requests

7 participants