From 24471eef9bbe7c96e828032b6bf09ed3bebf2551 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Wed, 6 Jul 2016 02:29:38 +0100 Subject: [PATCH] Use serde for json serialization. --- Cargo.lock | 63 ++++++++++++++++++++++++++++++++++ Cargo.toml | 7 +++- README.md | 2 +- build.rs | 4 ++- src/apresolve.rs | 6 ++-- src/authentication/facebook.rs | 4 +-- src/authentication/mod.rs | 62 ++++++++++++++++++--------------- src/lib.rs | 5 ++- 8 files changed, 116 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f06dd35a..81565f00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,10 @@ dependencies = [ "rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_macros 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)", "shannon 0.1.1 (git+https://github.com/plietar/rust-shannon)", "tempfile 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", @@ -209,6 +213,11 @@ dependencies = [ "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itoa" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "json_macros" version = "0.3.1" @@ -530,6 +539,14 @@ dependencies = [ "syntex_syntax 0.37.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quasi_macros" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quasi_codegen 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quine-mc_cluskey" version = "0.2.2" @@ -609,6 +626,52 @@ dependencies = [ "nom 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_codegen" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aster 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_codegen 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_macros 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen_internals 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.37.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.37.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_codegen_internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_errors 0.37.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.37.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_macros" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_codegen 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "shannon" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index e0cc1ef3..dfb1998c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,9 @@ rand = "~0.3.13" rpassword = "~0.2.2" rust-crypto = "~0.2.34" rustc-serialize = "~0.3.16" +serde = "0.7" +serde_json = "0.7" +serde_macros = { version = "0.7", optional = true } tempfile = "~2.1.3" time = "~0.1.34" url = "~0.5.0" @@ -57,10 +60,12 @@ openssl = { version = "0.7", optional = true } vergen = "~0.1.0" protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros" } json_macros = { git = "https://github.com/plietar/json_macros" } +serde_codegen = { version = "0.7", optional = true } [features] discovery = ["dns-sd"] -with-syntex = ["protobuf_macros/with-syntex", "json_macros/with-syntex"] +with-syntex = ["serde_codegen", "protobuf_macros/with-syntex", "json_macros/with-syntex"] +nightly = ["serde_macros"] with-tremor = ["tremor"] facebook = ["hyper/ssl", "openssl"] portaudio-backend = ["portaudio"] diff --git a/README.md b/README.md index 794b7612..701a29f0 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ The following backends are currently available : ## Development When developing *librespot*, it is preferable to use Rust nightly, and build it using the following : ```shell -cargo build --no-default-features --features portaudio-backend +cargo build --no-default-features --features "nightly portaudio-backend" ``` This produces better compilation error messages than with the default configuration. diff --git a/build.rs b/build.rs index 91bf34e1..ee5a4396 100644 --- a/build.rs +++ b/build.rs @@ -4,6 +4,7 @@ extern crate vergen; fn codegen() { extern crate json_macros; extern crate protobuf_macros; + extern crate serde_codegen; use std::env; use std::path::PathBuf; @@ -11,7 +12,8 @@ fn codegen() { let out = PathBuf::from(env::var("OUT_DIR").unwrap()); json_macros::expand("src/lib.in.rs", &out.join("lib.tmp0.rs")).unwrap(); - protobuf_macros::expand(&out.join("lib.tmp0.rs"), &out.join("lib.rs")).unwrap(); + serde_codegen::expand(&out.join("lib.tmp0.rs"), &out.join("lib.tmp1.rs")).unwrap(); + protobuf_macros::expand(&out.join("lib.tmp1.rs"), &out.join("lib.rs")).unwrap(); } #[cfg(not(feature = "with-syntex"))] diff --git a/src/apresolve.rs b/src/apresolve.rs index ca01a066..52b2adab 100644 --- a/src/apresolve.rs +++ b/src/apresolve.rs @@ -2,9 +2,9 @@ const APRESOLVE_ENDPOINT : &'static str = "http://apresolve.spotify.com/"; use hyper; use std::io::Read; -use rustc_serialize::json; +use serde_json; -#[derive(RustcDecodable)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct APResolveData { ap_list: Vec } @@ -16,7 +16,7 @@ pub fn apresolve() -> Result, ()> { let mut data = String::new(); response.read_to_string(&mut data).unwrap(); - let data : APResolveData = json::decode(&data).unwrap(); + let data : APResolveData = serde_json::from_str(&data).unwrap(); Ok(data.ap_list) } diff --git a/src/authentication/facebook.rs b/src/authentication/facebook.rs index a06f6963..c50098d5 100644 --- a/src/authentication/facebook.rs +++ b/src/authentication/facebook.rs @@ -5,7 +5,7 @@ use hyper::server::Response; use hyper::uri::RequestUri; use hyper::header::AccessControlAllowOrigin; use rand::{self, Rng}; -use rustc_serialize::json; +use serde_json; use std::collections::BTreeMap; use std::io::Read; use std::sync::{mpsc, Mutex}; @@ -63,7 +63,7 @@ fn facebook_get_me_id(token: &str) -> Result { let mut body = String::new(); response.read_to_string(&mut body).unwrap(); - let mut result : BTreeMap = json::decode(&body).unwrap(); + let mut result : BTreeMap = serde_json::from_str(&body).unwrap(); Ok(result.remove("id").unwrap()) } diff --git a/src/authentication/mod.rs b/src/authentication/mod.rs index 84bc8231..b8edc2a4 100644 --- a/src/authentication/mod.rs +++ b/src/authentication/mod.rs @@ -6,27 +6,27 @@ use crypto::hmac::Hmac; use crypto::pbkdf2::pbkdf2; use crypto::sha1::Sha1; use protobuf::ProtobufEnum; +use serde; +use serde_json; use std::io::{self, Read, Write}; use std::fs::File; use std::path::Path; use rustc_serialize::base64::{self, FromBase64, ToBase64}; -use rustc_serialize::json; use protocol::authentication::AuthenticationType; #[derive(Debug, Clone)] +#[derive(Serialize, Deserialize)] pub struct Credentials { pub username: String, - pub auth_type: AuthenticationType, - pub auth_data: Vec, -} -#[derive(Debug, Clone)] -#[derive(RustcDecodable, RustcEncodable)] -struct StoredCredentials { - pub username: String, - pub auth_type: i32, - pub auth_data: String, + #[serde(serialize_with="serialize_protobuf_enum")] + #[serde(deserialize_with="deserialize_protobuf_enum")] + pub auth_type: AuthenticationType, + + #[serde(serialize_with="serialize_base64")] + #[serde(deserialize_with="deserialize_base64")] + pub auth_data: Vec, } impl Credentials { @@ -124,7 +124,7 @@ impl Credentials { let mut contents = String::new(); reader.read_to_string(&mut contents).unwrap(); - json::decode::(&contents).unwrap().into() + serde_json::from_str(&contents).unwrap() } pub fn from_file>(path: P) -> Option { @@ -132,7 +132,7 @@ impl Credentials { } pub fn save_to_writer(&self, writer: &mut W) { - let contents = json::encode::(&self.clone().into()).unwrap(); + let contents = serde_json::to_string(&self.clone()).unwrap(); writer.write_all(contents.as_bytes()).unwrap(); } @@ -142,24 +142,30 @@ impl Credentials { } } -impl From for StoredCredentials { - fn from(credentials: Credentials) -> StoredCredentials { - StoredCredentials { - username: credentials.username, - auth_type: credentials.auth_type.value(), - auth_data: credentials.auth_data.to_base64(base64::STANDARD), - } - } +fn serialize_protobuf_enum(v: &T, ser: &mut S) -> Result<(), S::Error> + where T: ProtobufEnum, S: serde::Serializer { + + serde::Serialize::serialize(&v.value(), ser) } -impl From for Credentials { - fn from(credentials: StoredCredentials) -> Credentials { - Credentials { - username: credentials.username, - auth_type: AuthenticationType::from_i32(credentials.auth_type).unwrap(), - auth_data: credentials.auth_data.from_base64().unwrap(), - } - } +fn deserialize_protobuf_enum(de: &mut D) -> Result + where T: ProtobufEnum, D: serde::Deserializer { + + let v : i32 = try!(serde::Deserialize::deserialize(de)); + T::from_i32(v).ok_or(serde::Error::invalid_value("Invalid enum value")) +} + +fn serialize_base64(v: &T, ser: &mut S) -> Result<(), S::Error> + where T: AsRef<[u8]>, S: serde::Serializer { + + serde::Serialize::serialize(&v.as_ref().to_base64(base64::STANDARD), ser) +} + +fn deserialize_base64(de: &mut D) -> Result, D::Error> + where D: serde::Deserializer { + + let v : String = try!(serde::Deserialize::deserialize(de)); + v.from_base64().map_err(|e| serde::Error::custom(e.to_string())) } #[cfg(feature = "discovery")] diff --git a/src/lib.rs b/src/lib.rs index fcb4b408..4e205f10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,9 @@ #![crate_name = "librespot"] -#![cfg_attr(not(feature = "with-syntex"), feature(plugin))] +#![cfg_attr(not(feature = "with-syntex"), feature(plugin, custom_derive))] #![cfg_attr(not(feature = "with-syntex"), plugin(protobuf_macros))] #![cfg_attr(not(feature = "with-syntex"), plugin(json_macros))] +#![cfg_attr(not(feature = "with-syntex"), plugin(serde_macros))] #![cfg_attr(feature="clippy", feature(plugin))] #![cfg_attr(feature="clippy", plugin(clippy))] @@ -24,6 +25,8 @@ extern crate shannon; extern crate rand; extern crate rpassword; extern crate rustc_serialize; +extern crate serde; +extern crate serde_json; extern crate time; extern crate tempfile; extern crate url;