I'm implementing Rust Cargo version requirements. In general, I have trouble understanding caret requirements as specified. I found What's the difference between tilde(~) and caret(^) in package.json?, but this question is about npm version requirements of which I'm not sure if it is the same as Rust Cargo version requirements.
At https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements, I read:
Caret requirements allow SemVer compatible updates to a specified version. An update is allowed if the new version number does not modify the left-most non-zero digit in the major, minor, patch grouping. In this case, if we ran
cargo update -p time
, cargo should update us to version0.1.13
if it is the latest0.1.z
release, but would not update us to0.2.0
. If instead we had specified the version string as^1.0
, cargo should update to1.1
if it is the latest1.y
release, but not2.0
. The version0.0.x
is not considered compatible with any other version.
Here are some more examples of caret requirements and the versions that would be allowed with them:
^1.2.3 := >=1.2.3, <2.0.0 ^1.2 := >=1.2.0, <2.0.0 ^1 := >=1.0.0, <2.0.0 ^0.2.3 := >=0.2.3, <0.3.0 ^0.2 := >=0.2.0, <0.3.0 ^0.0.3 := >=0.0.3, <0.0.4 ^0.0 := >=0.0.0, <0.1.0 ^0 := >=0.0.0, <1.0.0
This compatibility convention is different from SemVer in the way it treats versions before
1.0.0
. While SemVer says there is no compatibility before1.0.0
, Cargo considers0.x.y
to be compatible with0.x.z
, wherey ≥ z
andx > 0
.
I'm confused about
In this case, if we ran
cargo update -p time
, cargo should update us to version0.1.13
if it is the latest0.1.z
release, but would not update us to0.2.0
.
With what version requirement is this the case? It seems left out of the sentence. It continues to refer to a seemingly missing caret version requirement:
If instead we had specified the version string as
^1.0
, cargo should update to1.1
if it is the latest1.y
release, but not2.0
.
In which it refers to >1.0
as the version string (which I miss in the sentence before).
If I dissect the examples, my reasoning is as follows:
^1.2.3 := >=1.2.3, <2.0.0 // same as >=1.2.3 AND 1.*
^1.2 := >=1.2.0, <2.0.0 // same as >=1.2 AND 1.*, which condenses into 1.2.*
^1 := >=1.0.0, <2.0.0 // same as 1.*
^0.2.3 := >=0.2.3, <0.3.0 // same as >=0.2.3 AND 0.2.*
^0.2 := >=0.2.0, <0.3.0 // same as 0.2.*, which condenses into 0.2.*
^0.0.3 := >=0.0.3, <0.0.4 // huh
^0.0 := >=0.0.0, <0.1.0 // same as >=0.0.0 AND 0.0.*
^0 := >=0.0.0, <1.0.0 // same as >=0.0.0 AND 0.*, which condenses into 0.*
So except for my understanding of the 6th example (^0.0.3
), my conclusion is that caret version requirements are exactly as wildcard version requirements, except when PATCH is specified in which the wildcard version requirement ANDs with the >= {version}
(equal or later then) comparison version requirement.
Is this understanding correct and why is example 6 as it is?
Unlike in npm, the default version requirement range is indeed the caret requirement! This is stated in the Cargo reference on "specifying dependencies", just before the section linked in the question.
The string
"0.1.12"
is a semver version requirement. Since this string does not have any operators in it, it is interpreted the same way as if we had specified"^0.1.12"
, which is called a caret requirement.
As such, the following two dependency specifications are equivalent.
time = "0.1.12"
time = "^0.1.12"
This, by the way, is the requirement referred to in the rest of the document. An update of time
could bring in a version higher than 0.1.12, but never 0.2.0 or higher.
See also: