Rust crates use Semantic Versioning. As a consequence, each release with a breaking change should result in a major version bump. A breaking change is commonly considered something that may break downstream crates (code the depends on the library in question).
However, in Rust a whole lot has the potential of breaking downstream crates. For example, changing (including merely adding to) the set of public symbols is possibly a breaking change, because downstream crates can use glob-imports (use foo::*;
) to pull symbols of our library into their namespace. Thus, adding symbols can break dependent crates as well; see this example.
Similarly, changing (adding or changing the version) the set of our dependencies can break downstream builds. You can also imagine that the downstream crate relies on a specific size of one of our public types. This is rarely, if at all, useful; I just want to show: everything could be a breaking change, if only the downstream crate tries hard enough.
Is there any guideline about this? What exactly is considered a breaking change and what not (because it's considered "the user's fault")?
There is a Rust RFC on this subject: RFC 1105: API Evolution. It's applicable to any Rust library project, and it covers all kinds of changes (not just breaking changes) and how they impact semantic versioning. I'll try to summarize the key points from the RFC in order to not make this answer a link-only answer. :)
The RFC acknowledges that pretty much any change to a library can cause a client to suddenly stop compiling. As such, it defines a set of major changes, which require a bump of the major version number, and a set of minor changes, which require a bump of the minor version number; not all breaking changes are major changes.
The key attribute of a minor change is that there must be a way that clients can avoid the breakage in advance by altering slightly their source code (e.g. change a glob import to a non-glob import, disambiguate an ambiguous call with UFCS, etc.) in such a way that the code is compatible with the version prior to the change and with the version that includes the change (assuming that it's a minor release). A minor change must also not force downstream crates to make major breaking changes in order to resolve the breakage.
The major changes defined in the RFC (as of commit
721f2d74
) are:The minor changes defined in the RFC (as of commit
721f2d74
, breaking unless specified) are:impl
.See the RFC for explanations and examples.