1use crate::{
4 error::{InvalidIri, InvalidUri, IriParseError},
5 parse::find_iri_ref_positions,
6 resolve::resolve,
7 types::{Iri, IriBuf, IriRef, IriRefBuf, Uri, UriBuf, UriRef, UriRefBuf},
8 validate::{
9 validate_authority_body, validate_fragment, validate_iri_ref, validate_path,
10 validate_query, validate_resolved_path, validate_scheme,
11 },
12};
13
14impl IriRefBuf {
15 pub fn set_scheme(&mut self, scheme: Option<&str>) -> Result<(), IriParseError> {
16 if let Some(s) = scheme {
17 validate_scheme(s)?;
18 }
19 rebuild(self, Edit::Scheme(scheme.map(str::to_string)), true)
20 }
21
22 pub fn set_authority(&mut self, authority: Option<&str>) -> Result<(), IriParseError> {
23 if let Some(a) = authority {
24 validate_authority_body(a, true)?;
25 }
26 rebuild(self, Edit::Authority(authority.map(str::to_string)), true)
27 }
28
29 pub fn set_path(&mut self, path: &str) -> Result<(), IriParseError> {
30 validate_path(path, true)?;
31 rebuild(self, Edit::Path(path.to_string()), true)
32 }
33
34 pub fn set_query(&mut self, query: Option<&str>) -> Result<(), IriParseError> {
35 if let Some(q) = query {
36 validate_query(q, true)?;
37 }
38 rebuild(self, Edit::Query(query.map(str::to_string)), true)
39 }
40
41 pub fn set_fragment(&mut self, fragment: Option<&str>) -> Result<(), IriParseError> {
42 if let Some(f) = fragment {
43 validate_fragment(f, true)?;
44 }
45 rebuild(self, Edit::Fragment(fragment.map(str::to_string)), true)
46 }
47
48 pub fn resolve<T: std::ops::Deref<Target = str>>(
49 &mut self,
50 base: &Iri<T>,
51 ) -> Result<(), IriParseError> {
52 let mut out = String::with_capacity(self.as_str().len() + base.as_str().len());
53 let pos = resolve(
54 (base.as_str(), base.positions()),
55 (self.as_str(), self.positions),
56 &mut out,
57 );
58 validate_resolved_path(&out, pos)?;
59 *self = IriRefBuf::from_raw_parts(out, pos);
60 Ok(())
61 }
62
63 pub fn try_into_iri(self) -> Result<IriBuf, InvalidIri<IriRefBuf>> {
64 if self.is_absolute() {
65 let p = self.positions;
66 Ok(Iri::from_raw_parts(self.into_inner(), p))
67 } else {
68 Err(InvalidIri(self))
69 }
70 }
71
72 pub fn as_iri(&self) -> Option<Iri<&str>> {
73 if self.is_absolute() {
74 Some(Iri::from_raw_parts(self.as_str(), self.positions))
75 } else {
76 None
77 }
78 }
79}
80
81impl Default for IriRefBuf {
82 fn default() -> Self {
83 Self::parse_unchecked(String::new())
84 }
85}
86
87impl Default for UriRefBuf {
88 fn default() -> Self {
89 Self::parse_unchecked(String::new())
90 }
91}
92
93impl IriBuf {
94 pub fn set_scheme(&mut self, scheme: &str) -> Result<(), IriParseError> {
95 validate_scheme(scheme)?;
96 let p = self.positions();
97 let iri = std::mem::take(&mut self.0.iri);
98 let mut r = IriRefBuf::from_raw_parts(iri, p);
99 rebuild(&mut r, Edit::Scheme(Some(scheme.to_string())), true)?;
100 *self = Iri::from_raw_parts(r.iri, r.positions);
101 Ok(())
102 }
103
104 pub fn set_authority(&mut self, authority: Option<&str>) -> Result<(), IriParseError> {
105 let p = self.positions();
106 let iri = std::mem::take(&mut self.0.iri);
107 let mut r = IriRefBuf::from_raw_parts(iri, p);
108 r.set_authority(authority)?;
109 *self = Iri::from_raw_parts(r.iri, r.positions);
110 Ok(())
111 }
112
113 pub fn set_path(&mut self, path: &str) -> Result<(), IriParseError> {
114 let p = self.positions();
115 let iri = std::mem::take(&mut self.0.iri);
116 let mut r = IriRefBuf::from_raw_parts(iri, p);
117 r.set_path(path)?;
118 *self = Iri::from_raw_parts(r.iri, r.positions);
119 Ok(())
120 }
121
122 pub fn set_query(&mut self, query: Option<&str>) -> Result<(), IriParseError> {
123 let p = self.positions();
124 let iri = std::mem::take(&mut self.0.iri);
125 let mut r = IriRefBuf::from_raw_parts(iri, p);
126 r.set_query(query)?;
127 *self = Iri::from_raw_parts(r.iri, r.positions);
128 Ok(())
129 }
130
131 pub fn set_fragment(&mut self, fragment: Option<&str>) -> Result<(), IriParseError> {
132 let p = self.positions();
133 let iri = std::mem::take(&mut self.0.iri);
134 let mut r = IriRefBuf::from_raw_parts(iri, p);
135 r.set_fragment(fragment)?;
136 *self = Iri::from_raw_parts(r.iri, r.positions);
137 Ok(())
138 }
139}
140
141impl UriRefBuf {
142 pub fn set_scheme(&mut self, scheme: Option<&str>) -> Result<(), IriParseError> {
143 if let Some(s) = scheme {
144 validate_scheme(s)?;
145 }
146 rebuild_uri(self, Edit::Scheme(scheme.map(str::to_string)))
147 }
148 pub fn set_authority(&mut self, authority: Option<&str>) -> Result<(), IriParseError> {
149 if let Some(a) = authority {
150 validate_authority_body(a, false)?;
151 }
152 rebuild_uri(self, Edit::Authority(authority.map(str::to_string)))
153 }
154 pub fn set_path(&mut self, path: &str) -> Result<(), IriParseError> {
155 validate_path(path, false)?;
156 rebuild_uri(self, Edit::Path(path.to_string()))
157 }
158 pub fn set_query(&mut self, query: Option<&str>) -> Result<(), IriParseError> {
159 if let Some(q) = query {
160 validate_query(q, false)?;
161 }
162 rebuild_uri(self, Edit::Query(query.map(str::to_string)))
163 }
164 pub fn set_fragment(&mut self, fragment: Option<&str>) -> Result<(), IriParseError> {
165 if let Some(f) = fragment {
166 validate_fragment(f, false)?;
167 }
168 rebuild_uri(self, Edit::Fragment(fragment.map(str::to_string)))
169 }
170 pub fn resolve<T: std::ops::Deref<Target = str>>(
171 &mut self,
172 base: &Uri<T>,
173 ) -> Result<(), IriParseError> {
174 let mut out = String::with_capacity(self.as_str().len() + base.as_str().len());
175 let pos = resolve(
176 (base.as_str(), base.positions()),
177 (self.as_str(), self.positions),
178 &mut out,
179 );
180 validate_resolved_path(&out, pos)?;
181 *self = UriRefBuf::from_raw_parts(out, pos);
182 Ok(())
183 }
184
185 pub fn try_into_uri(self) -> Result<UriBuf, InvalidUri<UriRefBuf>> {
186 if self.is_absolute() {
187 let p = self.positions;
188 Ok(Uri::from_raw_parts(self.into_inner(), p))
189 } else {
190 Err(InvalidUri(self))
191 }
192 }
193
194 pub fn as_uri(&self) -> Option<Uri<&str>> {
195 if self.is_absolute() {
196 Some(Uri::from_raw_parts(self.as_str(), self.positions))
197 } else {
198 None
199 }
200 }
201}
202
203impl UriBuf {
204 pub fn set_scheme(&mut self, scheme: &str) -> Result<(), IriParseError> {
205 let p = self.positions();
206 let uri = std::mem::take(&mut self.0.uri);
207 let mut r = UriRefBuf::from_raw_parts(uri, p);
208 r.set_scheme(Some(scheme))?;
209 *self = Uri::from_raw_parts(r.uri, r.positions);
210 Ok(())
211 }
212 pub fn set_authority(&mut self, authority: Option<&str>) -> Result<(), IriParseError> {
213 let p = self.positions();
214 let uri = std::mem::take(&mut self.0.uri);
215 let mut r = UriRefBuf::from_raw_parts(uri, p);
216 r.set_authority(authority)?;
217 *self = Uri::from_raw_parts(r.uri, r.positions);
218 Ok(())
219 }
220 pub fn set_path(&mut self, path: &str) -> Result<(), IriParseError> {
221 let p = self.positions();
222 let uri = std::mem::take(&mut self.0.uri);
223 let mut r = UriRefBuf::from_raw_parts(uri, p);
224 r.set_path(path)?;
225 *self = Uri::from_raw_parts(r.uri, r.positions);
226 Ok(())
227 }
228 pub fn set_query(&mut self, query: Option<&str>) -> Result<(), IriParseError> {
229 let p = self.positions();
230 let uri = std::mem::take(&mut self.0.uri);
231 let mut r = UriRefBuf::from_raw_parts(uri, p);
232 r.set_query(query)?;
233 *self = Uri::from_raw_parts(r.uri, r.positions);
234 Ok(())
235 }
236 pub fn set_fragment(&mut self, fragment: Option<&str>) -> Result<(), IriParseError> {
237 let p = self.positions();
238 let uri = std::mem::take(&mut self.0.uri);
239 let mut r = UriRefBuf::from_raw_parts(uri, p);
240 r.set_fragment(fragment)?;
241 *self = Uri::from_raw_parts(r.uri, r.positions);
242 Ok(())
243 }
244}
245
246enum Edit {
247 Scheme(Option<String>),
248 Authority(Option<String>),
249 Path(String),
250 Query(Option<String>),
251 Fragment(Option<String>),
252}
253
254fn rebuild(buf: &mut IriRefBuf, edit: Edit, is_iri: bool) -> Result<(), IriParseError> {
255 let out = {
256 let s = buf.as_str();
257 let (scheme, authority, path, query, fragment) = destructure(s, buf.positions);
258 let mut out = String::with_capacity(s.len() + 8);
259 match &edit {
260 Edit::Scheme(new) => {
261 write_iri(&mut out, new.as_deref(), authority, path, query, fragment)
262 }
263 Edit::Authority(new) => {
264 write_iri(&mut out, scheme, new.as_deref(), path, query, fragment)
265 }
266 Edit::Path(new) => write_iri(&mut out, scheme, authority, new, query, fragment),
267 Edit::Query(new) => {
268 write_iri(&mut out, scheme, authority, path, new.as_deref(), fragment)
269 }
270 Edit::Fragment(new) => {
271 write_iri(&mut out, scheme, authority, path, query, new.as_deref())
272 }
273 }
274 out
275 };
276 let positions = find_iri_ref_positions(&out);
277 validate_iri_ref(&out, positions, is_iri)?;
278 *buf = IriRef::from_raw_parts(out, positions);
279 Ok(())
280}
281
282fn write_iri(
283 out: &mut String,
284 scheme: Option<&str>,
285 authority: Option<&str>,
286 path: &str,
287 query: Option<&str>,
288 fragment: Option<&str>,
289) {
290 if let Some(s) = scheme {
291 out.push_str(s);
292 out.push(':');
293 }
294 if let Some(a) = authority {
295 out.push_str("//");
296 out.push_str(a);
297 }
298 out.push_str(path);
299 if let Some(q) = query {
300 out.push('?');
301 out.push_str(q);
302 }
303 if let Some(f) = fragment {
304 out.push('#');
305 out.push_str(f);
306 }
307}
308
309fn rebuild_uri(buf: &mut UriRefBuf, edit: Edit) -> Result<(), IriParseError> {
310 let mut tmp: IriRefBuf = IriRef::from_raw_parts(buf.as_str().to_string(), buf.positions);
311 rebuild(&mut tmp, edit, false)?;
312 let p = tmp.positions;
313 *buf = UriRef::from_raw_parts(tmp.iri, p);
314 Ok(())
315}
316
317fn destructure(
318 s: &str,
319 p: crate::parse::Positions,
320) -> (Option<&str>, Option<&str>, &str, Option<&str>, Option<&str>) {
321 let scheme = if p.scheme_end > 0 {
322 Some(&s[..p.scheme_end - 1])
323 } else {
324 None
325 };
326 let authority = if p.authority_end > p.scheme_end + 2
327 || (p.authority_end == p.scheme_end + 2
328 && p.scheme_end + 2 <= s.len()
329 && &s[p.scheme_end..p.scheme_end + 2] == "//")
330 {
331 Some(&s[p.scheme_end + 2..p.authority_end])
332 } else {
333 None
334 };
335 let path = &s[p.authority_end..p.path_end];
336 let query = if p.query_end > p.path_end {
337 Some(&s[p.path_end + 1..p.query_end])
338 } else {
339 None
340 };
341 let fragment = if s.len() > p.query_end {
342 Some(&s[p.query_end + 1..])
343 } else {
344 None
345 };
346 (scheme, authority, path, query, fragment)
347}
348