Why can a no_std crate depend on a crate that uses std?

717 Views Asked by At

In the example, hs reexport HashSet from std. But it compiles without error or warning. Why?

#![no_std]

pub use hs::HashSet;

pub fn new() -> HashSet<usize> {
    HashSet::new()
}

pub fn insert(a: &mut HashSet<usize>, v: usize) {
    a.insert(v);
}
2

There are 2 best solutions below

1
On BEST ANSWER

Well #![no_std] just means that you don't include std by default. It doesn't mean you can't explicitly or implicitly (i.e. through other crates) still include std. In other words #![no_std] does not prohibit using std but it disables using it by default.

For example this works, too:

#![no_std]
extern crate std;
fn main() {
    std::println!("hello!");
}
0
On

Every crate in Rust is opt-in, that is, you need to explicitly ask it as a dependency to have it as a dependency of your code (usually through Cargo.toml). All, but one: the standard library (hence the name), which is opt-out. That is to say, if you do nothing, Rust will implicitly understand you require it as a dependency, and you explicitly need to tell it that you don't (with #![no_std]) to prevent this. Besides this, std behaves like any other crate, that is, even if it's not one of your direct dependencies, you can still access to reexports of your actual dependencies.

It should be noted, however, that there is no reason to not want to standard library as a dependency except in situations where you just don't have it (for instance, if you are writing embedded code, or a kernel, or ...). In this case, having std as a (transitive) dependency will just fail at compile time, which means that not only you have to use #[no_std], but so should all the dependencies you have, and their dependencies, and so on... In your case, you have annotated your code with #[no_std], but there was no hard requirement for you to do so, so there is no problem in having a dependency that has access to std.

Finally, note that some parts of the standard library are accessible even if the whole standard library is not. For instance, core is not OS-dependent, so you can use it even on embedded, and usually obtaining alloc one way or another (that is, implementing what is required yourself for instance) also provides you quite a lot of the standard library. In particular, I think HashSet only requires core and alloc to be available, not the whole standard library.