فهرست منبع

Merge pull request #279 from maximih/master

Add impl Serialize and Deserialize for Option<Url>
Simon Sapin 9 سال پیش
والد
کامیت
e41a920289
2فایلهای تغییر یافته به همراه125 افزوده شده و 2 حذف شده
  1. 2 1
      url_serde/Cargo.toml
  2. 123 1
      url_serde/src/lib.rs

+ 2 - 1
url_serde/Cargo.toml

@@ -1,7 +1,7 @@
 [package]
 
 name = "url_serde"
-version = "0.1.1"
+version = "0.1.2"
 authors = ["The rust-url developers"]
 
 description = "Serde support for URL types"
@@ -17,6 +17,7 @@ url = "1.0.0"
 
 [dev-dependencies]
 serde_json = "0.9.0"
+serde_derive = "0.9.0"
 
 [lib]
 doctest = false

+ 123 - 1
url_serde/src/lib.rs

@@ -51,9 +51,12 @@ ipc::channel::<Serde<Url>>()
 extern crate serde;
 extern crate url;
 
+#[cfg(test)]
+#[macro_use]
+extern crate serde_derive;
+
 use std::cmp::PartialEq;
 use std::fmt;
-use std::hash::{Hash, Hasher};
 use std::ops::{Deref, DerefMut};
 use std::error::Error;
 use serde::{Deserialize, Serialize, Serializer, Deserializer};
@@ -95,6 +98,18 @@ impl<'a> Serialize for Ser<'a, Url> {
 }
 
 
+/// Serializes this Option<URL> into a `serde` stream.
+impl<'a> Serialize for Ser<'a, Option<Url>> {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+        if let Some(url) = self.0.as_ref() {
+            serializer.serialize_some(url.as_str())
+        } else {
+            serializer.serialize_none()
+        }
+    }
+}
+
+
 /// Deserialises a `T` value with a given deserializer.
 ///
 /// This is useful to deserialize Url types used in structure fields or
@@ -135,6 +150,21 @@ impl Deserialize for De<Url> {
 }
 
 
+/// Deserializes this Option<URL> from a `serde` stream.
+impl Deserialize for De<Option<Url>> {
+    fn deserialize<D>(deserializer: D) -> Result<De<Option<Url>>, D::Error> where D: Deserializer {
+        let option_representation: Option<String> = Deserialize::deserialize(deserializer)?;
+        if let Some(s) = option_representation {
+            return Url::parse(&s)
+                .map(Some)
+                .map(De)
+                .map_err(|err| {serde::de::Error::custom(err.description())});
+        }
+        Ok(De(None))
+
+    }
+}
+
 /// A convenience wrapper to be used as a type parameter, for example when
 /// a `Vec<T>` or an `HashMap<K, V>` need to be passed to serde.
 #[derive(Clone, Eq, Hash, PartialEq)]
@@ -217,3 +247,95 @@ fn test_ser_de_url() {
     let new_url: Url = serde_json::from_str(&s).map(De::into_inner).unwrap();
     assert_eq!(url, new_url);
 }
+
+
+#[test]
+fn test_derive_deserialize_with_for_url() {
+    extern crate serde_json;
+
+    #[derive(Deserialize, Debug, Eq, PartialEq)]
+    struct Test {
+        #[serde(deserialize_with = "deserialize", rename = "_url_")]
+        url: Url
+    }
+
+    let url_str = "http://www.test.com/foo/bar?$param=bazz";
+
+    let expected = Test {
+        url: Url::parse(url_str).unwrap()
+    };
+    let json_string = format!(r#"{{"_url_": "{}"}}"#, url_str);
+    let got: Test = serde_json::from_str(&json_string).unwrap();
+    assert_eq!(expected, got);
+
+}
+
+#[test]
+fn test_derive_deserialize_with_for_option_url() {
+    extern crate serde_json;
+
+    #[derive(Deserialize, Debug, Eq, PartialEq)]
+    struct Test {
+        #[serde(deserialize_with = "deserialize", rename = "_url_")]
+        url: Option<Url>
+    }
+
+    let url_str = "http://www.test.com/foo/bar?$param=bazz";
+
+    let expected = Test {
+        url: Some(Url::parse(url_str).unwrap())
+    };
+    let json_string = format!(r#"{{"_url_": "{}"}}"#, url_str);
+    let got: Test = serde_json::from_str(&json_string).unwrap();
+    assert_eq!(expected, got);
+
+    let expected = Test {
+        url: None
+    };
+    let json_string = r#"{"_url_": null}"#;
+    let got: Test = serde_json::from_str(&json_string).unwrap();
+    assert_eq!(expected, got);
+}
+
+
+#[test]
+fn test_derive_serialize_with_for_url() {
+    extern crate serde_json;
+
+    #[derive(Serialize, Debug, Eq, PartialEq)]
+    struct Test {
+        #[serde(serialize_with = "serialize", rename = "_url_")]
+        url: Url
+    }
+
+    let url_str = "http://www.test.com/foo/bar?$param=bazz";
+
+    let expected = format!(r#"{{"_url_":"{}"}}"#, url_str);
+    let input = Test {url: Url::parse(url_str).unwrap()};
+    let got = serde_json::to_string(&input).unwrap();
+    assert_eq!(expected, got);
+}
+
+
+#[test]
+fn test_derive_serialize_with_for_option_url() {
+    extern crate serde_json;
+
+    #[derive(Serialize, Debug, Eq, PartialEq)]
+    struct Test {
+        #[serde(serialize_with = "serialize", rename = "_url_")]
+        url: Option<Url>
+    }
+
+    let url_str = "http://www.test.com/foo/bar?$param=bazz";
+
+    let expected = format!(r#"{{"_url_":"{}"}}"#, url_str);
+    let input = Test {url: Some(Url::parse(url_str).unwrap())};
+    let got = serde_json::to_string(&input).unwrap();
+    assert_eq!(expected, got);
+
+    let expected = format!(r#"{{"_url_":null}}"#);
+    let input = Test {url: None};
+    let got = serde_json::to_string(&input).unwrap();
+    assert_eq!(expected, got);
+}