Skip to content

NO_STD#370

Draft
zendurix wants to merge 4 commits intopetgraph:masterfrom
zendurix:better_no_std
Draft

NO_STD#370
zendurix wants to merge 4 commits intopetgraph:masterfrom
zendurix:better_no_std

Conversation

@zendurix
Copy link

I have succesfully implemented no_std with hasbrown crate (to enable no_std use with default-features = false
It passed no_std check (https://github.com/mystor/cargo-no-std-check)

@zendurix zendurix mentioned this pull request Aug 26, 2020
Copy link
Member

@XVilka XVilka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure use crate::lib::*; is a good practice. The idea to wrap everything is good, but probably better to import only used modules. Please also add the corresponding CI job from #238

@XVilka
Copy link
Member

XVilka commented Aug 26, 2020

Also CI is failing:

error[E0432]: unresolved imports `rand::thread_rng`, `rand::ChaChaRng`
 --> tests/unionfind.rs:5:12
  |
5 | use rand::{thread_rng, ChaChaRng, Rng, SeedableRng};
  |            ^^^^^^^^^^  ^^^^^^^^^ no `ChaChaRng` in the root
  |            |
  |            no `thread_rng` in the root
warning: unused import: `SeedableRng`
 --> tests/unionfind.rs:5:40
  |
5 | use rand::{thread_rng, ChaChaRng, Rng, SeedableRng};
  |                                        ^^^^^^^^^^^
  |
  = note: #[warn(unused_imports)] on by default
warning: unused import: `Rng`
 --> tests/unionfind.rs:5:35
  |
5 | use rand::{thread_rng, ChaChaRng, Rng, SeedableRng};
  |                                   ^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0432`.
error: Could not compile `petgraph`.

@zendurix
Copy link
Author

Should all test be included in no_std? this will require some additional work

@XVilka
Copy link
Member

XVilka commented Aug 26, 2020

Yes.

@zendurix
Copy link
Author

zendurix commented Aug 26, 2020

Maybe leave thoose tests that uses RNG outside of no_std?

@XVilka
Copy link
Member

XVilka commented Aug 26, 2020

Yes, that makes sense.

@zendurix
Copy link
Author

I have implemented requested changes, all tests are passing in both std and no_std

@XVilka
Copy link
Member

XVilka commented Aug 26, 2020

Looks better, thanks!
Could you please also add a no_std CI job?

@zendurix
Copy link
Author

@XVilka
I am not sure how to do that, should I just add this line at the end of travis.yml ?
&& cargo test --all --no-default-features --features="graphmap","stable_graph","matrix_graph"

@XVilka
Copy link
Member

XVilka commented Aug 26, 2020

@zendurix you can just take .travis.yml from the old PR: https://github.com/petgraph/petgraph/pull/238/files#diff-354f30a63fb0907d4ad57269548329e3

@XVilka
Copy link
Member

XVilka commented Aug 26, 2020

Also I am not sure, instead of adding #[cfg(feature="std")] before every println! maybe it's better to define own macro or function and do the switch once?

By the way, you can also use https://github.com/hobofan/cargo-nono for checks.

@zendurix
Copy link
Author

Also I am not sure, instead of adding #[cfg(feature="std")] before every println! maybe it's better to define own macro or function and do the switch once?

By the way, you can also use https://github.com/hobofan/cargo-nono for checks.

I can think of smth like

pub fn print(args) {
   #[cfg(feature = "std)]
   println!(args)
}

But I am not very good with macros, and I am not sure how to do this

@XVilka
Copy link
Member

XVilka commented Aug 26, 2020

Maybe something like

macro_rules! no_std_println {
  ($(t:tt)*) => {
    #[cfg(feature = "std")]
    {
      println!($($t)*);
    }
  };
}

@zendurix
Copy link
Author

I see problems with CI (cause old PR have feature no_std) I will impl this macro and fix CI later today

@XVilka
Copy link
Member

XVilka commented Jan 13, 2021

@zendurix have you had any luck with this update? Could you please rebase because we migrated from Travis CI to GitHub Actions?

@XVilka
Copy link
Member

XVilka commented Mar 24, 2021

@zendurix could you please rebase your PR?

#[cfg(feature = "std")]
pub use std::collections::{hash_map::Entry::{Occupied, Vacant}, HashSet, hash_map::Iter};
#[cfg(not(feature = "std"))]
pub use hashbrown::{ HashSet, hash_map::{ HashMap, Entry::{Occupied, Vacant}, Iter}};
Copy link
Member

@bluss bluss May 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HashMap is used in the public API - this PR would mean that public API changes breakingly based on a cargo feature, and that's not an allowed usage of cargo features in general. This can't be integrated with this design, unfortunately.

The whole approach to HashMap needs to change somehow. I don't know if using hashbrown is necessary. Keep it simple and incremental, is it possible to support compiling without HashMap?

@chaosprint
Copy link

Hi, this is such a wonderful job. Is there any plan that the rebase can be done in the near future?

@indietyp indietyp added the 0.9.0-fixed Issue fixed in 0.9.0 label Oct 23, 2023
@indietyp
Copy link
Member

0.7.0 will have no-std support, until this version has landed I will keep this PR open.

github-merge-queue bot pushed a commit that referenced this pull request Mar 21, 2025
# Objective

- Alternative to #238
- Alternative to #370
- Implements Item 6 from #551

## Solution

- Promoted `hashbrown` to a direct dependency (currently transient
through `indexmap`)
- Added a new `std` feature, and included it in all features which rely
on `std` for documentation purposes.
- Added new CI task to ensure `no_std` support works (using
`wasm32v1-none` as an example `no_std` target)
- Added several lints which help minimise `std` usage
- Adjusted certain public APIs to allow passing a `S: BuildHasher`
instead of implicitly relying on `std::hash::RandomState` when the `std`
feature is disabled

---

## Notes

I know this has been attempted several times before and delayed due to a
desire to refactor the crate _first_ before adding this functionality.
Delays in adding `no_std` support forced Bevy to drop `petgraph` from
its core crates, relying on a specialised alternative. We'd love to keep
using `petgraph`, but `no_std` support is now a requirement going
forward. This will also come up with `wgpu` which is _also_ pursuing
`no_std` support [here](gfx-rs/wgpu#6826).

---

BREAKING CHANGE:

Petgraph previously assumed the usage of `std::hash::RandomState` as the
hashing implementation across its codebase. In `no_std`, this is not
possible. To minimise friction for libraries supporting both `std` and
`no_std` with Petgraph, I have made the following changes to the public
API:

### `petgraph::algo::simple_paths::all_simple_paths`

This function now has a 3rd generic parameter `S` which controls the
hashing implementation used. Because `all_simple_paths` is a function it
cannot have default generic parameters, so users must specify the hasher
themselves.

```rust
// Before
let foo = all_simple_paths(/* ... */);

// After
let foo = all_simple_paths::<_, _, std::hash::RandomState>(/* ... */);
```

### Switched from `std::collections::{HashMap, HashSet}` to
`hashbrown::{HashMap, HashSet}`

To support `no_std`, we cannot use the standard library's
implementations of `HashMap` or `HashSet`. Methods and types previously
referencing those collections from `std` will now reference them from
`hashbrown`. Note that `hashbrown` was already a dependency of Petgraph,
so no change in audit requirements.

### Added Hashing Parameter

The following types have had a new generic parameter `S` added to
specify the hashing implementation. Note that when `std` is enabled,
these will all default to `std::hash::RandomState`, as before.

- `UnGraphMap`
- `DiGraphMap`
- `MatrixGraph`
- `DiMatrix`
- `UnMatrix`
- `NodeIdentifiers`
- `NodeReferences`

Note that for `MatrixGraph`, `DiMatrix`, `UnMatrix` the new `S`
parameter is in the 3rd position (all others have `S` in the last
position). The reason is `S` has a default parameter with `std` enabled,
but is required with `std` disabled. This means it must be the last
_required_ parameter.

```rust
// Before
let foo: MatrixGraph<Foo, Bar, Directed, Option<Bar>, DefaultIx>;

// After
let foo: MatrixGraph<Foo, Bar, std::hash::RandomState, Directed, Option<Bar>, DefaultIx>;
```

Also note that because `Default` can now be implemented for multiple
versions of the above types (generic over the hasher), you may need to
either specify the hasher, or explicitly declare it as default (with the
`std` feature enabled):

```rust
// Note that N and E are inferred by code below.
// Before
let foo = UnMatrix::default();

// After (Explicitly infer N and E, but use defaults otherwise)
let foo = UnMatrix::<_, _>::default();
```

### `default-features = false` MSRV is 1.81

If you don't enable the `std` feature, the MSRV increases to 1.81, when
`core::error::Error` was stabilised. To preserve the original MSRV of
1.64, just enable the `std` feature.
@starovoid
Copy link
Collaborator

Hi all, this work can definitely be useful in further refactoring, but since no_std support was added in #747, I decided to convert this PR into a draft.

@starovoid starovoid marked this pull request as draft March 26, 2025 17:03
@starovoid starovoid removed this from the 0.8 milestone Mar 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

0.9.0-fixed Issue fixed in 0.9.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants