| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- // Copyright 2017 The rust-url developers.
- //
- // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
- // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
- // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
- // option. This file may not be copied, modified, or distributed
- // except according to those terms.
- /*!
- This crate provides wrappers and convenience functions to make rust-url
- and Serde work hand in hand.
- The supported types are:
- * `url::Url`
- # How do I use a data type with a `Url` member with Serde?
- Use the serde attributes `deserialize_with` and `serialize_with`.
- ```
- #[derive(serde::Serialize, serde::Deserialize)]
- struct MyStruct {
- #[serde(deserialize_with = "url_serde::deserialize",
- serialize_with = "url_serde::serialize")]
- url: Url,
- }
- ```
- # How do I encode a `Url` value with `serde_json::to_string`?
- Use the `Ser` wrapper.
- ```
- serde_json::to_string(&Ser::new(&url))
- ```
- # How do I decode a `Url` value with `serde_json::parse`?
- Use the `De` wrapper.
- ```
- serde_json::from_str(r"http:://www.rust-lang.org").map(De::into_inner)
- ```
- # How do I send `Url` values as part of an IPC channel?
- Use the `Serde` wrapper. It implements `Deref` and `DerefMut` for convenience.
- ```
- ipc::channel::<Serde<Url>>()
- ```
- */
- #![deny(missing_docs)]
- #![deny(unsafe_code)]
- extern crate serde;
- #[cfg(test)] #[macro_use] extern crate serde_derive;
- #[cfg(test)] extern crate serde_json;
- extern crate url;
- use serde::{Deserialize, Serialize, Serializer, Deserializer};
- use std::cmp::PartialEq;
- use std::error::Error;
- use std::fmt;
- use std::io::Write;
- use std::ops::{Deref, DerefMut};
- use std::str;
- use url::{Url, Host};
- /// Serialises `value` with a given serializer.
- ///
- /// This is useful to serialize `rust-url` types used in structure fields or
- /// tuple members with `#[serde(serialize_with = "url_serde::serialize")]`.
- pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
- where S: Serializer, for<'a> Ser<'a, T>: Serialize
- {
- Ser::new(value).serialize(serializer)
- }
- /// A wrapper to serialize `rust-url` types.
- ///
- /// This is useful with functions such as `serde_json::to_string`.
- ///
- /// Values of this type can only be passed to the `serde::Serialize` trait.
- #[derive(Debug)]
- pub struct Ser<'a, T: 'a>(&'a T);
- impl<'a, T> Ser<'a, T> where Ser<'a, T>: Serialize {
- /// Returns a new `Ser` wrapper.
- #[inline(always)]
- pub fn new(value: &'a T) -> Self {
- Ser(value)
- }
- }
- /// Serializes this URL into a `serde` stream.
- impl<'a> Serialize for Ser<'a, Url> {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
- serializer.serialize_str(self.0.as_str())
- }
- }
- /// 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()
- }
- }
- }
- impl<'a, String> Serialize for Ser<'a, Host<String>> where String: AsRef<str> {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
- match *self.0 {
- Host::Domain(ref s) => serializer.serialize_str(s.as_ref()),
- Host::Ipv4(_) | Host::Ipv6(_) => {
- // max("101.102.103.104".len(),
- // "[1000:1002:1003:1004:1005:1006:101.102.103.104]".len())
- const MAX_LEN: usize = 47;
- let mut buffer = [0; MAX_LEN];
- serializer.serialize_str(display_into_buffer(&self.0, &mut buffer))
- }
- }
- }
- }
- /// Like .to_string(), but doesn’t allocate memory for a `String`.
- ///
- /// Panics if `buffer` is too small.
- fn display_into_buffer<'a, T: fmt::Display>(value: &T, buffer: &'a mut [u8]) -> &'a str {
- let remaining_len;
- {
- let mut remaining = &mut *buffer;
- write!(remaining, "{}", value).unwrap();
- remaining_len = remaining.len()
- }
- let written_len = buffer.len() - remaining_len;
- let written = &buffer[..written_len];
- // write! only provides std::fmt::Formatter to Display implementations,
- // which has methods write_str and write_char but no method to write arbitrary bytes.
- // Therefore, `written` is well-formed in UTF-8.
- #[allow(unsafe_code)]
- unsafe {
- str::from_utf8_unchecked(written)
- }
- }
- /// Deserialises a `T` value with a given deserializer.
- ///
- /// This is useful to deserialize Url types used in structure fields or
- /// tuple members with `#[serde(deserialize_with = "url_serde::deserialize")]`.
- pub fn deserialize<T, D>(deserializer: D) -> Result<T, D::Error>
- where D: Deserializer, De<T>: Deserialize
- {
- De::deserialize(deserializer).map(De::into_inner)
- }
- /// A wrapper to deserialize `rust-url` types.
- ///
- /// This is useful with functions such as `serde_json::from_str`.
- ///
- /// Values of this type can only be obtained through
- /// the `serde::Deserialize` trait.
- #[derive(Debug)]
- pub struct De<T>(T);
- impl<T> De<T> where De<T>: serde::Deserialize {
- /// Consumes this wrapper, returning the deserialized value.
- #[inline(always)]
- pub fn into_inner(self) -> T {
- self.0
- }
- }
- /// Deserializes this URL from a `serde` stream.
- impl Deserialize for De<Url> {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer {
- let string_representation: String = Deserialize::deserialize(deserializer)?;
- Url::parse(&string_representation).map(De).map_err(|err| {
- serde::de::Error::custom(err.description())
- })
- }
- }
- /// Deserializes this Option<URL> from a `serde` stream.
- impl Deserialize for De<Option<Url>> {
- fn deserialize<D>(deserializer: D) -> Result<Self, 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))
- }
- }
- impl Deserialize for De<Host> {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer {
- let string_representation: String = Deserialize::deserialize(deserializer)?;
- Host::parse(&string_representation).map(De).map_err(|err| {
- serde::de::Error::custom(err.description())
- })
- }
- }
- /// 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)]
- pub struct Serde<T>(pub T)
- where De<T>: Deserialize, for<'a> Ser<'a, T>: Serialize;
- /// A convenience type alias for Serde<Url>.
- pub type SerdeUrl = Serde<Url>;
- impl<T> Serde<T>
- where De<T>: Deserialize, for<'a> Ser<'a, T>: Serialize
- {
- /// Consumes this wrapper, returning the inner value.
- #[inline(always)]
- pub fn into_inner(self) -> T {
- self.0
- }
- }
- impl<T> fmt::Debug for Serde<T>
- where T: fmt::Debug, De<T>: Deserialize, for<'a> Ser<'a, T>: Serialize
- {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- self.0.fmt(formatter)
- }
- }
- impl<T> Deref for Serde<T>
- where De<T>: Deserialize, for<'a> Ser<'a, T>: Serialize
- {
- type Target = T;
- fn deref(&self) -> &T {
- &self.0
- }
- }
- impl<T> DerefMut for Serde<T>
- where De<T>: Deserialize, for<'a> Ser<'a, T>: Serialize
- {
- fn deref_mut(&mut self) -> &mut T {
- &mut self.0
- }
- }
- impl<T: PartialEq> PartialEq<T> for Serde<T>
- where De<T>: Deserialize, for<'a> Ser<'a, T>: Serialize
- {
- fn eq(&self, other: &T) -> bool {
- self.0 == *other
- }
- }
- impl<T> Deserialize for Serde<T>
- where De<T>: Deserialize, for<'a> Ser<'a, T>: Serialize
- {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where D: Deserializer
- {
- De::deserialize(deserializer).map(De::into_inner).map(Serde)
- }
- }
- impl<T> Serialize for Serde<T>
- where De<T>: Deserialize, for<'a> Ser<'a, T>: Serialize
- {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where S: Serializer
- {
- Ser(&self.0).serialize(serializer)
- }
- }
- #[test]
- fn test_ser_de_url() {
- let url = Url::parse("http://www.test.com/foo/bar?$param=bazz").unwrap();
- let s = serde_json::to_string(&Ser::new(&url)).unwrap();
- 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() {
- #[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() {
- #[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() {
- #[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() {
- #[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);
- }
- #[test]
- fn test_host() {
- for host in &[
- Host::Domain("foo.com".to_owned()),
- Host::Ipv4("127.0.0.1".parse().unwrap()),
- Host::Ipv6("::1".parse().unwrap()),
- ] {
- let json = serde_json::to_string(&Ser(host)).unwrap();
- let de: De<Host> = serde_json::from_str(&json).unwrap();
- assert_eq!(de.into_inner(), *host)
- }
- }
|