Version solving

Version solving consists in finding a set of packages and versions that satisfy all the constraints of a given project dependencies. In Rust, it is the package manager Cargo that takes the dependencies specified in the Cargo.toml file and deduces the complete list of exact versions of packages needed for your code to run. That includes direct dependencies but also indirect ones, which are dependencies of your dependencies. Packages and versions are not restricted to code libraries though. In fact they could refer to anything where "packages" act as a general name for things, and "versions" describe the evolution of those things. Such things could be office documents, laws, cooking recipes etc. Though if you version cooking recipes, well you are a very organized person.

Semantic versioning

The most common form of versioning scheme for dependencies is called semantic versioning. The base idea of semantic versioning is to provide versions as triplets of the form Major.Minor.Patch such as 2.4.1. The "semantic" term comes from the meaning of each part of the versioning system. Publishing a new patch version, for example from 2.4.1 to 2.4.2 means no interface has changed in the provided API of the library. That may be the case for documentation changes, or internal performance improvements for example. Increasing the minor number, for example from 2.4.1 to 2.5.0, means that things have been added to the API, but nothing was changed in the pre-existing API provided by the library. Finally, increasing the major number, such as from 2.4.1 to 3.0.0, means that some parts of the API have changed and thus may be incompatible with how we are currently using the previous version.

In Rust, packages are called crates and use semantic versioning. In fact, if you specify a dependency of the form package = "2.4.1", cargo will interpret that as the version constraint 2.4.1 <= v < 3.0.0 for that package. It does so based on the fact that any version in that range should not break our code according to the rules of semantic versioning. For more information on dependencies specifications in Cargo.toml you can read the Cargo reference book.

Side note on semantic versioning

Some people think that the granularity of semantic versioning is too broad in the case of major version changes. Instead, versions should never be breaking, but use new namespaces for things that change. It brings the same benefits in the large, that what choosing immutability as default brings in the small. For more information on this point of view, I highly recommend "Spec-ulation" by Rich Hickey, creator of the Clojure programming language.