1use std::{
2 borrow::{Borrow, Cow},
3 hash::{self, Hash},
4};
5
6use static_regular_grammar::RegularGrammar;
7
8mod authority;
9mod authority_mut;
10mod fragment;
11mod path;
12mod path_mut;
13mod query;
14mod reference;
15
16pub use authority::*;
17pub use authority_mut::*;
18pub use fragment::*;
19pub use path::*;
20pub use path_mut::*;
21pub use query::*;
22pub use reference::*;
23
24use crate::{
25 common::{parse, str_eq, RiBufImpl, RiImpl, RiRefBufImpl, RiRefImpl},
26 uri::InvalidUriRef,
27 InvalidUri, Uri, UriBuf, UriRef, UriRefBuf,
28};
29
30macro_rules! iri_error {
31 ($($(#[$meta:meta])* $variant:ident : $ident:ident),*) => {
32 #[derive(Debug, thiserror::Error)]
33 pub enum IriError<T> {
34 $(
35 $(#[$meta])*
36 $variant(#[from] $ident<T>)
37 ),*
38 }
39
40 $(
41 impl<'a> From<$ident<String>> for IriError<Cow<'a, str>> {
42 fn from($ident(value): $ident<String>) -> Self {
43 Self::$variant($ident(Cow::Owned(value)))
44 }
45 }
46
47 impl<'a> From<$ident<&'a str>> for IriError<Cow<'a, str>> {
48 fn from($ident(value): $ident<&'a str>) -> Self {
49 Self::$variant($ident(Cow::Borrowed(value)))
50 }
51 }
52
53 impl<'a> From<$ident<Vec<u8>>> for IriError<Cow<'a, [u8]>> {
54 fn from($ident(value): $ident<Vec<u8>>) -> Self {
55 Self::$variant($ident(Cow::Owned(value)))
56 }
57 }
58
59 impl<'a> From<$ident<&'a [u8]>> for IriError<Cow<'a, [u8]>> {
60 fn from($ident(value): $ident<&'a [u8]>) -> Self {
61 Self::$variant($ident(Cow::Borrowed(value)))
62 }
63 }
64 )*
65 };
66}
67
68iri_error! {
69 #[error("invalid IRI: {0}")]
70 Iri: InvalidIri,
71
72 #[error("invalid IRI reference: {0}")]
73 Reference: InvalidIriRef,
74
75 #[error("invalid IRI scheme: {0}")]
76 Scheme: InvalidScheme,
77
78 #[error("invalid IRI authority: {0}")]
79 Authority: InvalidAuthority,
80
81 #[error("invalid IRI authority user info: {0}")]
82 UserInfo: InvalidUserInfo,
83
84 #[error("invalid IRI authority host: {0}")]
85 Host: InvalidHost,
86
87 #[error("invalid IRI authority port: {0}")]
88 Port: InvalidPort,
89
90 #[error("invalid IRI path: {0}")]
91 Path: InvalidPath,
92
93 #[error("invalid IRI path segment: {0}")]
94 PathSegment: InvalidSegment,
95
96 #[error("invalid IRI query: {0}")]
97 Query: InvalidQuery,
98
99 #[error("invalid IRI fragment: {0}")]
100 Fragment: InvalidFragment
101}
102
103#[derive(RegularGrammar)]
123#[grammar(
124 file = "src/iri/grammar.abnf",
125 entry_point = "IRI",
126 cache = "automata/iri.aut.cbor"
127)]
128#[grammar(sized(IriBuf, derive(Debug, Display, PartialEq, Eq, PartialOrd, Ord, Hash)))]
129#[cfg_attr(feature = "serde", grammar(serde))]
130#[cfg_attr(feature = "ignore-grammars", grammar(disable))]
131pub struct Iri(str);
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
134pub struct IriParts<'a> {
135 pub scheme: &'a Scheme,
136 pub authority: Option<&'a Authority>,
137 pub path: &'a Path,
138 pub query: Option<&'a Query>,
139 pub fragment: Option<&'a Fragment>,
140}
141
142impl RiRefImpl for Iri {
143 type Authority = Authority;
144 type Path = Path;
145 type Query = Query;
146 type Fragment = Fragment;
147
148 type RiRefBuf = IriRefBuf;
149
150 fn as_bytes(&self) -> &[u8] {
151 self.0.as_bytes()
152 }
153}
154
155impl RiImpl for Iri {}
156
157impl Iri {
158 pub fn parts(&self) -> IriParts {
159 let bytes = self.as_bytes();
160 let ranges = parse::parts(bytes, 0);
161
162 IriParts {
163 scheme: unsafe { Scheme::new_unchecked(&bytes[ranges.scheme]) },
164 authority: ranges
165 .authority
166 .map(|r| unsafe { Authority::new_unchecked(&self.0[r]) }),
167 path: unsafe { Path::new_unchecked(&self.0[ranges.path]) },
168 query: ranges
169 .query
170 .map(|r| unsafe { Query::new_unchecked(&self.0[r]) }),
171 fragment: ranges
172 .fragment
173 .map(|r| unsafe { Fragment::new_unchecked(&self.0[r]) }),
174 }
175 }
176
177 pub fn as_iri_ref(&self) -> &IriRef {
181 unsafe { IriRef::new_unchecked(&self.0) }
182 }
183
184 pub fn as_uri(&self) -> Option<&Uri> {
186 Uri::new(self.as_bytes()).ok()
187 }
188
189 pub fn as_uri_ref(&self) -> Option<&UriRef> {
191 UriRef::new(self.as_bytes()).ok()
192 }
193
194 #[inline]
196 pub fn scheme(&self) -> &Scheme {
197 RiImpl::scheme(self)
198 }
199
200 pub fn authority(&self) -> Option<&Authority> {
202 RiRefImpl::authority(self)
203 }
204
205 pub fn path(&self) -> &Path {
207 RiRefImpl::path(self)
208 }
209
210 pub fn query(&self) -> Option<&Query> {
211 RiRefImpl::query(self)
212 }
213
214 pub fn fragment(&self) -> Option<&Fragment> {
215 RiRefImpl::fragment(self)
216 }
217
218 pub fn relative_to(&self, other: &(impl ?Sized + AsRef<IriRef>)) -> IriRefBuf {
232 self.as_iri_ref().relative_to(other)
233 }
234
235 #[inline]
244 pub fn suffix(
245 &self,
246 prefix: &(impl ?Sized + AsRef<Iri>),
247 ) -> Option<(PathBuf, Option<&Query>, Option<&Fragment>)> {
248 RiRefImpl::suffix(self, prefix.as_ref())
249 }
250
251 #[inline]
262 pub fn base(&self) -> &Self {
263 unsafe { Self::new_unchecked(std::str::from_utf8_unchecked(RiRefImpl::base(self))) }
264 }
265}
266
267impl AsRef<IriRef> for Iri {
268 fn as_ref(&self) -> &IriRef {
269 self.as_iri_ref()
270 }
271}
272
273impl Borrow<IriRef> for Iri {
274 fn borrow(&self) -> &IriRef {
275 self.as_iri_ref()
276 }
277}
278
279impl<'a> From<&'a Iri> for &'a IriRef {
280 fn from(value: &'a Iri) -> Self {
281 value.as_iri_ref()
282 }
283}
284
285impl<'a> TryFrom<&'a Iri> for &'a Uri {
286 type Error = InvalidUri<&'a Iri>;
287
288 fn try_from(value: &'a Iri) -> Result<Self, Self::Error> {
289 value.as_uri().ok_or(InvalidUri(value))
290 }
291}
292
293impl<'a> TryFrom<&'a Iri> for &'a UriRef {
294 type Error = InvalidUriRef<&'a Iri>;
295
296 fn try_from(value: &'a Iri) -> Result<Self, Self::Error> {
297 value.as_uri_ref().ok_or(InvalidUriRef(value))
298 }
299}
300
301str_eq!(Iri);
302
303impl PartialEq for Iri {
304 fn eq(&self, other: &Self) -> bool {
305 self.parts() == other.parts()
306 }
307}
308
309impl<'a> PartialEq<&'a Iri> for Iri {
310 fn eq(&self, other: &&'a Self) -> bool {
311 *self == **other
312 }
313}
314
315impl PartialEq<IriBuf> for Iri {
316 fn eq(&self, other: &IriBuf) -> bool {
317 *self == *other.as_iri()
318 }
319}
320
321impl PartialEq<IriRef> for Iri {
322 fn eq(&self, other: &IriRef) -> bool {
323 *self.as_iri_ref() == *other
324 }
325}
326
327impl<'a> PartialEq<&'a IriRef> for Iri {
328 fn eq(&self, other: &&'a IriRef) -> bool {
329 *self.as_iri_ref() == **other
330 }
331}
332
333impl PartialEq<IriRefBuf> for Iri {
334 fn eq(&self, other: &IriRefBuf) -> bool {
335 *self.as_iri_ref() == *other.as_iri_ref()
336 }
337}
338
339impl Eq for Iri {}
340
341impl PartialOrd for Iri {
342 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
343 Some(self.cmp(other))
344 }
345}
346
347impl<'a> PartialOrd<&'a Iri> for Iri {
348 fn partial_cmp(&self, other: &&'a Self) -> Option<std::cmp::Ordering> {
349 self.partial_cmp(*other)
350 }
351}
352
353impl PartialOrd<IriBuf> for Iri {
354 fn partial_cmp(&self, other: &IriBuf) -> Option<std::cmp::Ordering> {
355 self.partial_cmp(other.as_iri())
356 }
357}
358
359impl PartialOrd<IriRef> for Iri {
360 fn partial_cmp(&self, other: &IriRef) -> Option<std::cmp::Ordering> {
361 self.as_iri_ref().partial_cmp(other)
362 }
363}
364
365impl<'a> PartialOrd<&'a IriRef> for Iri {
366 fn partial_cmp(&self, other: &&'a IriRef) -> Option<std::cmp::Ordering> {
367 self.as_iri_ref().partial_cmp(*other)
368 }
369}
370
371impl PartialOrd<IriRefBuf> for Iri {
372 fn partial_cmp(&self, other: &IriRefBuf) -> Option<std::cmp::Ordering> {
373 self.partial_cmp(other.as_iri_ref())
374 }
375}
376
377impl Ord for Iri {
378 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
379 self.parts().cmp(&other.parts())
380 }
381}
382
383impl Hash for Iri {
384 fn hash<H: hash::Hasher>(&self, state: &mut H) {
385 self.parts().hash(state)
386 }
387}
388
389impl RiRefImpl for IriBuf {
390 type Authority = Authority;
391 type Path = Path;
392 type Query = Query;
393 type Fragment = Fragment;
394
395 type RiRefBuf = IriRefBuf;
396
397 fn as_bytes(&self) -> &[u8] {
398 self.0.as_bytes()
399 }
400}
401
402impl RiImpl for IriBuf {}
403
404impl RiRefBufImpl for IriBuf {
405 type Ri = Iri;
406 type RiBuf = Self;
407
408 unsafe fn new_unchecked(bytes: Vec<u8>) -> Self {
409 Self::new_unchecked(String::from_utf8_unchecked(bytes))
410 }
411
412 unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
413 self.0.as_mut_vec()
414 }
415
416 fn into_bytes(self) -> Vec<u8> {
417 self.0.into_bytes()
418 }
419}
420
421impl RiBufImpl for IriBuf {}
422
423impl IriBuf {
424 #[inline]
426 pub fn from_vec(buffer: Vec<u8>) -> Result<Self, InvalidIri<Vec<u8>>> {
427 match String::from_utf8(buffer) {
428 Ok(string) => Self::new(string).map_err(|InvalidIri(s)| InvalidIri(s.into_bytes())),
429 Err(e) => Err(InvalidIri(e.into_bytes())),
430 }
431 }
432
433 pub fn from_scheme(scheme: SchemeBuf) -> Self {
435 RiBufImpl::from_scheme(scheme)
436 }
437
438 pub fn into_iri_ref(self) -> IriRefBuf {
440 unsafe { IriRefBuf::new_unchecked(self.0) }
441 }
442
443 pub fn try_into_uri(self) -> Result<UriBuf, InvalidUri<IriBuf>> {
445 UriBuf::new(self.into_bytes()).map_err(|InvalidUri(bytes)| unsafe {
446 InvalidUri(Self::new_unchecked(String::from_utf8_unchecked(bytes)))
447 })
448 }
449
450 pub fn try_into_uri_ref(self) -> Result<UriRefBuf, InvalidUriRef<IriBuf>> {
452 UriRefBuf::new(self.into_bytes()).map_err(|InvalidUriRef(bytes)| unsafe {
453 InvalidUriRef(Self::new_unchecked(String::from_utf8_unchecked(bytes)))
454 })
455 }
456
457 pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
465 self.0.as_mut_vec()
466 }
467
468 pub fn path_mut(&mut self) -> PathMut {
469 PathMut::from_impl(RiRefBufImpl::path_mut(self))
470 }
471
472 pub fn authority_mut(&mut self) -> Option<AuthorityMut> {
473 RiRefBufImpl::authority_mut(self).map(AuthorityMut::from_impl)
474 }
475
476 pub fn set_scheme(&mut self, new_scheme: &Scheme) {
489 RiBufImpl::set_scheme(self, new_scheme)
490 }
491
492 pub fn set_authority(&mut self, authority: Option<&Authority>) {
524 RiRefBufImpl::set_authority(self, authority)
525 }
526
527 pub fn set_path(&mut self, path: &Path) {
562 RiRefBufImpl::set_path(self, path)
563 }
564
565 pub fn set_query(&mut self, query: Option<&Query>) {
567 RiRefBufImpl::set_query(self, query)
568 }
569
570 pub fn set_fragment(&mut self, fragment: Option<&Fragment>) {
572 RiRefBufImpl::set_fragment(self, fragment)
573 }
574}
575
576impl AsRef<IriRef> for IriBuf {
577 fn as_ref(&self) -> &IriRef {
578 self.as_iri_ref()
579 }
580}
581
582impl Borrow<IriRef> for IriBuf {
583 fn borrow(&self) -> &IriRef {
584 self.as_iri_ref()
585 }
586}
587
588impl From<IriBuf> for IriRefBuf {
589 fn from(value: IriBuf) -> Self {
590 value.into_iri_ref()
591 }
592}
593
594impl TryFrom<IriBuf> for UriBuf {
595 type Error = InvalidUri<IriBuf>;
596
597 fn try_from(value: IriBuf) -> Result<Self, Self::Error> {
598 value.try_into_uri()
599 }
600}
601
602impl TryFrom<IriBuf> for UriRefBuf {
603 type Error = InvalidUriRef<IriBuf>;
604
605 fn try_from(value: IriBuf) -> Result<Self, Self::Error> {
606 value.try_into_uri_ref()
607 }
608}
609
610str_eq!(IriBuf);
611
612impl PartialEq<IriRef> for IriBuf {
613 fn eq(&self, other: &IriRef) -> bool {
614 *self.as_iri_ref() == *other
615 }
616}
617
618impl<'a> PartialEq<&'a IriRef> for IriBuf {
619 fn eq(&self, other: &&'a IriRef) -> bool {
620 *self.as_iri_ref() == **other
621 }
622}
623
624impl PartialEq<IriRefBuf> for IriBuf {
625 fn eq(&self, other: &IriRefBuf) -> bool {
626 *self.as_iri_ref() == *other.as_iri_ref()
627 }
628}
629
630impl PartialOrd<IriRef> for IriBuf {
631 fn partial_cmp(&self, other: &IriRef) -> Option<std::cmp::Ordering> {
632 self.as_iri_ref().partial_cmp(other)
633 }
634}
635
636impl<'a> PartialOrd<&'a IriRef> for IriBuf {
637 fn partial_cmp(&self, other: &&'a IriRef) -> Option<std::cmp::Ordering> {
638 self.as_iri_ref().partial_cmp(*other)
639 }
640}
641
642impl PartialOrd<IriRefBuf> for IriBuf {
643 fn partial_cmp(&self, other: &IriRefBuf) -> Option<std::cmp::Ordering> {
644 self.as_iri_ref().partial_cmp(other.as_iri_ref())
645 }
646}