1use core::fmt::{self, Display};
2use core::net::IpAddr;
3use core::ops::{Deref, DerefMut};
4
5use serde::de::Error;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8pub use url::{Host, ParseError as UriParseError, Position, Url as Uri};
9
10#[repr(transparent)]
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct RelativeRef(Uri);
13
14impl RelativeRef {
15 const FAKE_SCHEME: &'static str = "base";
16 const FAKE_RELATIVE_HOST: &'static str = ".";
17
18 pub fn parse(input: &str) -> Result<Self, UriParseError> {
19 if input.starts_with('/') {
20 Uri::parse(&format!("{}://{}", Self::FAKE_SCHEME, input)).map(Self)
21 } else {
22 Uri::parse(&format!(
23 "{}://{}/{}",
24 Self::FAKE_SCHEME,
25 Self::FAKE_RELATIVE_HOST,
26 input,
27 ))
28 .map(Self)
29 }
30 }
31
32 pub fn as_str(&self) -> &str {
33 match self.0.domain() {
34 None => &self.0[Position::BeforePath..],
35 Some(".") => self.0[Position::BeforePath..].trim_start_matches('/'),
36 _ => unreachable!(),
37 }
38 }
39
40 pub fn path(&self) -> &str {
41 match self.0.domain() {
42 None => self.0.path(),
43 Some(".") => self.0.path().trim_start_matches('/'),
44 _ => unreachable!(),
45 }
46 }
47
48 pub fn join(&self, input: &str) -> Result<Self, UriParseError> {
49 self.0.join(input).map(Self)
50 }
51
52 pub fn set_ip_host(&mut self, address: IpAddr) {
53 let _ = address;
54 }
55
56 pub fn set_host(&mut self, host: &str) {
57 let _ = host;
58 }
59
60 pub fn authority(&self) -> &str {
61 ""
62 }
63
64 pub fn scheme(&self) -> &str {
65 ""
66 }
67
68 pub fn host(&self) -> Option<Host<&str>> {
69 None
70 }
71
72 pub fn host_str(&self) -> Option<&str> {
73 None
74 }
75
76 pub fn has_host(&self) -> bool {
77 false
78 }
79
80 pub fn domain(&self) -> Option<&str> {
81 None
82 }
83}
84
85impl Deref for RelativeRef {
86 type Target = Uri;
87
88 fn deref(&self) -> &Self::Target {
89 &self.0
90 }
91}
92
93impl DerefMut for RelativeRef {
94 fn deref_mut(&mut self) -> &mut Self::Target {
95 &mut self.0
96 }
97}
98
99impl Display for RelativeRef {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 self.as_str().fmt(f)
102 }
103}
104
105impl Serialize for RelativeRef {
106 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
107 self.as_str().serialize(serializer)
108 }
109}
110
111impl<'de> Deserialize<'de> for RelativeRef {
112 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113 where
114 D: Deserializer<'de>,
115 {
116 let s = String::deserialize(deserializer)?;
117 Self::parse(&s).map_err(D::Error::custom)
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn simple_reflexivity() {
127 let paths = [
128 "abc",
129 "/abc",
130 "abc/def",
134 "abc/def/",
135 "abc/def/*",
136 "abc?q=1#title",
137 ];
138
139 for path in paths {
140 assert_eq!(path, RelativeRef::parse(path).unwrap().to_string());
141 }
142 }
143}