Skip to content

Commit

Permalink
Allow the edition specifier to be an integer
Browse files Browse the repository at this point in the history
This helps save the number of characters needed to specify an edition.
So far, each edition was fully described by its year number, 2015, 2018, 2021.
Also for the future, the intent is that editions will always just be
year numbers. Therefore, we don't have to use a toml string for them in Cargo.toml,
an integer is enough. This saves two characters in each Cargo.toml.
  • Loading branch information
est31 committed Jun 30, 2023
1 parent 5b377ce commit c48a4f0
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 5 deletions.
73 changes: 68 additions & 5 deletions src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,22 @@ impl StringOrVec {
}
}

#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
#[serde(untagged, expecting = "expected a string or an integer")]
pub enum StringOrI64 {
String(String),
I64(i64),
}

impl Display for StringOrI64 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StringOrI64::String(s) => f.write_str(s),
StringOrI64::I64(v) => write!(f, "{v}"),
}
}
}

#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
#[serde(untagged, expecting = "expected a boolean or a string")]
pub enum StringOrBool {
Expand Down Expand Up @@ -1262,6 +1278,50 @@ impl TomlWorkspaceDependency {
//. This already has a `Deserialize` impl from version_trim_whitespace
type MaybeWorkspaceSemverVersion = MaybeWorkspace<semver::Version, TomlWorkspaceField>;

type MaybeWorkspaceStringOrI64 = MaybeWorkspace<StringOrI64, TomlWorkspaceField>;
impl<'de> de::Deserialize<'de> for MaybeWorkspaceStringOrI64 {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;

impl<'de> de::Visitor<'de> for Visitor {
type Value = MaybeWorkspaceStringOrI64;

fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.write_str("a string, integer or workspace")
}

fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
let int = de::value::I64Deserializer::new(value);
StringOrI64::deserialize(int).map(MaybeWorkspace::Defined)
}

fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: de::Error,
{
let string = de::value::StringDeserializer::new(value);
StringOrI64::deserialize(string).map(MaybeWorkspace::Defined)
}

fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mvd = de::value::MapAccessDeserializer::new(map);
TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
}
}

d.deserialize_any(Visitor)
}
}

type MaybeWorkspaceString = MaybeWorkspace<String, TomlWorkspaceField>;
impl<'de> de::Deserialize<'de> for MaybeWorkspaceString {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
Expand Down Expand Up @@ -1501,7 +1561,7 @@ impl WorkspaceInherit for TomlWorkspaceField {
#[derive(Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
pub struct TomlPackage {
edition: Option<MaybeWorkspaceString>,
edition: Option<MaybeWorkspaceStringOrI64>,
rust_version: Option<MaybeWorkspaceString>,
name: InternedString,
#[serde(deserialize_with = "version_trim_whitespace")]
Expand Down Expand Up @@ -1583,7 +1643,7 @@ pub struct InheritableFields {
license_file: Option<String>,
repository: Option<String>,
publish: Option<VecStringOrBool>,
edition: Option<String>,
edition: Option<StringOrI64>,
badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
exclude: Option<Vec<String>>,
include: Option<Vec<String>>,
Expand Down Expand Up @@ -1620,7 +1680,7 @@ impl InheritableFields {
("package.categories", categories -> Vec<String>),
("package.description", description -> String),
("package.documentation", documentation -> String),
("package.edition", edition -> String),
("package.edition", edition -> StringOrI64),
("package.exclude", exclude -> Vec<String>),
("package.homepage", homepage -> String),
("package.include", include -> Vec<String>),
Expand Down Expand Up @@ -1728,7 +1788,7 @@ impl TomlManifest {
.edition
.as_ref()
.and_then(|e| e.as_defined())
.map(|e| Edition::from_str(e))
.map(|e| Edition::from_str(&e.to_string()))
.unwrap_or(Ok(Edition::Edition2015))
.map(|e| e.default_resolve_behavior())
})?;
Expand Down Expand Up @@ -2040,9 +2100,12 @@ impl TomlManifest {
let edition = if let Some(edition) = package.edition.clone() {
let edition: Edition = edition
.resolve("edition", || inherit()?.edition())?
.to_string()
.parse()
.with_context(|| "failed to parse the `edition` key")?;
package.edition = Some(MaybeWorkspace::Defined(edition.to_string()));
package.edition = Some(MaybeWorkspace::Defined(StringOrI64::String(
edition.to_string(),
)));
edition
} else {
Edition::Edition2015
Expand Down
65 changes: 65 additions & 0 deletions tests/testsuite/edition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,71 @@ fn edition_works_for_build_script() {
p.cargo("check -v").run();
}

#[cargo_test]
fn edition_works_as_integer() {
const NEEDS_2021: &str = "pub fn foo() { let hi: u8 = 0i32.try_into().unwrap(); }";
let p_2021 = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = 2021
"#,
)
.file("src/lib.rs", NEEDS_2021)
.build();
p_2021.cargo("check").run();

let p_2018 = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = 2018
"#,
)
.file("src/lib.rs", NEEDS_2021)
.build();
p_2018
.cargo("check")
.with_status(101)
.with_stderr_contains("[..] is included in the prelude starting in Edition 2021")
.run();
}

#[cargo_test]
fn edition_breaks_as_float() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = 2021.0
"#,
)
.file("src/lib.rs", "")
.build();

p.cargo("check -v")
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml`
Caused by:
invalid type: floating point `2021`, expected a string, integer or workspace
in `package.edition`
",
)
.run();
}

#[cargo_test]
fn edition_unstable_gated() {
// During the period where a new edition is coming up, but not yet stable,
Expand Down

0 comments on commit c48a4f0

Please sign in to comment.