diff --git a/Cargo.lock b/Cargo.lock index 8617962f3f9..e51ec1605f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,11 +28,15 @@ dependencies = [ "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -86,6 +90,8 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -111,7 +117,9 @@ name = "crates-io" version = "0.7.0" dependencies = [ "curl 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -156,6 +164,11 @@ dependencies = [ "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dtoa" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "env_logger" version = "0.4.0" @@ -272,6 +285,11 @@ dependencies = [ "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itoa" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -521,6 +539,11 @@ name = "quick-error" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "quote" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rand" version = "0.3.15" @@ -581,6 +604,48 @@ name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serde" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_codegen_internals" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syn 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen_internals 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_ignored" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "shell-escape" version = "0.1.3" @@ -591,6 +656,15 @@ name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syn" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tar" version = "0.4.10" @@ -656,8 +730,13 @@ dependencies = [ name = "toml" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "toml" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -673,6 +752,11 @@ name = "unicode-normalization" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "0.1.1" @@ -745,6 +829,7 @@ dependencies = [ "checksum curl 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "654c5b772f9e62a46a99cc9ee7442e80a139027889a6305cdd59bc1e5eb3e3e8" "checksum curl-sys 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "a89415561199ca2ac6de2519674739159c1583bc0a9b46ec30fd3814999d5ef5" "checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" +"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99971fb1b635fe7a0ee3c4d065845bb93cca80a23b5613b5613391ece5de4144" "checksum error-chain 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "318cb3c71ee4cdea69fdc9e15c173b245ed6063e1709029e8fd32525a881120f" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" @@ -758,6 +843,7 @@ dependencies = [ "checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" "checksum handlebars 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b930077f1422bf853008047b55896efc1409744bfc9903f1eec1a58fcc7edeff" "checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" +"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b" "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5" @@ -787,6 +873,7 @@ dependencies = [ "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" +"checksum quote 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e7b44fd83db28b83c1c58187159934906e5e955c812e211df413b76b03c909a5" "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" @@ -795,8 +882,14 @@ dependencies = [ "checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0ae9a3c8b07c09dbe43022486d55a18c629a0618d2241e49829aaef9b6d862f9" +"checksum serde_codegen_internals 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3172bf2940b975c0e4f6ab42a511c0a4407d4f46ccef87a9d3615db5c26fa96" +"checksum serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ecc6e0379ca933ece58302d2d3034443f06fbf38fd535857c1dc516195cbc3bf" +"checksum serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4b3f5576874721d14690657e9f0ed286e72a52be2f6fdc0cf2f024182bd8f64" +"checksum serde_json 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e095e4e94e7382b76f48e93bd845ffddda62df8dfd4c163b1bfa93d40e22e13a" "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" +"checksum syn 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f94368aae82bb29656c98443a7026ca931a659e8d19dcdc41d6e273054e820" "checksum tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb3bf6ec92843ca93f4fcfb5fc6dfe30534815b147885db4b5759b8e2ff7d52" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "checksum term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3deff8a2b3b6607d6d7cc32ac25c0b33709453ca9cceac006caac51e963cf94a" @@ -805,8 +898,10 @@ dependencies = [ "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum thread_local 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7793b722f0f77ce716e7f1acf416359ca32ff24d04ffbac4269f44a4a83be05d" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" +"checksum toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08272367dd2e766db3fa38f068067d17aa6a9dfd7259af24b3927db92f1e0c2f" "checksum unicode-bidi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b61814f3e7fd0e0f15370f767c7c943e08bc2e3214233ae8f88522b334ceb778" "checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" +"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" "checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" diff --git a/Cargo.toml b/Cargo.toml index 99e0f1e6eff..d7120460b50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,11 +35,15 @@ log = "0.3" num_cpus = "1.0" rustc-serialize = "0.3" semver = "0.6.0" +serde = "0.9" +serde_derive = "0.9" +serde_json = "0.9" +serde_ignored = "0.0.2" shell-escape = "0.1" tar = { version = "0.4", default-features = false } tempdir = "0.3" term = "0.4.4" -toml = "0.2" +toml = "0.3" url = "1.1" [target.'cfg(unix)'.dependencies] diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs index 792c9002d1b..0d0171ad2e8 100644 --- a/src/bin/cargo.rs +++ b/src/bin/cargo.rs @@ -6,6 +6,9 @@ extern crate rustc_serialize; extern crate toml; #[macro_use] extern crate log; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; use std::collections::BTreeSet; use std::collections::HashMap; diff --git a/src/bin/locate_project.rs b/src/bin/locate_project.rs index d89f6526920..810be467c0a 100644 --- a/src/bin/locate_project.rs +++ b/src/bin/locate_project.rs @@ -18,7 +18,7 @@ Options: -h, --help Print this message "; -#[derive(RustcEncodable)] +#[derive(Serialize)] pub struct ProjectLocation { root: String } diff --git a/src/bin/verify_project.rs b/src/bin/verify_project.rs index 882873d1f1e..26e11f96644 100644 --- a/src/bin/verify_project.rs +++ b/src/bin/verify_project.rs @@ -6,7 +6,7 @@ use std::process; use cargo; use cargo::util::important_paths::{find_root_manifest_for_wd}; use cargo::util::{CliResult, Config}; -use rustc_serialize::json; +use serde_json; use toml; #[derive(RustcDecodable)] @@ -55,10 +55,9 @@ pub fn execute(args: Flags, config: &Config) -> CliResult { Ok(_) => {}, Err(e) => fail("invalid", &format!("error reading file: {}", e)) }; - match toml::Parser::new(&contents).parse() { - None => fail("invalid", "invalid-format"), - Some(..) => {} - }; + if contents.parse::().is_err() { + fail("invalid", "invalid-format"); + } let mut h = HashMap::new(); h.insert("success".to_string(), "true".to_string()); @@ -69,6 +68,6 @@ pub fn execute(args: Flags, config: &Config) -> CliResult { fn fail(reason: &str, value: &str) -> ! { let mut h = HashMap::new(); h.insert(reason.to_string(), value.to_string()); - println!("{}", json::encode(&h).unwrap()); + println!("{}", serde_json::to_string(&h).unwrap()); process::exit(1) } diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index 377f21dee06..9401eeccbb0 100644 --- a/src/cargo/core/dependency.rs +++ b/src/cargo/core/dependency.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use semver::VersionReq; use semver::ReqParseError; -use rustc_serialize::{Encoder, Encodable}; +use serde::ser; use core::{SourceId, Summary, PackageId}; use util::{CargoError, CargoResult, Cfg, CfgExpr, ChainError, human, Config}; @@ -41,7 +41,7 @@ pub enum Platform { Cfg(CfgExpr), } -#[derive(RustcEncodable)] +#[derive(Serialize)] struct SerializedDependency<'a> { name: &'a str, source: &'a SourceId, @@ -54,8 +54,10 @@ struct SerializedDependency<'a> { target: Option<&'a Platform>, } -impl Encodable for Dependency { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl ser::Serialize for Dependency { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { SerializedDependency { name: self.name(), source: &self.source_id(), @@ -65,7 +67,7 @@ impl Encodable for Dependency { uses_default_features: self.uses_default_features(), features: self.features(), target: self.platform(), - }.encode(s) + }.serialize(s) } } @@ -76,13 +78,15 @@ pub enum Kind { Build, } -impl Encodable for Kind { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl ser::Serialize for Kind { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { match *self { Kind::Normal => None, Kind::Development => Some("dev"), Kind::Build => Some("build"), - }.encode(s) + }.serialize(s) } } @@ -136,7 +140,7 @@ This will soon become a hard error, so it's either recommended to update to a fixed version or contact the upstream maintainer about this warning. ", - req, inside.name(), inside.version(), requirement); + req, inside.name(), inside.version(), requirement); config.shell().warn(&msg)?; Ok(requirement) @@ -348,9 +352,11 @@ impl Platform { } } -impl Encodable for Platform { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - self.to_string().encode(s) +impl ser::Serialize for Platform { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { + self.to_string().serialize(s) } } diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 4ab5ea4f9f1..24cfd4d42f4 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -3,7 +3,7 @@ use std::fmt; use std::path::{PathBuf, Path}; use semver::Version; -use rustc_serialize::{Encoder, Encodable}; +use serde::ser; use core::{Dependency, PackageId, Summary, SourceId, PackageIdSpec}; use core::WorkspaceConfig; @@ -113,72 +113,68 @@ pub enum TargetKind { } impl TargetKind { - /// Returns a vector of crate types as specified in a manifest with one difference. - /// For ExampleLib it returns "example" instead of crate types - pub fn kinds(&self) -> Vec<&str> { + /// Returns a vector of crate types as specified in a manifest + pub fn crate_types(&self) -> Vec<&str> { use self::TargetKind::*; match *self { - Lib(ref kinds) => kinds.iter().map(LibKind::crate_type).collect(), + Lib(ref kinds) | ExampleLib(ref kinds) => { + kinds.iter().map(LibKind::crate_type).collect() + } Bin => vec!["bin"], - ExampleBin | ExampleLib(_) => vec!["example"], + ExampleBin => vec!["example"], Test => vec!["test"], CustomBuild => vec!["custom-build"], Bench => vec!["bench"] } } +} - /// Returns a vector of crate types as specified in a manifest - pub fn crate_types(&self) -> Vec<&str> { +impl ser::Serialize for TargetKind { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { use self::TargetKind::*; match *self { - Lib(ref kinds) | ExampleLib(ref kinds) => { - kinds.iter().map(LibKind::crate_type).collect() - } + Lib(ref kinds) => kinds.iter().map(LibKind::crate_type).collect(), Bin => vec!["bin"], - ExampleBin => vec!["example"], + ExampleBin | ExampleLib(_) => vec!["example"], Test => vec!["test"], CustomBuild => vec!["custom-build"], Bench => vec!["bench"] - } + }.serialize(s) } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] + +// Note that most of the fields here are skipped when serializing because we +// don't want to export them just yet (becomes a public API of Cargo). Others +// though are definitely needed! +#[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize)] pub struct Profile { pub opt_level: String, + #[serde(skip_serializing)] pub lto: bool, + #[serde(skip_serializing)] pub codegen_units: Option, // None = use rustc default + #[serde(skip_serializing)] pub rustc_args: Option>, + #[serde(skip_serializing)] pub rustdoc_args: Option>, pub debuginfo: Option, pub debug_assertions: bool, + #[serde(skip_serializing)] pub rpath: bool, pub test: bool, + #[serde(skip_serializing)] pub doc: bool, + #[serde(skip_serializing)] pub run_custom_build: bool, + #[serde(skip_serializing)] pub check: bool, + #[serde(skip_serializing)] pub panic: Option, } -#[derive(RustcEncodable)] -struct SerializedProfile<'a> { - opt_level: &'a str, - debuginfo: Option, - debug_assertions: bool, - test: bool, -} - -impl Encodable for Profile { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - SerializedProfile { - opt_level: &self.opt_level, - debuginfo: self.debuginfo, - debug_assertions: self.debug_assertions, - test: self.test, - }.encode(s) - } -} - #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct Profiles { pub release: Profile, @@ -209,22 +205,22 @@ pub struct Target { for_host: bool, } -#[derive(RustcEncodable)] +#[derive(Serialize)] struct SerializedTarget<'a> { - kind: Vec<&'a str>, + kind: &'a TargetKind, crate_types: Vec<&'a str>, name: &'a str, - src_path: &'a str, + src_path: &'a PathBuf, } -impl Encodable for Target { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl ser::Serialize for Target { + fn serialize(&self, s: S) -> Result { SerializedTarget { - kind: self.kind.kinds(), + kind: &self.kind, crate_types: self.kind.crate_types(), name: &self.name, - src_path: &self.src_path.display().to_string(), - }.encode(s) + src_path: &self.src_path, + }.serialize(s) } } diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 6b4cd2835d9..898745460f9 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -5,12 +5,12 @@ use std::hash; use std::path::{Path, PathBuf}; use semver::Version; +use serde::ser; use core::{Dependency, Manifest, PackageId, SourceId, Target}; use core::{Summary, SourceMap}; use ops; use util::{CargoResult, Config, LazyCell, ChainError, internal, human, lev_distance}; -use rustc_serialize::{Encoder,Encodable}; /// Information about a package that is available somewhere in the file system. /// @@ -24,7 +24,7 @@ pub struct Package { manifest_path: PathBuf, } -#[derive(RustcEncodable)] +#[derive(Serialize)] struct SerializedPackage<'a> { name: &'a str, version: &'a str, @@ -39,8 +39,10 @@ struct SerializedPackage<'a> { manifest_path: &'a str, } -impl Encodable for Package { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl ser::Serialize for Package { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { let summary = self.manifest.summary(); let package_id = summary.package_id(); let manmeta = self.manifest.metadata(); @@ -60,7 +62,7 @@ impl Encodable for Package { targets: &self.manifest.targets(), features: summary.features(), manifest_path: &self.manifest_path.display().to_string(), - }.encode(s) + }.serialize(s) } } diff --git a/src/cargo/core/package_id.rs b/src/cargo/core/package_id.rs index 12e6fae78ff..e2bd95c081a 100644 --- a/src/cargo/core/package_id.rs +++ b/src/cargo/core/package_id.rs @@ -5,8 +5,9 @@ use std::hash::Hash; use std::hash; use std::sync::Arc; -use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use semver; +use serde::de; +use serde::ser; use util::{CargoResult, CargoError, ToSemver}; use core::source::SourceId; @@ -24,40 +25,41 @@ struct PackageIdInner { source_id: SourceId, } -impl Encodable for PackageId { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl ser::Serialize for PackageId { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer + { let source = self.inner.source_id.to_url(); let encoded = format!("{} {} ({})", self.inner.name, self.inner.version, source); - encoded.encode(s) + encoded.serialize(s) } } -impl Decodable for PackageId { - fn decode(d: &mut D) -> Result { - let string: String = Decodable::decode(d)?; +impl de::Deserialize for PackageId { + fn deserialize(d: D) -> Result + where D: de::Deserializer + { + let string = String::deserialize(d)?; let mut s = string.splitn(3, ' '); let name = s.next().unwrap(); let version = match s.next() { Some(s) => s, - None => return Err(d.error("invalid serialized PackageId")), + None => return Err(de::Error::custom("invalid serialized PackageId")), }; - let version = semver::Version::parse(version).map_err(|_| { - d.error("invalid version") - })?; + let version = semver::Version::parse(version) + .map_err(de::Error::custom)?; let url = match s.next() { Some(s) => s, - None => return Err(d.error("invalid serialized PackageId")), + None => return Err(de::Error::custom("invalid serialized PackageId")), }; let url = if url.starts_with("(") && url.ends_with(")") { &url[1..url.len() - 1] } else { - return Err(d.error("invalid serialized PackageId")) + return Err(de::Error::custom("invalid serialized PackageId")) }; - let source_id = SourceId::from_url(url).map_err(|e| { - d.error(&e.to_string()) - })?; + let source_id = SourceId::from_url(url).map_err(de::Error::custom)?; Ok(PackageId { inner: Arc::new(PackageIdInner { diff --git a/src/cargo/core/resolver/encode.rs b/src/cargo/core/resolver/encode.rs index 1971801bcab..801fc474084 100644 --- a/src/cargo/core/resolver/encode.rs +++ b/src/cargo/core/resolver/encode.rs @@ -2,14 +2,15 @@ use std::collections::{HashMap, HashSet, BTreeMap}; use std::fmt; use std::str::FromStr; -use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; +use serde::ser; +use serde::de; use core::{Package, PackageId, SourceId, Workspace}; use util::{CargoResult, Graph, Config, internal, ChainError, CargoError}; use super::Resolve; -#[derive(RustcEncodable, RustcDecodable, Debug)] +#[derive(Serialize, Deserialize, Debug)] pub struct EncodableResolve { package: Option>, /// `root` is optional to allow forward compatibility. @@ -206,7 +207,7 @@ fn build_path_deps(ws: &Workspace) -> HashMap { } } -#[derive(RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct EncodableDependency { name: String, version: String, @@ -260,17 +261,21 @@ impl FromStr for EncodablePackageId { } } -impl Encodable for EncodablePackageId { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - self.to_string().encode(s) +impl ser::Serialize for EncodablePackageId { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { + self.to_string().serialize(s) } } -impl Decodable for EncodablePackageId { - fn decode(d: &mut D) -> Result { - String::decode(d).and_then(|string| { +impl de::Deserialize for EncodablePackageId { + fn deserialize(d: D) -> Result + where D: de::Deserializer, + { + String::deserialize(d).and_then(|string| { string.parse::() - .map_err(|e| d.error(&e.to_string())) + .map_err(de::Error::custom) }) } } @@ -281,8 +286,10 @@ pub struct WorkspaceResolve<'a, 'cfg: 'a> { pub use_root_key: bool, } -impl<'a, 'cfg> Encodable for WorkspaceResolve<'a, 'cfg> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl<'a, 'cfg> ser::Serialize for WorkspaceResolve<'a, 'cfg> { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { let mut ids: Vec<&PackageId> = self.resolve.graph.iter().collect(); ids.sort(); @@ -320,7 +327,7 @@ impl<'a, 'cfg> Encodable for WorkspaceResolve<'a, 'cfg> { package: Some(encodable), root: root, metadata: metadata, - }.encode(s) + }.serialize(s) } } diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index dc334535f73..142adfdb69d 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -7,7 +7,8 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; use std::sync::atomic::Ordering::SeqCst; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use serde::ser; +use serde::de; use url::Url; use core::{Package, PackageId, Registry}; @@ -342,22 +343,24 @@ impl Ord for SourceId { } } -impl Encodable for SourceId { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl ser::Serialize for SourceId { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { if self.is_path() { - s.emit_option_none() + None::.serialize(s) } else { - self.to_url().encode(s) + Some(self.to_url()).serialize(s) } } } -impl Decodable for SourceId { - fn decode(d: &mut D) -> Result { - let string: String = Decodable::decode(d)?; - SourceId::from_url(&string).map_err(|e| { - d.error(&e.to_string()) - }) +impl de::Deserialize for SourceId { + fn deserialize(d: D) -> Result + where D: de::Deserializer, + { + let string = String::deserialize(d)?; + SourceId::from_url(&string).map_err(de::Error::custom) } } diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index f63cd57cd5c..a844359e746 100755 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -3,6 +3,8 @@ #[cfg(test)] extern crate hamcrest; #[macro_use] extern crate log; +#[macro_use] extern crate serde_derive; +#[macro_use] extern crate serde_json; extern crate crates_io as registry; extern crate crossbeam; extern crate curl; @@ -18,6 +20,8 @@ extern crate libgit2_sys; extern crate num_cpus; extern crate rustc_serialize; extern crate semver; +extern crate serde; +extern crate serde_ignored; extern crate shell_escape; extern crate tar; extern crate tempdir; @@ -27,8 +31,8 @@ extern crate url; use std::io; use std::fmt; -use rustc_serialize::{Decodable, Encodable}; -use rustc_serialize::json; +use rustc_serialize::Decodable; +use serde::ser; use docopt::Docopt; use core::{Shell, MultiShell, ShellConfig, Verbosity, ColorConfig}; @@ -121,8 +125,8 @@ pub fn call_main_without_stdin( exec(flags, config) } -pub fn print_json(obj: &T) { - let encoded = json::encode(&obj).unwrap(); +pub fn print_json(obj: &T) { + let encoded = serde_json::to_string(&obj).unwrap(); println!("{}", encoded); } diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 02daac2ab6d..5ad84e376ff 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -19,13 +19,18 @@ use sources::{GitSource, PathSource, SourceConfigMap}; use util::{CargoResult, ChainError, Config, human, internal}; use util::{Filesystem, FileLock}; -#[derive(RustcDecodable, RustcEncodable)] +#[derive(Deserialize, Serialize)] +#[serde(untagged)] enum CrateListing { V1(CrateListingV1), - Empty, + Empty(Empty), } -#[derive(RustcDecodable, RustcEncodable)] +#[derive(Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct Empty {} + +#[derive(Deserialize, Serialize)] struct CrateListingV1 { v1: BTreeMap>, } @@ -412,12 +417,12 @@ fn read_crate_list(mut file: &File) -> CargoResult { (|| -> CargoResult<_> { let mut contents = String::new(); file.read_to_string(&mut contents)?; - let listing = toml::decode_str(&contents).chain_error(|| { + let listing = toml::from_str(&contents).chain_error(|| { internal("invalid TOML found for metadata") })?; match listing { CrateListing::V1(v1) => Ok(v1), - CrateListing::Empty => { + CrateListing::Empty(_) => { Ok(CrateListingV1 { v1: BTreeMap::new() }) } } @@ -430,7 +435,7 @@ fn write_crate_list(mut file: &File, listing: CrateListingV1) -> CargoResult<()> (|| -> CargoResult<_> { file.seek(SeekFrom::Start(0))?; file.set_len(0)?; - let data = toml::encode_str::(&CrateListing::V1(listing)); + let data = toml::to_string(&CrateListing::V1(listing))?; file.write_all(data.as_bytes())?; Ok(()) }).chain_error(|| { diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index e86a4de4189..bd48cb0a4b9 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -1,4 +1,4 @@ -use rustc_serialize::{Encodable, Encoder}; +use serde::ser::{self, Serialize}; use core::resolver::Resolve; use core::{Package, PackageId, Workspace}; @@ -67,7 +67,7 @@ fn metadata_full(ws: &Workspace, }) } -#[derive(RustcEncodable)] +#[derive(Serialize)] pub struct ExportInfo { packages: Vec, workspace_members: Vec, @@ -75,38 +75,29 @@ pub struct ExportInfo { version: u32, } -/// Newtype wrapper to provide a custom `Encodable` implementation. +/// Newtype wrapper to provide a custom `Serialize` implementation. /// The one from lockfile does not fit because it uses a non-standard /// format for `PackageId`s -struct MetadataResolve{ +#[derive(Serialize)] +struct MetadataResolve { + #[serde(rename = "nodes", serialize_with = "serialize_resolve")] resolve: Resolve, root: Option, } -impl Encodable for MetadataResolve { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - #[derive(RustcEncodable)] - struct EncodableResolve<'a> { - root: Option<&'a PackageId>, - nodes: Vec>, - } +fn serialize_resolve(resolve: &Resolve, s: S) -> Result + where S: ser::Serializer, +{ + #[derive(Serialize)] + struct Node<'a> { + id: &'a PackageId, + dependencies: Vec<&'a PackageId>, + } - #[derive(RustcEncodable)] - struct Node<'a> { - id: &'a PackageId, - dependencies: Vec<&'a PackageId>, + resolve.iter().map(|id| { + Node { + id: id, + dependencies: resolve.deps(id).collect(), } - - let encodable = EncodableResolve { - root: self.root.as_ref(), - nodes: self.resolve.iter().map(|id| { - Node { - id: id, - dependencies: self.resolve.deps(id).collect(), - } - }).collect(), - }; - - encodable.encode(s) - } + }).collect::>().serialize(s) } diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs index 9ada0fb748d..a3af64f4570 100644 --- a/src/cargo/ops/cargo_rustc/fingerprint.rs +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -6,7 +6,9 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use filetime::FileTime; -use rustc_serialize::{json, Encodable, Decodable, Encoder, Decoder}; +use serde::ser::{self, Serialize}; +use serde::de::{self, Deserialize}; +use serde_json; use core::{Package, TargetKind}; use util; @@ -125,18 +127,48 @@ pub fn prepare_target<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, /// `DependencyQueue`, but it also needs to be retained here because Cargo can /// be interrupted while executing, losing the state of the `DependencyQueue` /// graph. +#[derive(Serialize, Deserialize)] pub struct Fingerprint { rustc: u64, features: String, target: u64, profile: u64, + #[serde(serialize_with = "serialize_deps", deserialize_with = "deserialize_deps")] deps: Vec<(String, Arc)>, local: LocalFingerprint, + #[serde(skip_serializing, skip_deserializing)] memoized_hash: Mutex>, rustflags: Vec, } -#[derive(RustcEncodable, RustcDecodable, Hash)] +fn serialize_deps(deps: &Vec<(String, Arc)>, ser: S) + -> Result + where S: ser::Serializer, +{ + deps.iter().map(|&(ref a, ref b)| { + (a, b.hash()) + }).collect::>().serialize(ser) +} + +fn deserialize_deps(d: D) -> Result)>, D::Error> + where D: de::Deserializer, +{ + let decoded = >::deserialize(d)?; + Ok(decoded.into_iter().map(|(name, hash)| { + (name, Arc::new(Fingerprint { + rustc: 0, + target: 0, + profile: 0, + local: LocalFingerprint::Precalculated(String::new()), + features: String::new(), + deps: Vec::new(), + memoized_hash: Mutex::new(Some(hash)), + rustflags: Vec::new(), + })) + }).collect()) +} + +#[derive(Serialize, Deserialize, Hash)] enum LocalFingerprint { Precalculated(String), MtimeBased(MtimeSlot, PathBuf), @@ -242,79 +274,27 @@ impl hash::Hash for Fingerprint { } } -impl Encodable for Fingerprint { - fn encode(&self, e: &mut E) -> Result<(), E::Error> { - e.emit_struct("Fingerprint", 6, |e| { - e.emit_struct_field("rustc", 0, |e| self.rustc.encode(e))?; - e.emit_struct_field("target", 1, |e| self.target.encode(e))?; - e.emit_struct_field("profile", 2, |e| self.profile.encode(e))?; - e.emit_struct_field("local", 3, |e| self.local.encode(e))?; - e.emit_struct_field("features", 4, |e| { - self.features.encode(e) - })?; - e.emit_struct_field("deps", 5, |e| { - self.deps.iter().map(|&(ref a, ref b)| { - (a, b.hash()) - }).collect::>().encode(e) - })?; - e.emit_struct_field("rustflags", 6, |e| self.rustflags.encode(e))?; - Ok(()) - }) - } -} - -impl Decodable for Fingerprint { - fn decode(d: &mut D) -> Result { - fn decode(d: &mut D) -> Result { - Decodable::decode(d) - } - d.read_struct("Fingerprint", 6, |d| { - Ok(Fingerprint { - rustc: d.read_struct_field("rustc", 0, decode)?, - target: d.read_struct_field("target", 1, decode)?, - profile: d.read_struct_field("profile", 2, decode)?, - local: d.read_struct_field("local", 3, decode)?, - features: d.read_struct_field("features", 4, decode)?, - memoized_hash: Mutex::new(None), - deps: { - let decode = decode::, D>; - let v = d.read_struct_field("deps", 5, decode)?; - v.into_iter().map(|(name, hash)| { - (name, Arc::new(Fingerprint { - rustc: 0, - target: 0, - profile: 0, - local: LocalFingerprint::Precalculated(String::new()), - features: String::new(), - deps: Vec::new(), - memoized_hash: Mutex::new(Some(hash)), - rustflags: Vec::new(), - })) - }).collect() - }, - rustflags: d.read_struct_field("rustflags", 6, decode)?, - }) - }) - } -} - impl hash::Hash for MtimeSlot { fn hash(&self, h: &mut H) { self.0.lock().unwrap().hash(h) } } -impl Encodable for MtimeSlot { - fn encode(&self, e: &mut E) -> Result<(), E::Error> { +impl ser::Serialize for MtimeSlot { + fn serialize(&self, s: S) -> Result + where S: ser::Serializer, + { self.0.lock().unwrap().map(|ft| { (ft.seconds_relative_to_1970(), ft.nanoseconds()) - }).encode(e) + }).serialize(s) } } -impl Decodable for MtimeSlot { - fn decode(e: &mut D) -> Result { - let kind: Option<(u64, u32)> = Decodable::decode(e)?; +impl de::Deserialize for MtimeSlot { + fn deserialize(d: D) -> Result + where D: de::Deserializer, + { + let kind: Option<(u64, u32)> = de::Deserialize::deserialize(d)?; Ok(MtimeSlot(Mutex::new(kind.map(|(s, n)| { FileTime::from_seconds_since_1970(s, n) })))) @@ -507,7 +487,7 @@ fn write_fingerprint(loc: &Path, fingerprint: &Fingerprint) -> CargoResult<()> { debug!("write fingerprint: {}", loc.display()); paths::write(&loc, util::to_hex(hash).as_bytes())?; paths::write(&loc.with_extension("json"), - json::encode(&fingerprint).unwrap().as_bytes())?; + &serde_json::to_vec(&fingerprint).unwrap())?; Ok(()) } @@ -536,7 +516,7 @@ fn compare_old_fingerprint(loc: &Path, new_fingerprint: &Fingerprint) } let old_fingerprint_json = paths::read(&loc.with_extension("json"))?; - let old_fingerprint = json::decode(&old_fingerprint_json).chain_error(|| { + let old_fingerprint = serde_json::from_str(&old_fingerprint_json).chain_error(|| { internal(format!("failed to deserialize json")) })?; new_fingerprint.compare(&old_fingerprint) diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index a8cfa13b72d..b8d6f07d2c3 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -6,7 +6,7 @@ use std::io::{self, Write}; use std::path::{self, PathBuf}; use std::sync::Arc; -use rustc_serialize::json; +use serde_json; use core::{Package, PackageId, PackageSet, Target, Resolve}; use core::{Profile, Profiles, Workspace}; @@ -346,7 +346,7 @@ fn rustc(cx: &mut Context, unit: &Unit, exec: Arc) -> CargoResult CargoResult> { })?; (|| { - let table = cargo_toml::parse(&s, f.path(), ws.config())?; - let table = toml::Value::Table(table); - let mut d = toml::Decoder::new(table); - let v: resolver::EncodableResolve = Decodable::decode(&mut d)?; + let resolve = cargo_toml::parse(&s, f.path(), ws.config())?; + let v: resolver::EncodableResolve = resolve.try_into()?; Ok(Some(v.into_resolve(ws)?)) }).chain_error(|| { human(format!("failed to parse lock file at: {}", f.path().display())) @@ -50,24 +47,23 @@ pub fn write_pkg_lockfile(ws: &Workspace, resolve: &Resolve) -> CargoResult<()> true }; - let mut e = Encoder::new(); - WorkspaceResolve { + let toml = toml::Value::try_from(WorkspaceResolve { ws: ws, resolve: resolve, use_root_key: use_root_key, - }.encode(&mut e).unwrap(); + }).unwrap(); let mut out = String::new(); // Note that we do not use e.toml.to_string() as we want to control the // exact format the toml is in to ensure pretty diffs between updates to the // lockfile. - if let Some(root) = e.toml.get(&"root".to_string()) { + if let Some(root) = toml.get("root") { out.push_str("[root]\n"); emit_package(root.as_table().unwrap(), &mut out); } - let deps = e.toml[&"package".to_string()].as_slice().unwrap(); + let deps = toml["package"].as_array().unwrap(); for dep in deps.iter() { let dep = dep.as_table().unwrap(); @@ -75,9 +71,9 @@ pub fn write_pkg_lockfile(ws: &Workspace, resolve: &Resolve) -> CargoResult<()> emit_package(dep, &mut out); } - if let Some(metadata) = e.toml.get(&"metadata".to_string()) { + if let Some(meta) = toml.get("metadata") { out.push_str("[metadata]\n"); - out.push_str(&metadata.to_string()); + out.push_str(&meta.to_string()); } // If the lockfile contents haven't changed so don't rewrite it. This is @@ -117,16 +113,16 @@ fn has_crlf_line_endings(s: &str) -> bool { } } -fn emit_package(dep: &toml::Table, out: &mut String) { - out.push_str(&format!("name = {}\n", lookup(dep, "name"))); - out.push_str(&format!("version = {}\n", lookup(dep, "version"))); +fn emit_package(dep: &toml::value::Table, out: &mut String) { + out.push_str(&format!("name = {}\n", &dep["name"])); + out.push_str(&format!("version = {}\n", &dep["version"])); if dep.contains_key("source") { - out.push_str(&format!("source = {}\n", lookup(dep, "source"))); + out.push_str(&format!("source = {}\n", &dep["source"])); } - if let Some(s) = dep.get("dependencies") { - let slice = Value::as_slice(s).unwrap(); + if let Some(ref s) = dep.get("dependencies") { + let slice = s.as_array().unwrap(); if !slice.is_empty() { out.push_str("dependencies = [\n"); @@ -139,10 +135,6 @@ fn emit_package(dep: &toml::Table, out: &mut String) { } out.push_str("\n"); } else if dep.contains_key("replace") { - out.push_str(&format!("replace = {}\n\n", lookup(dep, "replace"))); + out.push_str(&format!("replace = {}\n\n", &dep["replace"])); } } - -fn lookup<'a>(table: &'a toml::Table, key: &str) -> &'a toml::Value { - table.get(key).expect(&format!("didn't find {}", key)) -} diff --git a/src/cargo/sources/directory.rs b/src/cargo/sources/directory.rs index c55fc3669a7..1cf8b27550b 100644 --- a/src/cargo/sources/directory.rs +++ b/src/cargo/sources/directory.rs @@ -5,7 +5,7 @@ use std::io::Read; use std::path::{Path, PathBuf}; use rustc_serialize::hex::ToHex; -use rustc_serialize::json; +use serde_json; use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry}; use sources::PathSource; @@ -19,7 +19,7 @@ pub struct DirectorySource<'cfg> { config: &'cfg Config, } -#[derive(RustcDecodable)] +#[derive(Deserialize)] struct Checksum { package: String, files: HashMap, @@ -93,7 +93,7 @@ impl<'cfg> Source for DirectorySource<'cfg> { pkg.package_id().version())) })?; - let cksum: Checksum = json::decode(&cksum).chain_error(|| { + let cksum: Checksum = serde_json::from_str(&cksum).chain_error(|| { human(format!("failed to decode `.cargo-checksum.json` of \ {} v{}", pkg.package_id().name(), diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 877752cead4..97c43118c34 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -3,9 +3,9 @@ use std::fmt; use std::fs::{self, File}; use std::path::{Path, PathBuf}; -use rustc_serialize::{Encodable, Encoder}; -use url::Url; use git2::{self, ObjectType}; +use serde::ser::{self, Serialize}; +use url::Url; use core::GitReference; use util::{CargoResult, ChainError, human, ToUrl, internal, Config, network}; @@ -13,6 +13,19 @@ use util::{CargoResult, ChainError, human, ToUrl, internal, Config, network}; #[derive(PartialEq, Clone, Debug)] pub struct GitRevision(git2::Oid); +impl ser::Serialize for GitRevision { + fn serialize(&self, s: S) -> Result { + serialize_str(self, s) + } +} + +fn serialize_str(t: &T, s: S) -> Result + where T: fmt::Display, + S: ser::Serializer, +{ + t.to_string().serialize(s) +} + impl fmt::Display for GitRevision { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) @@ -29,77 +42,34 @@ impl GitShortID { /// GitRemote represents a remote repository. It gets cloned into a local /// GitDatabase. -#[derive(PartialEq,Clone,Debug)] +#[derive(PartialEq, Clone, Debug, Serialize)] pub struct GitRemote { + #[serde(serialize_with = "serialize_str")] url: Url, } -#[derive(PartialEq,Clone,RustcEncodable)] -struct EncodableGitRemote { - url: String, -} - -impl Encodable for GitRemote { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - EncodableGitRemote { - url: self.url.to_string() - }.encode(s) - } -} - /// GitDatabase is a local clone of a remote repository's database. Multiple /// GitCheckouts can be cloned from this GitDatabase. +#[derive(Serialize)] pub struct GitDatabase { remote: GitRemote, path: PathBuf, + #[serde(skip_serializing)] repo: git2::Repository, } -#[derive(RustcEncodable)] -pub struct EncodableGitDatabase { - remote: GitRemote, - path: String, -} - -impl Encodable for GitDatabase { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - EncodableGitDatabase { - remote: self.remote.clone(), - path: self.path.display().to_string() - }.encode(s) - } -} - /// GitCheckout is a local checkout of a particular revision. Calling /// `clone_into` with a reference will resolve the reference into a revision, /// and return a CargoError if no revision for that reference was found. +#[derive(Serialize)] pub struct GitCheckout<'a> { database: &'a GitDatabase, location: PathBuf, revision: GitRevision, + #[serde(skip_serializing)] repo: git2::Repository, } -#[derive(RustcEncodable)] -pub struct EncodableGitCheckout { - database: EncodableGitDatabase, - location: String, - revision: String, -} - -impl<'a> Encodable for GitCheckout<'a> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - EncodableGitCheckout { - location: self.location.display().to_string(), - revision: self.revision.to_string(), - database: EncodableGitDatabase { - remote: self.database.remote.clone(), - path: self.database.path.display().to_string(), - }, - }.encode(s) - } -} - // Implementations impl GitRemote { diff --git a/src/cargo/sources/registry/index.rs b/src/cargo/sources/registry/index.rs index fffdd5702c8..bbd7e226ca7 100644 --- a/src/cargo/sources/registry/index.rs +++ b/src/cargo/sources/registry/index.rs @@ -3,7 +3,7 @@ use std::io::prelude::*; use std::fs::File; use std::path::Path; -use rustc_serialize::json; +use serde_json; use core::dependency::{Dependency, DependencyInner, Kind}; use core::{SourceId, Summary, PackageId, Registry}; @@ -116,7 +116,7 @@ impl<'cfg> RegistryIndex<'cfg> { -> CargoResult<(Summary, bool)> { let RegistryPackage { name, vers, cksum, deps, features, yanked - } = json::decode::(line)?; + } = serde_json::from_str::(line)?; let pkgid = PackageId::new(&name, &vers, &self.source_id)?; let deps: CargoResult> = deps.into_iter().map(|dep| { self.parse_registry_dependency(dep) diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index 0f188a00870..2044c30ebfe 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -184,7 +184,7 @@ pub struct RegistrySource<'cfg> { index_locked: bool, } -#[derive(RustcDecodable)] +#[derive(Deserialize)] pub struct RegistryConfig { /// Download endpoint for all crates. This will be appended with /// `///download` and then will be hit with an HTTP GET @@ -196,7 +196,7 @@ pub struct RegistryConfig { pub api: String, } -#[derive(RustcDecodable)] +#[derive(Deserialize)] struct RegistryPackage { name: String, vers: String, @@ -206,7 +206,7 @@ struct RegistryPackage { yanked: Option, } -#[derive(RustcDecodable)] +#[derive(Deserialize)] struct RegistryDependency { name: String, req: String, diff --git a/src/cargo/sources/registry/remote.rs b/src/cargo/sources/registry/remote.rs index e3c9b9c7b41..67e60a074c9 100644 --- a/src/cargo/sources/registry/remote.rs +++ b/src/cargo/sources/registry/remote.rs @@ -5,7 +5,7 @@ use std::path::Path; use curl::easy::{Easy, List}; use git2; use rustc_serialize::hex::ToHex; -use rustc_serialize::json; +use serde_json; use url::Url; use core::{PackageId, SourceId}; @@ -49,7 +49,7 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> { "the registry index")?; let path = lock.path().parent().unwrap(); let contents = paths::read(&path.join("config.json"))?; - let config = json::decode(&contents)?; + let config = serde_json::from_str(&contents)?; Ok(Some(config)) } diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index abee2381713..08af70451c8 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -372,14 +372,13 @@ impl Config { walk_tree(&self.cwd, |mut file, path| { let mut contents = String::new(); file.read_to_string(&mut contents)?; - let table = cargo_toml::parse(&contents, - path, - self).chain_error(|| { + let toml = cargo_toml::parse(&contents, + &path, + self).chain_error(|| { human(format!("could not parse TOML configuration in `{}`", path.display())) })?; - let toml = toml::Value::Table(table); - let value = CV::from_toml(path, toml).chain_error(|| { + let value = CV::from_toml(&path, toml).chain_error(|| { human(format!("failed to load TOML configuration from `{}`", path.display())) })?; @@ -409,13 +408,13 @@ impl Config { } } -#[derive(Eq, PartialEq, Clone, RustcEncodable, RustcDecodable, Copy)] +#[derive(Eq, PartialEq, Clone, Copy)] pub enum Location { Project, Global } -#[derive(Eq,PartialEq,Clone,RustcDecodable)] +#[derive(Eq,PartialEq,Clone,Deserialize)] pub enum ConfigValue { Integer(i64, PathBuf), String(String, PathBuf), @@ -743,9 +742,11 @@ pub fn set_config(cfg: &Config, let mut contents = String::new(); let _ = file.read_to_string(&mut contents); let mut toml = cargo_toml::parse(&contents, file.path(), cfg)?; - toml.insert(key.to_string(), value.into_toml()); + toml.as_table_mut() + .unwrap() + .insert(key.to_string(), value.into_toml()); - let contents = toml::Value::Table(toml).to_string(); + let contents = toml.to_string(); file.seek(SeekFrom::Start(0))?; file.write_all(contents.as_bytes())?; file.file().set_len(contents.len() as u64)?; diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index c7babd0b77f..14697ad8ea8 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -11,8 +11,8 @@ use std::string; use curl; use git2; use handlebars; -use rustc_serialize::json; use semver; +use serde_json; use term; use toml; use url; @@ -334,13 +334,12 @@ from_error! { io::Error, ProcessError, git2::Error, - json::DecoderError, - json::EncoderError, + serde_json::Error, curl::Error, CliError, - toml::Error, url::ParseError, - toml::DecodeError, + toml::ser::Error, + toml::de::Error, ffi::NulError, term::Error, num::ParseIntError, @@ -363,14 +362,17 @@ impl From> for Box { impl CargoError for semver::ReqParseError {} impl CargoError for io::Error {} impl CargoError for git2::Error {} -impl CargoError for json::DecoderError {} -impl CargoError for json::EncoderError {} +impl CargoError for serde_json::Error {} impl CargoError for curl::Error {} impl CargoError for ProcessError {} impl CargoError for CargoTestError {} impl CargoError for CliError {} -impl CargoError for toml::Error {} -impl CargoError for toml::DecodeError {} +impl CargoError for toml::ser::Error { + fn is_human(&self) -> bool { true } +} +impl CargoError for toml::de::Error { + fn is_human(&self) -> bool { true } +} impl CargoError for url::ParseError {} impl CargoError for ffi::NulError {} impl CargoError for term::Error {} diff --git a/src/cargo/util/machine_message.rs b/src/cargo/util/machine_message.rs index 64e6c35f160..9626494cd3d 100644 --- a/src/cargo/util/machine_message.rs +++ b/src/cargo/util/machine_message.rs @@ -1,27 +1,23 @@ -use rustc_serialize::Encodable; -use rustc_serialize::json::{self, Json}; +use serde::ser; +use serde_json::{self, Value}; use core::{PackageId, Target, Profile}; -pub trait Message: Encodable { +pub trait Message: ser::Serialize { fn reason(&self) -> &str; } pub fn emit(t: T) { - let json = json::encode(&t).unwrap(); - let mut map = match json.parse().unwrap() { - Json::Object(obj) => obj, - _ => panic!("not a json object"), - }; - map.insert("reason".to_string(), Json::String(t.reason().to_string())); - println!("{}", Json::Object(map)); + let mut json: Value = serde_json::to_value(&t).unwrap(); + json["reason"] = json!(t.reason()); + println!("{}", json); } -#[derive(RustcEncodable)] +#[derive(Serialize)] pub struct FromCompiler<'a> { pub package_id: &'a PackageId, pub target: &'a Target, - pub message: json::Json, + pub message: serde_json::Value, } impl<'a> Message for FromCompiler<'a> { @@ -30,7 +26,7 @@ impl<'a> Message for FromCompiler<'a> { } } -#[derive(RustcEncodable)] +#[derive(Serialize)] pub struct Artifact<'a> { pub package_id: &'a PackageId, pub target: &'a Target, @@ -45,7 +41,7 @@ impl<'a> Message for Artifact<'a> { } } -#[derive(RustcEncodable)] +#[derive(Serialize)] pub struct BuildScript<'a> { pub package_id: &'a PackageId, pub linked_libs: &'a [String], diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 8c06e30ca87..d44dafe56be 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{HashMap, HashSet, BTreeSet}; use std::default::Default; use std::fmt; use std::fs; @@ -7,7 +7,8 @@ use std::str; use toml; use semver::{self, VersionReq}; -use rustc_serialize::{Decodable, Decoder}; +use serde::de::{self, Deserialize}; +use serde_ignored; use core::{SourceId, Profiles, PackageIdSpec, GitReference, WorkspaceConfig}; use core::{Summary, Manifest, Target, Dependency, DependencyInner, PackageId}; @@ -29,7 +30,6 @@ pub struct Layout { examples: Vec, tests: Vec, benches: Vec, - } impl Layout { @@ -102,15 +102,19 @@ pub fn to_manifest(contents: &str, None => manifest.clone(), }; let root = parse(contents, &manifest, config)?; - let mut d = toml::Decoder::new(toml::Value::Table(root)); - let manifest: TomlManifest = Decodable::decode(&mut d).map_err(|e| { - human(e.to_string()) + let mut unused = BTreeSet::new(); + let manifest: TomlManifest = serde_ignored::deserialize(root, |path| { + let mut key = String::new(); + stringify(&mut key, &path); + if !key.starts_with("package.metadata") { + unused.insert(key); + } })?; return match manifest.to_real_manifest(source_id, &layout, config) { Ok((mut manifest, paths)) => { - if let Some(ref toml) = d.toml { - add_unused_keys(&mut manifest, toml, String::new()); + for key in unused { + manifest.add_warning(format!("unused manifest key: {}", key)); } if !manifest.targets().iter().any(|t| !t.is_custom_build()) { bail!("no targets specified in the manifest\n \ @@ -127,41 +131,43 @@ pub fn to_manifest(contents: &str, } }; - fn add_unused_keys(m: &mut Manifest, toml: &toml::Value, key: String) { - if key == "package.metadata" { - return - } - match *toml { - toml::Value::Table(ref table) => { - for (k, v) in table.iter() { - add_unused_keys(m, v, if key.is_empty() { - k.clone() - } else { - key.clone() + "." + k - }) + fn stringify(dst: &mut String, path: &serde_ignored::Path) { + use serde_ignored::Path; + + match *path { + Path::Root => {} + Path::Seq { parent, index } => { + stringify(dst, parent); + if dst.len() > 0 { + dst.push_str("."); } + dst.push_str(&index.to_string()); } - toml::Value::Array(ref arr) => { - for v in arr.iter() { - add_unused_keys(m, v, key.clone()); + Path::Map { parent, ref key } => { + stringify(dst, parent); + if dst.len() > 0 { + dst.push_str("."); } + dst.push_str(key); } - _ => m.add_warning(format!("unused manifest key: {}", key)), + Path::Some { parent } | + Path::NewtypeVariant { parent } | + Path::NewtypeStruct { parent } => stringify(dst, parent), } } } pub fn parse(toml: &str, file: &Path, - config: &Config) -> CargoResult { - let mut first_parser = toml::Parser::new(toml); - if let Some(toml) = first_parser.parse() { - return Ok(toml); - } + config: &Config) -> CargoResult { + let first_error = match toml.parse() { + Ok(ret) => return Ok(ret), + Err(e) => e, + }; - let mut second_parser = toml::Parser::new(toml); + let mut second_parser = toml::de::Deserializer::new(toml); second_parser.set_require_newline_after_table(false); - if let Some(toml) = second_parser.parse() { + if let Ok(ret) = toml::Value::deserialize(&mut second_parser) { let msg = format!("\ TOML file found which contains invalid syntax and will soon not parse at `{}`. @@ -171,25 +177,12 @@ invalid), but this file has a table header which does not have a newline after it. A newline needs to be added and this warning will soon become a hard error in the future.", file.display()); config.shell().warn(&msg)?; - return Ok(toml) + return Ok(ret) } - let mut error_str = "could not parse input as TOML\n".to_string(); - for error in first_parser.errors.iter() { - let (loline, locol) = first_parser.to_linecol(error.lo); - let (hiline, hicol) = first_parser.to_linecol(error.hi); - error_str.push_str(&format!("{}:{}:{}{} {}\n", - file.display(), - loline + 1, locol + 1, - if loline != hiline || locol != hicol { - format!("-{}:{}", hiline + 1, - hicol + 1) - } else { - "".to_string() - }, - error.desc)); - } - Err(human(error_str)) + Err(first_error).chain_error(|| { + human("could not parse input as TOML") + }) } type TomlLibTarget = TomlTarget; @@ -198,14 +191,15 @@ type TomlExampleTarget = TomlTarget; type TomlTestTarget = TomlTarget; type TomlBenchTarget = TomlTarget; -#[derive(RustcDecodable)] +#[derive(Deserialize)] +#[serde(untagged)] pub enum TomlDependency { Simple(String), Detailed(DetailedTomlDependency) } -#[derive(RustcDecodable, Clone, Default)] +#[derive(Deserialize, Clone, Default)] pub struct DetailedTomlDependency { version: Option, path: Option, @@ -215,10 +209,11 @@ pub struct DetailedTomlDependency { rev: Option, features: Option>, optional: Option, + #[serde(rename = "default-features")] default_features: Option, } -#[derive(RustcDecodable)] +#[derive(Deserialize)] pub struct TomlManifest { package: Option>, project: Option>, @@ -229,7 +224,9 @@ pub struct TomlManifest { test: Option>, bench: Option>, dependencies: Option>, + #[serde(rename = "dev-dependencies")] dev_dependencies: Option>, + #[serde(rename = "build-dependencies")] build_dependencies: Option>, features: Option>>, target: Option>, @@ -238,7 +235,7 @@ pub struct TomlManifest { badges: Option>>, } -#[derive(RustcDecodable, Clone, Default)] +#[derive(Deserialize, Clone, Default)] pub struct TomlProfiles { test: Option, doc: Option, @@ -250,50 +247,74 @@ pub struct TomlProfiles { #[derive(Clone)] pub struct TomlOptLevel(String); -impl Decodable for TomlOptLevel { - fn decode(d: &mut D) -> Result { - match d.read_u32() { - Ok(i) => Ok(TomlOptLevel(i.to_string())), - Err(_) => { - match d.read_str() { - Ok(ref s) if s == "s" || s == "z" => - Ok(TomlOptLevel(s.to_string())), - Ok(_) | Err(_) => - Err(d.error("expected an integer, a string \"z\" or a string \"s\"")) +impl de::Deserialize for TomlOptLevel { + fn deserialize(d: D) -> Result + where D: de::Deserializer + { + struct Visitor; + + impl de::Visitor for Visitor { + type Value = TomlOptLevel; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an optimization level") + } + + fn visit_i64(self, value: i64) -> Result + where E: de::Error + { + Ok(TomlOptLevel(value.to_string())) + } + + fn visit_str(self, value: &str) -> Result + where E: de::Error + { + if value == "s" || value == "z" { + Ok(TomlOptLevel(value.to_string())) + } else { + Err(E::custom(format!("must be an integer, `z`, or `s`, \ + but found: {}", value))) } } } + + d.deserialize_u32(Visitor) } } -#[derive(RustcDecodable, Clone)] +#[derive(Deserialize, Clone)] +#[serde(untagged)] pub enum U32OrBool { U32(u32), Bool(bool), } -#[derive(RustcDecodable, Clone, Default)] +#[derive(Deserialize, Clone, Default)] pub struct TomlProfile { + #[serde(rename = "opt-level")] opt_level: Option, lto: Option, + #[serde(rename = "codegen-units")] codegen_units: Option, debug: Option, + #[serde(rename = "debug-assertions")] debug_assertions: Option, rpath: Option, panic: Option, } -#[derive(RustcDecodable, Clone, Debug)] +#[derive(Deserialize, Clone, Debug)] +#[serde(untagged)] pub enum StringOrBool { String(String), Bool(bool), } -#[derive(RustcDecodable)] +#[derive(Deserialize)] pub struct TomlProject { name: String, version: TomlVersion, - authors: Vec, + authors: Option>, build: Option, links: Option, exclude: Option>, @@ -309,11 +330,12 @@ pub struct TomlProject { keywords: Option>, categories: Option>, license: Option, + #[serde(rename = "license-file")] license_file: Option, repository: Option, } -#[derive(RustcDecodable)] +#[derive(Deserialize)] pub struct TomlWorkspace { members: Option>, } @@ -322,13 +344,30 @@ pub struct TomlVersion { version: semver::Version, } -impl Decodable for TomlVersion { - fn decode(d: &mut D) -> Result { - let s = d.read_str()?; - match s.to_semver() { - Ok(s) => Ok(TomlVersion { version: s }), - Err(e) => Err(d.error(&e)), +impl de::Deserialize for TomlVersion { + fn deserialize(d: D) -> Result + where D: de::Deserializer + { + struct Visitor; + + impl de::Visitor for Visitor { + type Value = TomlVersion; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a semver version") + } + + fn visit_str(self, value: &str) -> Result + where E: de::Error + { + match value.to_semver() { + Ok(s) => Ok(TomlVersion { version: s}), + Err(e) => Err(E::custom(e)), + } + } } + + d.deserialize_str(Visitor) } } @@ -630,7 +669,7 @@ impl TomlManifest { homepage: project.homepage.clone(), documentation: project.documentation.clone(), readme: project.readme.clone(), - authors: project.authors.clone(), + authors: project.authors.clone().unwrap_or(Vec::new()), license: project.license.clone(), license_file: project.license_file.clone(), repository: project.repository.clone(), @@ -918,50 +957,50 @@ impl TomlDependency { } } -#[derive(RustcDecodable, Debug, Clone)] +#[derive(Default, Deserialize, Debug, Clone)] struct TomlTarget { name: Option, + + // The intention was to only accept `crate-type` here but historical + // versions of Cargo also accepted `crate_type`, so look for both. + #[serde(rename = "crate-type")] crate_type: Option>, + #[serde(rename = "crate_type")] + crate_type2: Option>, + path: Option, test: Option, doctest: Option, bench: Option, doc: Option, plugin: Option, + #[serde(rename = "proc-macro")] proc_macro: Option, harness: Option, + #[serde(rename = "required-features")] required_features: Option>, } -#[derive(RustcDecodable, Clone)] +#[derive(Deserialize, Clone)] +#[serde(untagged)] enum PathValue { String(String), Path(PathBuf), } /// Corresponds to a `target` entry, but `TomlTarget` is already used. -#[derive(RustcDecodable)] +#[derive(Deserialize)] struct TomlPlatform { dependencies: Option>, + #[serde(rename = "build-dependencies")] build_dependencies: Option>, + #[serde(rename = "dev-dependencies")] dev_dependencies: Option>, } impl TomlTarget { fn new() -> TomlTarget { - TomlTarget { - name: None, - crate_type: None, - path: None, - test: None, - doctest: None, - bench: None, - doc: None, - plugin: None, - proc_macro: None, - harness: None, - required_features: None - } + TomlTarget::default() } fn name(&self) -> String { @@ -1100,7 +1139,8 @@ fn normalize(package_root: &Path, let path = l.path.clone().unwrap_or_else( || PathValue::Path(Path::new("src").join(&format!("{}.rs", l.name()))) ); - let crate_types = match l.crate_type.clone() { + let crate_types = l.crate_type.as_ref().or(l.crate_type2.as_ref()); + let crate_types = match crate_types { Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(), None => { vec![ if l.plugin == Some(true) {LibKind::Dylib} @@ -1148,8 +1188,9 @@ fn normalize(package_root: &Path, PathValue::Path(default(ex)) }); - let crate_types = match ex.crate_type { - Some(ref kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(), + let crate_types = ex.crate_type.as_ref().or(ex.crate_type2.as_ref()); + let crate_types = match crate_types { + Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(), None => Vec::new() }; diff --git a/src/crates-io/Cargo.toml b/src/crates-io/Cargo.toml index 54a54e1dea0..21db0467fe9 100644 --- a/src/crates-io/Cargo.toml +++ b/src/crates-io/Cargo.toml @@ -14,5 +14,7 @@ path = "lib.rs" [dependencies] curl = "0.4" +serde = "0.9" +serde_derive = "0.9" +serde_json = "0.9" url = "1.0" -rustc-serialize = "0.3" diff --git a/src/crates-io/lib.rs b/src/crates-io/lib.rs index 915f44363a3..df032f349f2 100644 --- a/src/crates-io/lib.rs +++ b/src/crates-io/lib.rs @@ -1,6 +1,8 @@ extern crate curl; extern crate url; -extern crate rustc_serialize; +extern crate serde_json; +#[macro_use] +extern crate serde_derive; use std::collections::HashMap; use std::fmt; @@ -10,7 +12,6 @@ use std::io::{self, Cursor}; use std::result; use curl::easy::{Easy, List}; -use rustc_serialize::json::{self, Json}; use url::percent_encoding::{percent_encode, QUERY_ENCODE_SET}; @@ -37,26 +38,12 @@ pub enum Error { TokenMissing, Io(io::Error), NotFound, - JsonEncodeError(json::EncoderError), - JsonDecodeError(json::DecoderError), - JsonParseError(json::ParserError), + Json(serde_json::Error), } -impl From for Error { - fn from(err: json::EncoderError) -> Error { - Error::JsonEncodeError(err) - } -} - -impl From for Error { - fn from(err: json::DecoderError) -> Error { - Error::JsonDecodeError(err) - } -} - -impl From for Error { - fn from(err: json::ParserError) -> Error { - Error::JsonParseError(err) +impl From for Error { + fn from(err: serde_json::Error) -> Error { + Error::Json(err) } } @@ -66,14 +53,14 @@ impl From for Error { } } -#[derive(RustcDecodable)] +#[derive(Deserialize)] pub struct Crate { pub name: String, pub description: Option, pub max_version: String } -#[derive(RustcEncodable)] +#[derive(Serialize)] pub struct NewCrate { pub name: String, pub vers: String, @@ -92,7 +79,7 @@ pub struct NewCrate { pub badges: HashMap>, } -#[derive(RustcEncodable)] +#[derive(Serialize)] pub struct NewCrateDependency { pub optional: bool, pub default_features: bool, @@ -103,7 +90,7 @@ pub struct NewCrateDependency { pub kind: String, } -#[derive(RustcDecodable)] +#[derive(Deserialize)] pub struct User { pub id: u32, pub login: String, @@ -117,13 +104,13 @@ pub struct Warnings { pub invalid_badges: Vec, } -#[derive(RustcDecodable)] struct R { ok: bool } -#[derive(RustcDecodable)] struct ApiErrorList { errors: Vec } -#[derive(RustcDecodable)] struct ApiError { detail: String } -#[derive(RustcEncodable)] struct OwnersReq<'a> { users: &'a [&'a str] } -#[derive(RustcDecodable)] struct Users { users: Vec } -#[derive(RustcDecodable)] struct TotalCrates { total: u32 } -#[derive(RustcDecodable)] struct Crates { crates: Vec, meta: TotalCrates } +#[derive(Deserialize)] struct R { ok: bool } +#[derive(Deserialize)] struct ApiErrorList { errors: Vec } +#[derive(Deserialize)] struct ApiError { detail: String } +#[derive(Serialize)] struct OwnersReq<'a> { users: &'a [&'a str] } +#[derive(Deserialize)] struct Users { users: Vec } +#[derive(Deserialize)] struct TotalCrates { total: u32 } +#[derive(Deserialize)] struct Crates { crates: Vec, meta: TotalCrates } impl Registry { pub fn new(host: String, token: Option) -> Registry { Registry::new_handle(host, token, Easy::new()) @@ -140,29 +127,29 @@ impl Registry { } pub fn add_owners(&mut self, krate: &str, owners: &[&str]) -> Result<()> { - let body = json::encode(&OwnersReq { users: owners })?; + let body = serde_json::to_string(&OwnersReq { users: owners })?; let body = self.put(format!("/crates/{}/owners", krate), body.as_bytes())?; - assert!(json::decode::(&body)?.ok); + assert!(serde_json::from_str::(&body)?.ok); Ok(()) } pub fn remove_owners(&mut self, krate: &str, owners: &[&str]) -> Result<()> { - let body = json::encode(&OwnersReq { users: owners })?; + let body = serde_json::to_string(&OwnersReq { users: owners })?; let body = self.delete(format!("/crates/{}/owners", krate), Some(body.as_bytes()))?; - assert!(json::decode::(&body)?.ok); + assert!(serde_json::from_str::(&body)?.ok); Ok(()) } pub fn list_owners(&mut self, krate: &str) -> Result> { let body = self.get(format!("/crates/{}/owners", krate))?; - Ok(json::decode::(&body)?.users) + Ok(serde_json::from_str::(&body)?.users) } pub fn publish(&mut self, krate: &NewCrate, tarball: &File) -> Result { - let json = json::encode(krate)?; + let json = serde_json::to_string(krate)?; // Prepare the body. The format of the upload request is: // // @@ -208,28 +195,27 @@ impl Registry { body.read(buf).unwrap_or(0) })?; - // Can't derive RustcDecodable because JSON has a key named "crate" :( let response = if body.len() > 0 { - Json::from_str(&body)? + body.parse::()? } else { - Json::from_str("{}")? + "{}".parse()? }; let invalid_categories: Vec = - response - .find_path(&["warnings", "invalid_categories"]) - .and_then(Json::as_array) + response.get("warnings") + .and_then(|j| j.get("invalid_categories")) + .and_then(|j| j.as_array()) .map(|x| { - x.iter().flat_map(Json::as_string).map(Into::into).collect() + x.iter().flat_map(|j| j.as_str()).map(Into::into).collect() }) .unwrap_or_else(Vec::new); let invalid_badges: Vec = - response - .find_path(&["warnings", "invalid_badges"]) - .and_then(Json::as_array) + response.get("warnings") + .and_then(|j| j.get("invalid_badges")) + .and_then(|j| j.as_array()) .map(|x| { - x.iter().flat_map(Json::as_string).map(Into::into).collect() + x.iter().flat_map(|j| j.as_str()).map(Into::into).collect() }) .unwrap_or_else(Vec::new); @@ -246,21 +232,21 @@ impl Registry { None, Auth::Unauthorized )?; - let crates = json::decode::(&body)?; + let crates = serde_json::from_str::(&body)?; Ok((crates.crates, crates.meta.total)) } pub fn yank(&mut self, krate: &str, version: &str) -> Result<()> { let body = self.delete(format!("/crates/{}/{}/yank", krate, version), None)?; - assert!(json::decode::(&body)?.ok); + assert!(serde_json::from_str::(&body)?.ok); Ok(()) } pub fn unyank(&mut self, krate: &str, version: &str) -> Result<()> { let body = self.put(format!("/crates/{}/{}/unyank", krate, version), &[])?; - assert!(json::decode::(&body)?.ok); + assert!(serde_json::from_str::(&body)?.ok); Ok(()) } @@ -337,7 +323,7 @@ fn handle(handle: &mut Easy, Ok(body) => body, Err(..) => return Err(Error::NonUtf8Body), }; - match json::decode::(&body) { + match serde_json::from_str::(&body) { Ok(errors) => { return Err(Error::Api(errors.errors.into_iter().map(|s| s.detail) .collect())) @@ -369,9 +355,7 @@ impl fmt::Display for Error { Error::TokenMissing => write!(f, "no upload token found, please run `cargo login`"), Error::Io(ref e) => write!(f, "io error: {}", e), Error::NotFound => write!(f, "cannot find crate"), - Error::JsonEncodeError(ref e) => write!(f, "json encode error: {}", e), - Error::JsonDecodeError(ref e) => write!(f, "json decode error: {}", e), - Error::JsonParseError(ref e) => write!(f, "json parse error: {}", e), + Error::Json(ref e) => write!(f, "json error: {}", e), } } } diff --git a/tests/bad-config.rs b/tests/bad-config.rs index 63aae50dfa4..9db8606d86c 100644 --- a/tests/bad-config.rs +++ b/tests/bad-config.rs @@ -206,12 +206,13 @@ fn invalid_global_config() { [ERROR] Couldn't load Cargo configuration Caused by: - could not parse TOML configuration in `[..]config` + could not parse TOML configuration in `[..]` Caused by: could not parse input as TOML -[..]config:1:2 expected `=`, but found eof +Caused by: + expected an equals, found eof at line 1 ")); } @@ -232,7 +233,7 @@ fn bad_cargo_lock() { [ERROR] failed to parse lock file at: [..]Cargo.lock Caused by: - expected a value of type `string` for the key `package.name` + missing field `name` for key `package` ")); } @@ -315,7 +316,7 @@ fn bad_source_in_cargo_lock() { [ERROR] failed to parse lock file at: [..] Caused by: - invalid source `You shall not parse` for the key `package.source` + invalid source `You shall not parse` for key `package.source` ")); } @@ -421,8 +422,9 @@ fn malformed_override() { Caused by: could not parse input as TOML -Cargo.toml:[..] +Caused by: + expected a table key, found a newline at line 8 ")); } diff --git a/tests/build.rs b/tests/build.rs index 721ec3478b7..c937f0487e4 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -100,8 +100,9 @@ fn cargo_compile_with_invalid_manifest2() { Caused by: could not parse input as TOML -Cargo.toml:3:19-3:20 expected a value +Caused by: + invalid number at line 3 ")) } @@ -124,8 +125,11 @@ fn cargo_compile_with_invalid_manifest3() { [ERROR] failed to parse manifest at `[..]` Caused by: - could not parse input as TOML\n\ -src[/]Cargo.toml:1:5-1:6 expected a value\n\n")) + could not parse input as TOML + +Caused by: + invalid number at line 1 +")) } #[test] @@ -175,7 +179,7 @@ fn cargo_compile_with_invalid_version() { [ERROR] failed to parse manifest at `[..]` Caused by: - cannot parse '1.0' as a semver for the key `project.version` + cannot parse '1.0' as a semver for key `project.version` ")) } @@ -876,39 +880,39 @@ suffix = env::consts::DLL_SUFFIX, fn crate_env_vars() { let p = project("foo") .file("Cargo.toml", r#" - [project] - name = "foo" - version = "0.5.1-alpha.1" - description = "This is foo" - homepage = "http://example.com" - authors = ["wycats@example.com"] + [project] + name = "foo" + version = "0.5.1-alpha.1" + description = "This is foo" + homepage = "http://example.com" + authors = ["wycats@example.com"] "#) .file("src/main.rs", r#" extern crate foo; - static VERSION_MAJOR: &'static str = env!("CARGO_PKG_VERSION_MAJOR"); - static VERSION_MINOR: &'static str = env!("CARGO_PKG_VERSION_MINOR"); - static VERSION_PATCH: &'static str = env!("CARGO_PKG_VERSION_PATCH"); - static VERSION_PRE: &'static str = env!("CARGO_PKG_VERSION_PRE"); - static VERSION: &'static str = env!("CARGO_PKG_VERSION"); - static CARGO_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR"); - static PKG_NAME: &'static str = env!("CARGO_PKG_NAME"); - static HOMEPAGE: &'static str = env!("CARGO_PKG_HOMEPAGE"); - static DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION"); + static VERSION_MAJOR: &'static str = env!("CARGO_PKG_VERSION_MAJOR"); + static VERSION_MINOR: &'static str = env!("CARGO_PKG_VERSION_MINOR"); + static VERSION_PATCH: &'static str = env!("CARGO_PKG_VERSION_PATCH"); + static VERSION_PRE: &'static str = env!("CARGO_PKG_VERSION_PRE"); + static VERSION: &'static str = env!("CARGO_PKG_VERSION"); + static CARGO_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR"); + static PKG_NAME: &'static str = env!("CARGO_PKG_NAME"); + static HOMEPAGE: &'static str = env!("CARGO_PKG_HOMEPAGE"); + static DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION"); fn main() { let s = format!("{}-{}-{} @ {} in {}", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_PRE, CARGO_MANIFEST_DIR); - assert_eq!(s, foo::version()); - println!("{}", s); - assert_eq!("foo", PKG_NAME); - assert_eq!("http://example.com", HOMEPAGE); - assert_eq!("This is foo", DESCRIPTION); + assert_eq!(s, foo::version()); + println!("{}", s); + assert_eq!("foo", PKG_NAME); + assert_eq!("http://example.com", HOMEPAGE); + assert_eq!("This is foo", DESCRIPTION); let s = format!("{}.{}.{}-{}", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_PRE); - assert_eq!(s, VERSION); + assert_eq!(s, VERSION); } "#) .file("src/lib.rs", r#" @@ -1755,8 +1759,9 @@ Caused by: Caused by: could not parse input as TOML -[..].cargo[..]config:2:20-2:21 expected `=`, but found `i` +Caused by: + expected an equals, found an identifier at line 2 ")); } diff --git a/tests/cargotest/Cargo.toml b/tests/cargotest/Cargo.toml index 55ef9643f1b..233a378d3ee 100644 --- a/tests/cargotest/Cargo.toml +++ b/tests/cargotest/Cargo.toml @@ -17,6 +17,8 @@ kernel32-sys = "0.2" libc = "0.2" log = "0.3" rustc-serialize = "0.3" +serde = "0.9" +serde_json = "0.9" tar = { version = "0.4", default-features = false } tempdir = "0.3" term = "0.4.4" diff --git a/tests/cargotest/lib.rs b/tests/cargotest/lib.rs index affb7863795..11df25fdd13 100644 --- a/tests/cargotest/lib.rs +++ b/tests/cargotest/lib.rs @@ -8,6 +8,9 @@ extern crate git2; extern crate hamcrest; extern crate libc; extern crate rustc_serialize; +extern crate serde; +#[macro_use] +extern crate serde_json; extern crate tar; extern crate tempdir; extern crate term; @@ -49,6 +52,7 @@ fn _process(t: &OsStr) -> cargo::util::ProcessBuilder { .env("CARGO_HOME", support::paths::home().join(".cargo")) .env_remove("RUSTC") .env_remove("RUSTFLAGS") + .env_remove("CARGO_INCREMENTAL") .env_remove("XDG_CONFIG_HOME") // see #2345 .env("GIT_CONFIG_NOSYSTEM", "1") // keep trying to sandbox ourselves .env_remove("CARGO_TARGET_DIR") // we assume 'target' diff --git a/tests/cargotest/support/mod.rs b/tests/cargotest/support/mod.rs index ecc3e017de6..88b5c396437 100644 --- a/tests/cargotest/support/mod.rs +++ b/tests/cargotest/support/mod.rs @@ -11,7 +11,7 @@ use std::process::Output; use std::str; use std::usize; -use rustc_serialize::json::Json; +use serde_json::{self, Value}; use url::Url; use hamcrest as ham; use cargo::util::ProcessBuilder; @@ -335,7 +335,7 @@ pub struct Execs { expect_stderr_contains: Vec, expect_stdout_not_contains: Vec, expect_stderr_not_contains: Vec, - expect_json: Option>, + expect_json: Option>, } impl Execs { @@ -376,7 +376,7 @@ impl Execs { pub fn with_json(mut self, expected: &str) -> Execs { self.expect_json = Some(expected.split("\n\n").map(|obj| { - Json::from_str(obj).unwrap() + obj.parse().unwrap() }).collect()); self } @@ -500,8 +500,8 @@ impl Execs { } } - fn match_json(&self, expected: &Json, line: &str) -> ham::MatchResult { - let actual = match Json::from_str(line) { + fn match_json(&self, expected: &Value, line: &str) -> ham::MatchResult { + let actual = match line.parse() { Err(e) => return Err(format!("invalid json, {}:\n`{}`", e, line)), Ok(actual) => actual, }; @@ -509,8 +509,10 @@ impl Execs { match find_mismatch(expected, &actual) { Some((expected_part, actual_part)) => Err(format!( "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n", - expected.pretty(), actual.pretty(), - expected_part.pretty(), actual_part.pretty() + serde_json::to_string_pretty(expected).unwrap(), + serde_json::to_string_pretty(&actual).unwrap(), + serde_json::to_string_pretty(expected_part).unwrap(), + serde_json::to_string_pretty(actual_part).unwrap(), )), None => Ok(()), } @@ -583,32 +585,42 @@ fn lines_match_works() { } // Compares JSON object for approximate equality. -// You can use `[..]` wildcard in strings (useful for OS dependent things such as paths). -// You can use a `"{...}"` string literal as a wildcard for arbitrary nested JSON (useful -// for parts of object emitted by other programs (e.g. rustc) rather than Cargo itself). -// Arrays are sorted before comparison. -fn find_mismatch<'a>(expected: &'a Json, actual: &'a Json) -> Option<(&'a Json, &'a Json)> { - use rustc_serialize::json::Json::*; +// You can use `[..]` wildcard in strings (useful for OS dependent things such +// as paths). You can use a `"{...}"` string literal as a wildcard for +// arbitrary nested JSON (useful for parts of object emitted by other programs +// (e.g. rustc) rather than Cargo itself). Arrays are sorted before comparison. +fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) + -> Option<(&'a Value, &'a Value)> { + use serde_json::Value::*; match (expected, actual) { - (&I64(l), &I64(r)) if l == r => None, - (&F64(l), &F64(r)) if l == r => None, - (&U64(l), &U64(r)) if l == r => None, - (&Boolean(l), &Boolean(r)) if l == r => None, + (&Number(ref l), &Number(ref r)) if l == r => None, + (&Bool(l), &Bool(r)) if l == r => None, (&String(ref l), &String(ref r)) if lines_match(l, r) => None, (&Array(ref l), &Array(ref r)) => { if l.len() != r.len() { return Some((expected, actual)); } - fn sorted(xs: &Vec) -> Vec<&Json> { - let mut result = xs.iter().collect::>(); - result.sort_by(|x, y| x.partial_cmp(y).expect("JSON spec does not allow NaNs")); - result - } + let mut l = l.iter().collect::>(); + let mut r = r.iter().collect::>(); - sorted(l).iter().zip(sorted(r)) - .filter_map(|(l, r)| find_mismatch(l, r)) - .nth(0) + l.retain(|l| { + match r.iter().position(|r| find_mismatch(l, r).is_none()) { + Some(i) => { + r.remove(i); + false + } + None => true + } + }); + + if l.len() > 0 { + assert!(r.len() > 0); + Some((&l[0], &r[0])) + } else { + assert!(r.len() == 0); + None + } } (&Object(ref l), &Object(ref r)) => { let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k)); diff --git a/tests/cargotest/support/registry.rs b/tests/cargotest/support/registry.rs index a57dfa26327..3eae9432992 100644 --- a/tests/cargotest/support/registry.rs +++ b/tests/cargotest/support/registry.rs @@ -7,7 +7,6 @@ use flate2::Compression::Default; use flate2::write::GzEncoder; use git2; use rustc_serialize::hex::ToHex; -use rustc_serialize::json::ToJson; use tar::{Builder, Header}; use url::Url; @@ -137,29 +136,29 @@ impl Package { // Figure out what we're going to write into the index let deps = self.deps.iter().map(|dep| { - let mut map = HashMap::new(); - map.insert("name".to_string(), dep.name.to_json()); - map.insert("req".to_string(), dep.vers.to_json()); - map.insert("features".to_string(), dep.features.to_json()); - map.insert("default_features".to_string(), true.to_json()); - map.insert("target".to_string(), dep.target.to_json()); - map.insert("optional".to_string(), false.to_json()); - map.insert("kind".to_string(), dep.kind.to_json()); - map + json!({ + "name": dep.name, + "req": dep.vers, + "features": dep.features, + "default_features": true, + "target": dep.target, + "optional": false, + "kind": dep.kind, + }) }).collect::>(); let cksum = { let mut c = Vec::new(); t!(t!(File::open(&self.archive_dst())).read_to_end(&mut c)); cksum(&c) }; - let mut dep = HashMap::new(); - dep.insert("name".to_string(), self.name.to_json()); - dep.insert("vers".to_string(), self.vers.to_json()); - dep.insert("deps".to_string(), deps.to_json()); - dep.insert("cksum".to_string(), cksum.to_json()); - dep.insert("features".to_string(), self.features.to_json()); - dep.insert("yanked".to_string(), self.yanked.to_json()); - let line = dep.to_json().to_string(); + let line = json!({ + "name": self.name, + "vers": self.vers, + "deps": deps, + "cksum": cksum, + "features": self.features, + "yanked": self.yanked, + }).to_string(); let file = match self.name.len() { 1 => format!("1/{}", self.name), diff --git a/tests/registry.rs b/tests/registry.rs index c84d28cdd6b..1a60826cd2f 100644 --- a/tests/registry.rs +++ b/tests/registry.rs @@ -1317,17 +1317,17 @@ fn old_version_req_upstream() { p.build(); Package::new("remote", "0.3.0") - .file("Cargo.toml", r#" - [project] + .file("Cargo.toml", r#" + [project] name = "remote" version = "0.3.0" authors = [] [dependencies] bar = "0.2*" - "#) + "#) .file("src/lib.rs", "") - .publish(); + .publish(); Package::new("bar", "0.2.0").publish(); assert_that(p.cargo("build"), @@ -1356,17 +1356,17 @@ fn toml_lies_but_index_is_truth() { Package::new("foo", "0.2.0").publish(); Package::new("bar", "0.3.0") .dep("foo", "0.2.0") - .file("Cargo.toml", r#" - [project] + .file("Cargo.toml", r#" + [project] name = "bar" version = "0.3.0" authors = [] [dependencies] foo = "0.1.0" - "#) + "#) .file("src/lib.rs", "extern crate foo;") - .publish(); + .publish(); let p = project("foo") .file("Cargo.toml", r#"