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#[derive(Clone, Debug, Default)]
39pub struct Link {
40 pub href: Uri,
42
43 pub meta: Map,
50
51 _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}