Relax tokio version requirements#103
Conversation
|
Ah okay. So if a crate compiles targets |
Yea, if no other 3rd party dependency constraints on tokio. Cargo looks at all constraints on a dep and tries to auto choose a version that fits all. If it can't it throws up its hands and requires manual intervention with something like a patch setting. The current constraints are very specific so I think will cause problems at some point. |
| [dependencies] | ||
| futures = { version = "0.3.30", default-features = false, optional = true } | ||
| # Must be under 1.39.0 due to MSRV 1.63.0 requirement. | ||
| tokio = { version = ">=1.37.0, <1.39.0", default-features = false, optional = true } |
There was a problem hiding this comment.
Oh, yes, this was previously straight up wrong.
There was a problem hiding this comment.
Wrong as in, the consumer could always just override a the tokio version with a patch or something and break the MSRV?
There was a problem hiding this comment.
Wrong that pinning belongs to Cargo.lock not Cargo.toml. Putting these into Cargo.toml causes huge problems with updates that would be otherwise trivial one-command things.
There was a problem hiding this comment.
Yea, using this lib downstream was what made me realize this is painful and not super productive. The intention wasn't to pin, but I forget the justification for the >=1.37.0 floor, at least the <1.39.0 ceiling is attempting to convey useful information to the consumer.
There was a problem hiding this comment.
The lower bound tends to be legitimate (but it's also often too strict) the upper one is the problem.
protocol/Cargo.toml
Outdated
| tokio = { version = ">=1.37.0, <1.39.0", default-features = false, optional = true } | ||
| # The tokio feature may increase the MSRV beyond 1.63.0 | ||
| # depending on which version of tokio is selected by the caller. | ||
| tokio = { version = "1", default-features = false, optional = true } |
There was a problem hiding this comment.
FTR I've seen people saying that writing 1.0.0 is better since it conveys the intention. But I don't really care much.
There was a problem hiding this comment.
So same semantics, but 1.0.0 conveys something like "Starting exactly at this point version"? Just making sure I understand what I am signing up for here.
There was a problem hiding this comment.
Same semantics in the eyes of cargo but 1.0.0 conveys to some people "I didn't write '1' just because I was lazy, I really intended 1.0.0". (I personally don't agree with those people that they should care, but they do exist and perhaps making them happy is worth 4 extra characters. :))
protocol/README.md
Outdated
|
|
||
| This crate has a baseline MSRV of **1.63.0**. | ||
|
|
||
| However, when using the `tokio` feature flag, the effective MSRV may be higher depending on which version of tokio is selected by the caller. |
There was a problem hiding this comment.
I'd even say that any external dependency may possibly do this. tokio is currently the only one that actually does but it may happen if they backport MSRV bump to rand for instance.
There was a problem hiding this comment.
Ah, yea good point. I guess my thinking is that the current feature flag interface really invites the consumer to unintentionally, and quietly, break the MSRV with their tokio version.
There was a problem hiding this comment.
It's not that bad if they set rust-version and let a new cargo generate the lock file (they can run it in a VM or whatever, no risk there).
There was a problem hiding this comment.
Yea, I think the v3 resolver will help out here.
There was a problem hiding this comment.
IIRC it's unrelated to resolver version, just cargo being new enough but I might be wrong.
There was a problem hiding this comment.
I have flipped things to resolver = 3 temporarily to grab good lock files. I think it will be the default soon: https://doc.rust-lang.org/edition-guide/rust-2024/cargo-resolver.html
protocol/Cargo.toml
Outdated
| [features] | ||
| default = ["std"] | ||
| # High-level wrappers using futures traits. | ||
| async = ["std", "futures/std"] |
There was a problem hiding this comment.
Sounds like this feature should've been called futures and use the dep: syntax.
There was a problem hiding this comment.
Is futurues a more conventional name for the async interface of a library? That is what this feature flag exposes, which I think is a little more than just futures. But it is using the async traits from the futures dep.
There was a problem hiding this comment.
No, the convention is that if you clearly use a public dependency then the feature should be named after the dependency. E.g. we have serde feature in other crates that activates the serde dependency and whatever else is required to implement it. This is even in the API guidelines. If the dependency is private and you're not sure if it'll even stay then using a different name is fine. (Here, it's public but sadly, futures is unstable.)
There was a problem hiding this comment.
I found these API guidelines on feature names, but they don't mention exactly what to base the name on. Although, lookin around the ecosystem, I do see the convention that they generally are tied to a dependency's name. I don't feel too terrible about this name though since the intention was to capture "async capabilities without specifying a particular runtime", and to me "futures" would be kinda confusing since the intention isn't to directly interact with futures...but will definitely keep this in mind for naming things next time.
There was a problem hiding this comment.
I remember being in some discussion around this and the desire to name the features the same even motivated some changes to cargo. So it's definitely a thing even if we can't find a specific doc saying so.
I haven't looked into the code, but if you don't use futures publicly (their types in the API) then async should be fine and maybe even really a better name. But if it's public I'd recommend renaming it.
There was a problem hiding this comment.
The types are used as trait bounds on the input parameters for public functions, so I think that counts? I can rename it in that case in another patch.
There was a problem hiding this comment.
Yeah, rename would be appropriate in that case.
protocol/Cargo.toml
Outdated
| # High-level wrappers using futures traits. | ||
| async = ["std", "futures/std"] | ||
| # High-level wrappers using tokio traits - may affect MSRV requirements. | ||
| tokio = ["std", "tokio/io-util"] |
There was a problem hiding this comment.
I''m confused how is this not rejected for not using dep:.
There was a problem hiding this comment.
dep: is new to me, and we were originally targeting MSRV 1.56 here so technically wasn't available (it was introduced in 1.60). Digging into it though, it sounds like dep is a way to make things a little more explicit. I believe things are just working right now because this tokio feature flag is overriding the implicit one created by the optional tokio dependency? In any case, would rather be more explicit on intentions.
I pushed 5443dac to switch to the dep syntax.
There was a problem hiding this comment.
Well, that's the thing. IIRC Cargo complained before when hitting same-named things that they are conflicting. That's what I'm confused about - why it wasn't rejected by it here. But yes, dep: is more explicit and thus nicer.
There was a problem hiding this comment.
I can't for the life of me find any docs on how explicit features interact with the implicit ones, but it hasn't been exploding so I think it must overwrite or merge them somehow.
EDIT: maybe a post 1.60+ thing?
There was a problem hiding this comment.
I don't know it by heart either but I remember I had to do a bit more digging when I already knew it's possible but didn't know the details. Someone slacked on "how do we teach this" section in the RFC :D
Allow any compatible Tokio 1.x version to be used with the tokio feature flag, rather than restricting to specific version ranges. This gives users more flexibility to select their preferred Tokio version. When using the tokio feature with Tokio 1.39.0+, the effective MSRV increases to 1.70.0.
Replace implicit feature enabling of optional dependencies with the more
explicit dep: syntax. Dep: prevents implicit feature flag creation
("tokio" and "futures") of the optional dependencies.
Things just worked before because the tokio feature flag was
overwritten, but this makes it clear.
5443dac to
05f725b
Compare
|
Folded in doc improvements and then switched to better |
Allow any compatible Tokio 1.x version to be used with the tokio feature flag, rather than restricting to specific version ranges. This gives users more flexibility to select their preferred Tokio version. But when using the tokio feature with Tokio 1.39.0+, the effective MSRV increases to 1.70.0.
The library only depends on the stable tokio traits
AsyncRead,AsyncReadExt,AsyncWrite,AsyncWriteExt, so should be compatible with a lot of versions. I'd rather give the caller control in this case, especially since its behind a feature flag, instead of enforcing the strict MSRV requirements of the library.