json_api/doc/
link.rs

1use std::cmp::{Eq, PartialEq};
2use std::fmt::{self, Display, Formatter};
3use std::hash::{Hash, Hasher};
4use std::ops::Deref;
5use std::str::FromStr;
6
7use http::Uri;
8use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor};
9use serde::ser::{Serialize, SerializeStruct, Serializer};
10
11use error::Error;
12use value::Map;
13
14/// A data structure containing a URL. Can be deserialized from either a string or link
15/// object.
16///
17/// For more information, check out the *[links]* section of the JSON API specification.
18///
19/// # Example
20///
21/// ```
22/// # extern crate json_api;
23/// #
24/// # use json_api::Error;
25/// #
26/// # fn example() -> Result<(), Error> {
27/// use json_api::doc::Link;
28/// "https://rust-lang.org".parse::<Link>()?;
29/// # Ok(())
30/// # }
31/// #
32/// # fn main() {
33/// # example().unwrap();
34/// # }
35/// ```
36///
37/// [links]: https://goo.gl/E4E6Vt
38#[derive(Clone, Debug, Default)]
39pub struct Link {
40    /// The link’s URI.
41    pub href: Uri,
42
43    /// Non-standard meta information. If this value of this field is empty, the link
44    /// will be serialized as a string containing the contents of `href`. For more
45    /// information, check out the *[meta information]* section of the JSON API
46    /// specification.
47    ///
48    /// [meta information]: https://goo.gl/LyrGF8
49    pub meta: Map,
50
51    /// Private field for backwards compatibility.
52    _ext: (),
53}
54
55impl Deref for Link {
56    type Target = Uri;
57
58    fn deref(&self) -> &Self::Target {
59        &self.href
60    }
61}
62
63impl Display for Link {
64    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
65        self.href.fmt(f)
66    }
67}
68
69impl Eq for Link {}
70
71impl FromStr for Link {
72    type Err = Error;
73
74    fn from_str(value: &str) -> Result<Self, Self::Err> {
75        Ok(Link {
76            href: value.parse()?,
77            meta: Default::default(),
78            _ext: (),
79        })
80    }
81}
82
83impl Hash for Link {
84    fn hash<H: Hasher>(&self, state: &mut H) {
85        self.href.hash(state)
86    }
87}
88
89impl PartialEq for Link {
90    fn eq(&self, rhs: &Link) -> bool {
91        self.href == rhs.href
92    }
93}
94
95impl PartialEq<Uri> for Link {
96    fn eq(&self, rhs: &Uri) -> bool {
97        self.href == *rhs
98    }
99}
100
101impl<'a> PartialEq<&'a str> for Link {
102    fn eq(&self, other: &&'a str) -> bool {
103        self.href == *other
104    }
105}
106
107impl<'a> PartialEq<Link> for &'a str {
108    fn eq(&self, link: &Link) -> bool {
109        *link == *self
110    }
111}
112
113impl<'de> Deserialize<'de> for Link {
114    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
115    where
116        D: Deserializer<'de>,
117    {
118        #[derive(Deserialize)]
119        #[serde(field_identifier, rename_all = "lowercase")]
120        enum Field {
121            Href,
122            Meta,
123        }
124
125        struct LinkVisitor;
126
127        impl<'de> Visitor<'de> for LinkVisitor {
128            type Value = Link;
129
130            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
131                f.write_str("string or a link object")
132            }
133
134            fn visit_str<E>(self, value: &str) -> Result<Link, E>
135            where
136                E: de::Error,
137            {
138                value.parse().map_err(de::Error::custom)
139            }
140
141            fn visit_map<V>(self, mut map: V) -> Result<Link, V::Error>
142            where
143                V: MapAccess<'de>,
144            {
145                let mut href = None;
146                let mut meta = None;
147
148                while let Some(key) = map.next_key()? {
149                    match key {
150                        Field::Href if href.is_some() => {
151                            return Err(de::Error::duplicate_field("href"))
152                        }
153                        Field::Meta if meta.is_some() => {
154                            return Err(de::Error::duplicate_field("meta"))
155                        }
156                        Field::Href => {
157                            let next = map.next_value::<String>()?;
158                            href = Some(next.parse().map_err(de::Error::custom)?);
159                        }
160                        Field::Meta => {
161                            meta = Some(map.next_value()?);
162                        }
163                    }
164                }
165
166                Ok(Link {
167                    href: href.ok_or_else(|| de::Error::missing_field("href"))?,
168                    meta: meta.unwrap_or_default(),
169                    _ext: (),
170                })
171            }
172        }
173
174        deserializer.deserialize_any(LinkVisitor)
175    }
176}
177
178impl Serialize for Link {
179    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
180    where
181        S: Serializer,
182    {
183        let href = self.href.to_string();
184        let meta = &self.meta;
185
186        if meta.is_empty() {
187            serializer.serialize_str(&href)
188        } else {
189            let mut state = serializer.serialize_struct("Link", 2)?;
190
191            state.serialize_field("href", &href)?;
192            state.serialize_field("meta", meta)?;
193
194            state.end()
195        }
196    }
197}