Skip to content

Commit e41a920

Browse files
authored
Merge pull request #279 from maximih/master
Add impl Serialize and Deserialize for Option<Url>
2 parents c7254e5 + 599b97d commit e41a920

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

url_serde/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
name = "url_serde"
4-
version = "0.1.1"
4+
version = "0.1.2"
55
authors = ["The rust-url developers"]
66

77
description = "Serde support for URL types"
@@ -17,6 +17,7 @@ url = "1.0.0"
1717

1818
[dev-dependencies]
1919
serde_json = "0.9.0"
20+
serde_derive = "0.9.0"
2021

2122
[lib]
2223
doctest = false

url_serde/src/lib.rs

+123-1
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,12 @@ ipc::channel::<Serde<Url>>()
5151
extern crate serde;
5252
extern crate url;
5353

54+
#[cfg(test)]
55+
#[macro_use]
56+
extern crate serde_derive;
57+
5458
use std::cmp::PartialEq;
5559
use std::fmt;
56-
use std::hash::{Hash, Hasher};
5760
use std::ops::{Deref, DerefMut};
5861
use std::error::Error;
5962
use serde::{Deserialize, Serialize, Serializer, Deserializer};
@@ -95,6 +98,18 @@ impl<'a> Serialize for Ser<'a, Url> {
9598
}
9699

97100

101+
/// Serializes this Option<URL> into a `serde` stream.
102+
impl<'a> Serialize for Ser<'a, Option<Url>> {
103+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
104+
if let Some(url) = self.0.as_ref() {
105+
serializer.serialize_some(url.as_str())
106+
} else {
107+
serializer.serialize_none()
108+
}
109+
}
110+
}
111+
112+
98113
/// Deserialises a `T` value with a given deserializer.
99114
///
100115
/// This is useful to deserialize Url types used in structure fields or
@@ -135,6 +150,21 @@ impl Deserialize for De<Url> {
135150
}
136151

137152

153+
/// Deserializes this Option<URL> from a `serde` stream.
154+
impl Deserialize for De<Option<Url>> {
155+
fn deserialize<D>(deserializer: D) -> Result<De<Option<Url>>, D::Error> where D: Deserializer {
156+
let option_representation: Option<String> = Deserialize::deserialize(deserializer)?;
157+
if let Some(s) = option_representation {
158+
return Url::parse(&s)
159+
.map(Some)
160+
.map(De)
161+
.map_err(|err| {serde::de::Error::custom(err.description())});
162+
}
163+
Ok(De(None))
164+
165+
}
166+
}
167+
138168
/// A convenience wrapper to be used as a type parameter, for example when
139169
/// a `Vec<T>` or an `HashMap<K, V>` need to be passed to serde.
140170
#[derive(Clone, Eq, Hash, PartialEq)]
@@ -217,3 +247,95 @@ fn test_ser_de_url() {
217247
let new_url: Url = serde_json::from_str(&s).map(De::into_inner).unwrap();
218248
assert_eq!(url, new_url);
219249
}
250+
251+
252+
#[test]
253+
fn test_derive_deserialize_with_for_url() {
254+
extern crate serde_json;
255+
256+
#[derive(Deserialize, Debug, Eq, PartialEq)]
257+
struct Test {
258+
#[serde(deserialize_with = "deserialize", rename = "_url_")]
259+
url: Url
260+
}
261+
262+
let url_str = "http://www.test.com/foo/bar?$param=bazz";
263+
264+
let expected = Test {
265+
url: Url::parse(url_str).unwrap()
266+
};
267+
let json_string = format!(r#"{{"_url_": "{}"}}"#, url_str);
268+
let got: Test = serde_json::from_str(&json_string).unwrap();
269+
assert_eq!(expected, got);
270+
271+
}
272+
273+
#[test]
274+
fn test_derive_deserialize_with_for_option_url() {
275+
extern crate serde_json;
276+
277+
#[derive(Deserialize, Debug, Eq, PartialEq)]
278+
struct Test {
279+
#[serde(deserialize_with = "deserialize", rename = "_url_")]
280+
url: Option<Url>
281+
}
282+
283+
let url_str = "http://www.test.com/foo/bar?$param=bazz";
284+
285+
let expected = Test {
286+
url: Some(Url::parse(url_str).unwrap())
287+
};
288+
let json_string = format!(r#"{{"_url_": "{}"}}"#, url_str);
289+
let got: Test = serde_json::from_str(&json_string).unwrap();
290+
assert_eq!(expected, got);
291+
292+
let expected = Test {
293+
url: None
294+
};
295+
let json_string = r#"{"_url_": null}"#;
296+
let got: Test = serde_json::from_str(&json_string).unwrap();
297+
assert_eq!(expected, got);
298+
}
299+
300+
301+
#[test]
302+
fn test_derive_serialize_with_for_url() {
303+
extern crate serde_json;
304+
305+
#[derive(Serialize, Debug, Eq, PartialEq)]
306+
struct Test {
307+
#[serde(serialize_with = "serialize", rename = "_url_")]
308+
url: Url
309+
}
310+
311+
let url_str = "http://www.test.com/foo/bar?$param=bazz";
312+
313+
let expected = format!(r#"{{"_url_":"{}"}}"#, url_str);
314+
let input = Test {url: Url::parse(url_str).unwrap()};
315+
let got = serde_json::to_string(&input).unwrap();
316+
assert_eq!(expected, got);
317+
}
318+
319+
320+
#[test]
321+
fn test_derive_serialize_with_for_option_url() {
322+
extern crate serde_json;
323+
324+
#[derive(Serialize, Debug, Eq, PartialEq)]
325+
struct Test {
326+
#[serde(serialize_with = "serialize", rename = "_url_")]
327+
url: Option<Url>
328+
}
329+
330+
let url_str = "http://www.test.com/foo/bar?$param=bazz";
331+
332+
let expected = format!(r#"{{"_url_":"{}"}}"#, url_str);
333+
let input = Test {url: Some(Url::parse(url_str).unwrap())};
334+
let got = serde_json::to_string(&input).unwrap();
335+
assert_eq!(expected, got);
336+
337+
let expected = format!(r#"{{"_url_":null}}"#);
338+
let input = Test {url: None};
339+
let got = serde_json::to_string(&input).unwrap();
340+
assert_eq!(expected, got);
341+
}

0 commit comments

Comments
 (0)