-
Notifications
You must be signed in to change notification settings - Fork 48
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
Make the crate no_std
+ alloc
#44
Conversation
On regards to your point about having to figure out what to do with the default value of |
… `RandomState`. Now the `S` type parameter is only required to implement `Default`.
I think we're still missing a couple of important things in #![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate cfg_if;
#[cfg(feature = "std")]
extern crate core;
cfg_if! {
if #[cfg(feature = "alloc")] {
extern crate alloc;
} else if #[cfg(feature = "std")] {
extern crate std as alloc;
}
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're still missing a couple of important things in
src/lib.rs
.crossbeam-epoch/src/lib.rs
is probably good inspiration. In particular, we'll need to addcfg_if
toCargo.toml
, and then something like#![cfg_attr(not(feature = "std"), no_std)] #[macro_use] extern crate cfg_if; #[cfg(feature = "std")] extern crate core; cfg_if! { if #[cfg(feature = "alloc")] { extern crate alloc; } else if #[cfg(feature = "std")] { extern crate std as alloc; } }
Alright. Are extern crate alloc
and extern crate core
necessary thought? The compiler is complaining about the fact that they are unused...
Ah, no, you're right, with the 2018 edition you may be able to remove them. The one thing you will need somewhere is probably this though #[cfg(feature = "std")]
use std as alloc; But could very well be that we can get rid of |
The compiler still complains about |
Hmm, I was thinking of elsewhere in the crate where we try to use |
I get a bunch of errors related to the absence of some things auto-imported from I'll work on the auto-imported things. I don't see a clear path on how to deal with |
I think anything where we take a |
I am very surprised that CI doesn't catch that it doesn't compile with |
It looks like it doesn't even re-compile when |
Yep. |
If you do the following locally, in order, do you get any errors? $ cargo check --all --bins --examples
$ cargo check --all --bins --examples --no-default-features |
As in, just do: #![cfg_attr(feature = "std", deny(missing_debug_implementations))] (and remove the existing |
Another alternative is to have a separate impl on |
Actually there is a potential source of unsoundness here: The approach I went with for crossbeam-skiplist is that the |
@Amanieu oh, that is interesting. I believe that's a problem beyond just Doesn't that mean that users cannot take advantage of the global epoch collection though? As in, they can't share the collection between many different programs that use |
The high-level wrapper can use the default collector (the one used by pub fn new() -> SkipMap<K, V> {
SkipMap {
inner: base::SkipList::new(epoch::default_collector().clone()),
}
} |
That does mean that methods cannot generally return references though, right? Since you would not be able to give the return value an appropriate lifetime, as it would be tied to the guard we construct inside each method. That's pretty unfortunate. |
That is, in the high-level type. In the low-level type you can still take a |
A newtype Two of the motivations for #45 are |
Actually, I have a proposal. Writing it up as an issue as we speak. Will link when written. |
Okay, for the unsoundness let's continue that conversation in #46. I think this PR is mostly orthogonal to that issue. @GarkGarcia for this PR, I think the main remaining thing is to merge |
Could you handle that for me please? |
Okay, so, I think the next (last?) challenge is that |
This is necessary since there is no particular lock implementation that "makes sense" on `no_std`. This patch changes all types to be generic over any lock type that implements `lock_api::RawMutex`, and defaults to `parking_lot::RawMutex` on `std`. Note that this patch forks the struct definition for `HashMap` into one for `std` (which has a default for `L`) and one for `no_std` (which does not). This is fine since any code written _without_ the `std` feature _will_ compile with the `std` feature enabled (`indexmap` does the same; the reverse is not true). We _could_ introduce an intermediate private struct to avoid repeating the definition, but it would require writing `self.inner` all over the place, which would be sad. This seemed marginally cleaner. Also, this diff makes me want implied bounds a lot: rust-lang/rust#44491
All right, I fixed that by making us generic over |
🎉 tests pass 🎉 I'll merge this in a few hours unless there are any objections. The |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exposed lock seems like a step too far to me, that perhaps no_std
isn't really worth it. The lock should really be an internal detail, not something the user should care about like the hasher. But if you really want to support no_std
, I guess there's not much choice...
/// See the [crate-level documentation](index.html) for details. | ||
pub struct HashMap<K, V, S = RandomState> { | ||
#[cfg(feature = "std")] | ||
pub struct HashMap<K, V, L = parking_lot::RawMutex, S = RandomState> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest L
and S
should be reversed, so HashMap<K, V, S>
still looks like the standard collection. This would also simplify the test cases where you had to start specifying the lock type to use a different hasher, which feels like an API wart. However, that means you'd have to remove the default S
in the no-std configuration too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not wanting to remove the default S
in no-std is why I ordered them this way. I'm honestly not sure which is better/worse. My inclination is to make things harder for no_std
folks when given a trade-off, which would suggest no defaults in no-std and L
last.
|
||
/// An iterator over a map's entries. | ||
/// | ||
/// See [`HashMap::iter`](crate::HashMap::iter) for details. | ||
#[derive(Debug)] | ||
pub struct Iter<'g, K, V> { | ||
pub(crate) node_iter: NodeIter<'g, K, V>, | ||
pub struct Iter<'g, K, V, L> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a default L
for all of the iterator types too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bah, then we'd have to duplicate all of these too. One other option here is to define a default value on no_std
that panics when used. It ain't great at all, but it would allow us to not duplicate all the structs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose that's why hashbrown
uses an uninhabited default on no-std.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, hashbrown uses ahash on no_std. It only uses an uninhabited default when compiled as a dependency for libstd (because the libstd build system is weird and makes dependencies difficult).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh ok, I misunderstood that context, and hashbrown doesn't need a lock like this. An uninhabited default might still work though, or we could use macro_rules!
to hide the duplication.
I don't disagree with you that the change is becoming pretty painful API-wise. I've put out a call for input from the people who actually use If we decide it's not worth it, then I still think there are a bunch of changes from this PR we may want to adopt in |
This is far from complete, but I went ahead and replaced
std
forcore
in all of the easy places. I also created thestd
feature and configured all relevant functions to only be exposed when using it.I'd like some input before I proceed.