In my very large Rust-based project of about 100k lines of code, 100 direct dependencies, and 800 total dependencies, I always require version="*" for each dependency, except for specific ones that either I cannot or don't want to upgrade.
I normally build with cargo --locked. Periodically, I will do a cargo update and run cargo outdated so that I'm able to see if there are specific packages keeping me at older versions.
To upgrade a specific package, I can just remove it's record directly from Cargo.lock and then do a regular cargo build.
This works very well!
Advantages
I minimize my number of dependencies, and therefor build times
I keep my personal ecosystem from falling too far behind that of crates.io
I rarely wind up with a situation where I have two dependencies that depend on a different symbol version
I don't have to change a version in all of my many Cargo.tomls
Disadvantages
I cannot publish my large repository to a wider audience (but that will never happen for this repository)
People who see my code start feeling ill and start shifting their eyes nervously.
People who see my code start feeling ill and start shifting their eyes nervously.
To be honest, I had this reaction just reading your description. But, if it's a only personal project there's no harm, as long as you're not selling it as a new best practice!
I once had a project where I added a crate and a completely different part of the application that didn't use that crate broke.
Turns out that I didn't include the patch version in a dependency and that new dependency required an earlier patch version that had a critical bug in it.
Your solution is like this, but even more extreme by also allowing a dependency to get your code to link to an old major version, breaking everything.
So, your solution only works if you don't plan to ever add a new dependency.
I can somewhat relate. I mostly do something like this (instead of the exact dependency version):
chrono = {version = "0", features = ["serde"]}
clap = {version = "4", features = ["derive"]}
anyhow = "1"
I do, however, typically write application code instead of library, so it's probably less critical for me. Occasionally do run into dependency hell here and there, but nothing too bad so far!