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
Add bitcoin_hashes features #408
Add bitcoin_hashes features #408
Conversation
We re-export `bitcoin_hashes` so users do not have to depend directly on it. This is Rust best practice as makes keeping versions in sync easier. Currently, however, it is not possible to enable different features in `bitcoin_hashes` and our feature enables it with no default features - this makes the re-export basically useless. Add a bunch of features that can be used to turn on the various `bitcoin_hashes` features.
bitcoin-hashes-alloc = ["bitcoin_hashes/alloc"] | ||
bitcoin-hashes-std-serde = ["bitcoin_hashes/std", "bitcoin_hashes/serde-std"] | ||
bitcoin-hashes-alloc-serde = ["bitcoin_hashes/alloc", "bitcoin_hashes/serde"] | ||
bitcoin-hashes-std-schemars = ["bitcoin_hashes/std", "bitcoin_hashes/schemars"] |
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.
If we're going to reexport things I think it only makes sense to reexport features that are actually used in conditions here. In this case bitcoin-hashes-std
. However I suspect your approach may help with forward compatibility. Is it worth 2^n complexity, though?
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 also am very uncomfortable with the 2^n complexity here. I've run into this problem many times when using re-exports from the rust-bitcoin dependency tree but I don't think it's reasonable to try and solve it this way. (This is only one dependency from one crate, and it brings in 5 new feature gates!)
@@ -28,9 +28,18 @@ recovery = ["secp256k1-sys/recovery"] | |||
lowmemory = ["secp256k1-sys/lowmemory"] | |||
global-context = ["std"] | |||
|
|||
# Give users full control of bitcoin_hashes features while stil using the secp256k1 re-exported | |||
# bitcoin_hashes dependency. | |||
bitcoin-hashes-std = ["bitcoin_hashes/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.
I think we should activate this with our std
feature.
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.
Additionally, once we are in a higher MSRV, we can use "weak-dependency" features here then!
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.
If we batch these together with our features, the list shouldn't explode as much.
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.
We would have to mandate bitcoin_hashes
in combination with std
which doesn't seem right. Weak dependencies will take optimistically about a year and a half to be allowed here. (But once they are, hell yeah, let's use them.)
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.
We would have to mandate
bitcoin_hashes
in combination withstd
which doesn't seem right.
Yes but also, the cost is negligible thought, isn't it? Esp. when weighted against the API complexity of all these features.
My vote would go down for either:
- Tie all
bitcoin_hashes
features to the respectivebitcoin
features - Force users to depend on
bitcoin_hashes
separately if they want to activate features
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'm not sure what do you mean by "Tie all bitcoin_hashes
features to the respective bitcoin
features". Note that we're in secp256k1
repo.
Force users to depend on
bitcoin_hashes
separately if they want to activate features
We can't do this because we don't get to learn which features were activated in bitcoin_hashes
. I already tried this in my own project and failed.
But now I also remembered one super-annoying issue:
- Crate A has
std
feature toimpl std::error::Error
- Crate B has same
std
feature as A, optionally depends on A, and has an error type that has an error type from A as a source - Crate C depends on B with
std
, without A - Crate D depends on B without
std
with A
The compilation will fail because A/std is not enabled so the impl is missing but B tries to use it because std
is enabled.
The only solution to this (other than future Rust version) I can think of is don't return Some
from source
when A is activated without a special feature - one exactly like in this PR.
Actually we should check for these cases in all the crates...
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.
Note that we're in
secp256k1
repo.
Whoops my bad, I meant secp256k1
obviously. With tie all features, I meant:
[features]
std = ["bitcoin_hashes/std"]
Crate C depends on B with
std
, without ACrate D depends on B without
std
with A
Features get unified across a dependency-graph so we should end up with B/std
and A
, no?
- Crate B has same
std
feature as A, optionally depends on A, and has an error type that has an error type from A as a source
We shouldn't have cfg'd enum variants if that is what you are describing here. Those will cause headache across dependency graphs!
I think the Rust idiomatic way is to forward all features to your dependencies, i.e.
std
feature in crate A enables an std
feature (if present) in all its dependencies. Up until "weak-dependency features" land and/or can be used, this will automatically enable optional dependencies if you enable such a feature. That is a price we need to evaluate whether it is worth paying. Our dependency graph is pretty small anyway so this might not be a big deal on the whole. YMMV.
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.
Features get unified across a dependency-graph so we should end up with
B/std
andA
, no?
Only if we do it like you suggest which has the downside of potentially pulling in unneeded dependency.
We shouldn't have cfg'd enum variants if that is what you are describing here.
That's not the issue and there are several ways to deal with it even without #[non_exhaustive]
(but we will bump MSRV so #[non_exhaustive]
is the way to go. So no, that's not the issue. The issue is impl std::error::Error for MyError
conditional on std
feature.
forward all features
IMO there's no great solution today. There are multiple bad solutions, forwarding only required features seems the least bad.
Why was this closed? |
We re-export
bitcoin_hashes
so users do not have to depend directly onit. This is Rust best practice as makes keeping versions in sync easier.
Currently, however, it is not possible to enable different features in
bitcoin_hashes
and our feature enables it with no default features -this makes the re-export basically useless.
Add a bunch of features that can be used to turn on the various
bitcoin_hashes
features.Note
The re-export/feature problem is not specific to this repo, I'd think there was a standard way to solve this. The solution presented here is made up by me so I'm inclined to think there is probably a better, more standard, solution. Hence this PR is draft for feedback please. We suffer the same problem all the way up our stack and its going to get worse when we start crate smashing.
Done while investigating: rust-bitcoin/rust-bitcoin#819 (comment)