1use std::hash::{self, Hash};
2
3use static_regular_grammar::RegularGrammar;
4
5use crate::{
6 common::{parse, str_eq, RiRefBufImpl, RiRefImpl},
7 uri::InvalidUriRef,
8 InvalidIri, InvalidUri, Iri, IriBuf, Uri, UriBuf, UriRef, UriRefBuf,
9};
10
11use super::{Authority, AuthorityMut, Fragment, Path, PathBuf, PathMut, Query, Scheme};
12
13#[derive(RegularGrammar)]
15#[grammar(
16 file = "src/iri/grammar.abnf",
17 entry_point = "IRI-reference",
18 name = "IRI reference",
19 cache = "automata/iri/reference.aut.cbor"
20)]
21#[grammar(sized(
22 IriRefBuf,
23 derive(Debug, Display, PartialEq, Eq, PartialOrd, Ord, Hash)
24))]
25#[cfg_attr(feature = "serde", grammar(serde))]
26#[cfg_attr(feature = "ignore-grammars", grammar(disable))]
27pub struct IriRef(str);
28
29impl RiRefImpl for IriRef {
30 type Authority = Authority;
31 type Path = Path;
32 type Query = Query;
33 type Fragment = Fragment;
34
35 type RiRefBuf = IriRefBuf;
36
37 fn as_bytes(&self) -> &[u8] {
38 self.0.as_bytes()
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub struct IriRefParts<'a> {
44 pub scheme: Option<&'a Scheme>,
45 pub authority: Option<&'a Authority>,
46 pub path: &'a Path,
47 pub query: Option<&'a Query>,
48 pub fragment: Option<&'a Fragment>,
49}
50
51impl IriRef {
52 pub fn parts(&self) -> IriRefParts {
53 let bytes = self.as_bytes();
54 let ranges = parse::reference_parts(bytes, 0);
55
56 IriRefParts {
57 scheme: ranges
58 .scheme
59 .map(|r| unsafe { Scheme::new_unchecked(&bytes[r]) }),
60 authority: ranges
61 .authority
62 .map(|r| unsafe { Authority::new_unchecked(&self.0[r]) }),
63 path: unsafe { Path::new_unchecked(&self.0[ranges.path]) },
64 query: ranges
65 .query
66 .map(|r| unsafe { Query::new_unchecked(&self.0[r]) }),
67 fragment: ranges
68 .fragment
69 .map(|r| unsafe { Fragment::new_unchecked(&self.0[r]) }),
70 }
71 }
72
73 #[inline]
75 pub fn as_iri(&self) -> Option<&Iri> {
76 if self.scheme().is_some() {
77 Some(unsafe { Iri::new_unchecked(&self.0) })
78 } else {
79 None
80 }
81 }
82
83 pub fn as_uri(&self) -> Option<&Uri> {
85 Uri::new(self.as_bytes()).ok()
86 }
87
88 pub fn as_uri_ref(&self) -> Option<&UriRef> {
90 UriRef::new(self.as_bytes()).ok()
91 }
92
93 #[inline]
95 pub fn scheme(&self) -> Option<&Scheme> {
96 RiRefImpl::scheme_opt(self)
97 }
98
99 pub fn authority(&self) -> Option<&Authority> {
101 RiRefImpl::authority(self)
102 }
103
104 pub fn path(&self) -> &Path {
106 RiRefImpl::path(self)
107 }
108
109 pub fn query(&self) -> Option<&Query> {
110 RiRefImpl::query(self)
111 }
112
113 pub fn fragment(&self) -> Option<&Fragment> {
114 RiRefImpl::fragment(self)
115 }
116
117 #[inline]
122 pub fn resolved(&self, base_iri: &(impl ?Sized + AsRef<Iri>)) -> IriBuf {
123 let iri_ref = self.to_owned();
124 iri_ref.into_resolved(base_iri)
125 }
126
127 pub fn relative_to(&self, other: &(impl ?Sized + AsRef<IriRef>)) -> IriRefBuf {
141 RiRefImpl::relative_to(self, other.as_ref())
142 }
143
144 #[inline]
153 pub fn suffix(
154 &self,
155 prefix: &(impl ?Sized + AsRef<IriRef>),
156 ) -> Option<(PathBuf, Option<&Query>, Option<&Fragment>)> {
157 RiRefImpl::suffix(self, prefix.as_ref())
158 }
159
160 #[inline]
171 pub fn base(&self) -> &Self {
172 unsafe { Self::new_unchecked(std::str::from_utf8_unchecked(RiRefImpl::base(self))) }
173 }
174}
175
176impl<'a> TryFrom<&'a IriRef> for &'a Iri {
177 type Error = InvalidIri<&'a IriRef>;
178
179 fn try_from(value: &'a IriRef) -> Result<Self, Self::Error> {
180 value.as_iri().ok_or(InvalidIri(value))
181 }
182}
183
184impl<'a> TryFrom<&'a IriRef> for &'a Uri {
185 type Error = InvalidUri<&'a IriRef>;
186
187 fn try_from(value: &'a IriRef) -> Result<Self, Self::Error> {
188 value.as_uri().ok_or(InvalidUri(value))
189 }
190}
191
192impl<'a> TryFrom<&'a IriRef> for &'a UriRef {
193 type Error = InvalidUriRef<&'a IriRef>;
194
195 fn try_from(value: &'a IriRef) -> Result<Self, Self::Error> {
196 value.as_uri_ref().ok_or(InvalidUriRef(value))
197 }
198}
199
200str_eq!(IriRef);
201
202impl PartialEq for IriRef {
203 fn eq(&self, other: &Self) -> bool {
204 self.parts() == other.parts()
205 }
206}
207
208impl<'a> PartialEq<&'a IriRef> for IriRef {
209 fn eq(&self, other: &&'a Self) -> bool {
210 *self == **other
211 }
212}
213
214impl PartialEq<IriRefBuf> for IriRef {
215 fn eq(&self, other: &IriRefBuf) -> bool {
216 *self == *other.as_iri_ref()
217 }
218}
219
220impl PartialEq<Iri> for IriRef {
221 fn eq(&self, other: &Iri) -> bool {
222 *self == *other.as_iri_ref()
223 }
224}
225
226impl<'a> PartialEq<&'a Iri> for IriRef {
227 fn eq(&self, other: &&'a Iri) -> bool {
228 *self == *other.as_iri_ref()
229 }
230}
231
232impl PartialEq<IriBuf> for IriRef {
233 fn eq(&self, other: &IriBuf) -> bool {
234 *self == *other.as_iri_ref()
235 }
236}
237
238impl Eq for IriRef {}
239
240impl PartialOrd for IriRef {
241 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
242 Some(self.cmp(other))
243 }
244}
245
246impl<'a> PartialOrd<&'a IriRef> for IriRef {
247 fn partial_cmp(&self, other: &&'a Self) -> Option<std::cmp::Ordering> {
248 self.partial_cmp(*other)
249 }
250}
251
252impl PartialOrd<IriRefBuf> for IriRef {
253 fn partial_cmp(&self, other: &IriRefBuf) -> Option<std::cmp::Ordering> {
254 self.partial_cmp(other.as_iri_ref())
255 }
256}
257
258impl PartialOrd<Iri> for IriRef {
259 fn partial_cmp(&self, other: &Iri) -> Option<std::cmp::Ordering> {
260 self.partial_cmp(other.as_iri_ref())
261 }
262}
263
264impl<'a> PartialOrd<&'a Iri> for IriRef {
265 fn partial_cmp(&self, other: &&'a Iri) -> Option<std::cmp::Ordering> {
266 self.partial_cmp(other.as_iri_ref())
267 }
268}
269
270impl PartialOrd<IriBuf> for IriRef {
271 fn partial_cmp(&self, other: &IriBuf) -> Option<std::cmp::Ordering> {
272 self.partial_cmp(other.as_iri_ref())
273 }
274}
275
276impl Ord for IriRef {
277 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
278 self.parts().cmp(&other.parts())
279 }
280}
281
282impl Hash for IriRef {
283 fn hash<H: hash::Hasher>(&self, state: &mut H) {
284 self.parts().hash(state)
285 }
286}
287
288impl RiRefImpl for IriRefBuf {
289 type Authority = Authority;
290 type Path = Path;
291 type Query = Query;
292 type Fragment = Fragment;
293
294 type RiRefBuf = Self;
295
296 fn as_bytes(&self) -> &[u8] {
297 self.0.as_bytes()
298 }
299}
300
301impl RiRefBufImpl for IriRefBuf {
302 type Ri = Iri;
303 type RiBuf = IriBuf;
304
305 unsafe fn new_unchecked(bytes: Vec<u8>) -> Self {
306 Self::new_unchecked(String::from_utf8_unchecked(bytes))
307 }
308
309 unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
310 self.0.as_mut_vec()
311 }
312
313 fn into_bytes(self) -> Vec<u8> {
314 self.0.into_bytes()
315 }
316}
317
318impl IriRefBuf {
319 #[inline]
321 pub fn from_vec(buffer: Vec<u8>) -> Result<Self, InvalidIriRef<Vec<u8>>> {
322 match String::from_utf8(buffer) {
323 Ok(string) => {
324 Self::new(string).map_err(|InvalidIriRef(s)| InvalidIriRef(s.into_bytes()))
325 }
326 Err(e) => Err(InvalidIriRef(e.into_bytes())),
327 }
328 }
329
330 #[inline]
336 pub unsafe fn from_vec_unchecked(buffer: Vec<u8>) -> Self {
337 Self::new_unchecked(String::from_utf8_unchecked(buffer))
338 }
339
340 pub fn try_into_iri(self) -> Result<IriBuf, InvalidIri<Self>> {
342 if self.scheme().is_some() {
343 unsafe { Ok(IriBuf::new_unchecked(self.0)) }
344 } else {
345 Err(InvalidIri(self))
346 }
347 }
348
349 pub fn try_into_uri(self) -> Result<UriBuf, InvalidUri<Self>> {
351 UriBuf::new(self.into_bytes()).map_err(|InvalidUri(bytes)| unsafe {
352 InvalidUri(Self::new_unchecked(String::from_utf8_unchecked(bytes)))
353 })
354 }
355
356 pub fn try_into_uri_ref(self) -> Result<UriRefBuf, InvalidUriRef<Self>> {
358 UriRefBuf::new(self.into_bytes()).map_err(|InvalidUriRef(bytes)| unsafe {
359 InvalidUriRef(Self::new_unchecked(String::from_utf8_unchecked(bytes)))
360 })
361 }
362
363 pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
371 self.0.as_mut_vec()
372 }
373
374 pub fn path_mut(&mut self) -> PathMut {
375 PathMut::from_impl(RiRefBufImpl::path_mut(self))
376 }
377
378 pub fn authority_mut(&mut self) -> Option<AuthorityMut> {
379 RiRefBufImpl::authority_mut(self).map(AuthorityMut::from_impl)
380 }
381
382 pub fn set_scheme(&mut self, scheme: Option<&Scheme>) {
407 RiRefBufImpl::set_scheme(self, scheme)
408 }
409
410 pub fn set_authority(&mut self, authority: Option<&Authority>) {
442 RiRefBufImpl::set_authority(self, authority)
443 }
444
445 pub fn set_path(&mut self, path: &Path) {
487 RiRefBufImpl::set_path(self, path)
488 }
489
490 pub fn set_query(&mut self, query: Option<&Query>) {
492 RiRefBufImpl::set_query(self, query)
493 }
494
495 pub fn set_fragment(&mut self, fragment: Option<&Fragment>) {
497 RiRefBufImpl::set_fragment(self, fragment)
498 }
499
500 pub fn resolve(&mut self, base_iri: &(impl ?Sized + AsRef<Iri>)) {
506 RiRefBufImpl::resolve(self, base_iri.as_ref())
507 }
508
509 pub fn into_resolved(self, base_iri: &(impl ?Sized + AsRef<Iri>)) -> IriBuf {
510 RiRefBufImpl::into_resolved(self, base_iri.as_ref())
511 }
512}
513
514impl TryFrom<IriRefBuf> for IriBuf {
515 type Error = InvalidIri<IriRefBuf>;
516
517 fn try_from(value: IriRefBuf) -> Result<Self, Self::Error> {
518 value.try_into_iri()
519 }
520}
521
522impl TryFrom<IriRefBuf> for UriBuf {
523 type Error = InvalidUri<IriRefBuf>;
524
525 fn try_from(value: IriRefBuf) -> Result<Self, Self::Error> {
526 value.try_into_uri()
527 }
528}
529
530impl TryFrom<IriRefBuf> for UriRefBuf {
531 type Error = InvalidUriRef<IriRefBuf>;
532
533 fn try_from(value: IriRefBuf) -> Result<Self, Self::Error> {
534 value.try_into_uri_ref()
535 }
536}
537
538str_eq!(IriRefBuf);
539
540impl PartialEq<Iri> for IriRefBuf {
541 fn eq(&self, other: &Iri) -> bool {
542 *self.as_iri_ref() == *other.as_iri_ref()
543 }
544}
545
546impl<'a> PartialEq<&'a Iri> for IriRefBuf {
547 fn eq(&self, other: &&'a Iri) -> bool {
548 *self.as_iri_ref() == *other.as_iri_ref()
549 }
550}
551
552impl PartialEq<IriBuf> for IriRefBuf {
553 fn eq(&self, other: &IriBuf) -> bool {
554 *self.as_iri_ref() == *other.as_iri_ref()
555 }
556}
557
558impl PartialOrd<Iri> for IriRefBuf {
559 fn partial_cmp(&self, other: &Iri) -> Option<std::cmp::Ordering> {
560 self.as_iri_ref().partial_cmp(other.as_iri_ref())
561 }
562}
563
564impl<'a> PartialOrd<&'a Iri> for IriRefBuf {
565 fn partial_cmp(&self, other: &&'a Iri) -> Option<std::cmp::Ordering> {
566 self.as_iri_ref().partial_cmp(other.as_iri_ref())
567 }
568}
569
570impl PartialOrd<IriBuf> for IriRefBuf {
571 fn partial_cmp(&self, other: &IriBuf) -> Option<std::cmp::Ordering> {
572 self.as_iri_ref().partial_cmp(other.as_iri_ref())
573 }
574}
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579
580 const PARTS: [(
581 &str,
582 (Option<&str>, Option<&str>, &str, Option<&str>, Option<&str>),
583 ); 36] = [
584 ("", (None, None, "", None, None)),
586 ("scheme:", (Some("scheme"), None, "", None, None)),
588 ("//authority", (None, Some("authority"), "", None, None)),
589 ("path", (None, None, "path", None, None)),
590 ("/path", (None, None, "/path", None, None)),
591 ("/", (None, None, "/", None, None)),
592 ("foo//bar", (None, None, "foo//bar", None, None)),
593 ("?query", (None, None, "", Some("query"), None)),
594 ("#fragment", (None, None, "", None, Some("fragment"))),
595 (
596 "scheme:?query",
597 (Some("scheme"), None, "", Some("query"), None),
598 ),
599 (
601 "scheme://authority",
602 (Some("scheme"), Some("authority"), "", None, None),
603 ),
604 ("scheme:path", (Some("scheme"), None, "path", None, None)),
605 ("scheme:/path", (Some("scheme"), None, "/path", None, None)),
606 (
607 "scheme:?query",
608 (Some("scheme"), None, "", Some("query"), None),
609 ),
610 (
611 "scheme:#fragment",
612 (Some("scheme"), None, "", None, Some("fragment")),
613 ),
614 (
615 "//authority/path",
616 (None, Some("authority"), "/path", None, None),
617 ),
618 (
619 "//authority?query",
620 (None, Some("authority"), "", Some("query"), None),
621 ),
622 (
623 "//authority#fragment",
624 (None, Some("authority"), "", None, Some("fragment")),
625 ),
626 ("path?query", (None, None, "path", Some("query"), None)),
627 ("/path?query", (None, None, "/path", Some("query"), None)),
628 (
629 "path#fragment",
630 (None, None, "path", None, Some("fragment")),
631 ),
632 (
633 "?query#fragment",
634 (None, None, "", Some("query"), Some("fragment")),
635 ),
636 (
638 "scheme://authority/path",
639 (Some("scheme"), Some("authority"), "/path", None, None),
640 ),
641 (
642 "scheme://authority?query",
643 (Some("scheme"), Some("authority"), "", Some("query"), None),
644 ),
645 (
646 "scheme://authority#fragment",
647 (
648 Some("scheme"),
649 Some("authority"),
650 "",
651 None,
652 Some("fragment"),
653 ),
654 ),
655 (
656 "scheme:path?query",
657 (Some("scheme"), None, "path", Some("query"), None),
658 ),
659 (
660 "scheme:path#fragment",
661 (Some("scheme"), None, "path", None, Some("fragment")),
662 ),
663 (
664 "//authority/path?query",
665 (None, Some("authority"), "/path", Some("query"), None),
666 ),
667 (
668 "//authority/path#fragment",
669 (None, Some("authority"), "/path", None, Some("fragment")),
670 ),
671 (
672 "//authority?query#fragment",
673 (None, Some("authority"), "", Some("query"), Some("fragment")),
674 ),
675 (
676 "path?query#fragment",
677 (None, None, "path", Some("query"), Some("fragment")),
678 ),
679 (
681 "scheme://authority/path?query",
682 (
683 Some("scheme"),
684 Some("authority"),
685 "/path",
686 Some("query"),
687 None,
688 ),
689 ),
690 (
691 "scheme://authority/path#fragment",
692 (
693 Some("scheme"),
694 Some("authority"),
695 "/path",
696 None,
697 Some("fragment"),
698 ),
699 ),
700 (
701 "scheme://authority?query#fragment",
702 (
703 Some("scheme"),
704 Some("authority"),
705 "",
706 Some("query"),
707 Some("fragment"),
708 ),
709 ),
710 (
711 "scheme:path?query#fragment",
712 (
713 Some("scheme"),
714 None,
715 "path",
716 Some("query"),
717 Some("fragment"),
718 ),
719 ),
720 (
722 "scheme://authority/path?query#fragment",
723 (
724 Some("scheme"),
725 Some("authority"),
726 "/path",
727 Some("query"),
728 Some("fragment"),
729 ),
730 ),
731 ];
732
733 #[test]
734 fn parts() {
735 for (input, expected) in PARTS {
736 let input = IriRef::new(input).unwrap();
737 let parts = input.parts();
738
739 assert_eq!(parts.scheme.map(Scheme::as_str), expected.0);
740 assert_eq!(parts.authority.map(Authority::as_str), expected.1);
741 assert_eq!(parts.path.as_str(), expected.2);
742 assert_eq!(parts.query.map(Query::as_str), expected.3);
743 assert_eq!(parts.fragment.map(Fragment::as_str), expected.4)
744 }
745 }
746
747 #[test]
748 fn scheme() {
749 for (input, expected) in PARTS {
750 let input = IriRef::new(input).unwrap();
751 assert_eq!(input.scheme().map(Scheme::as_str), expected.0)
752 }
753 }
754
755 #[test]
756 fn authority() {
757 for (input, expected) in PARTS {
758 let input = IriRef::new(input).unwrap();
759 assert_eq!(input.authority().map(Authority::as_str), expected.1)
761 }
762 }
763
764 #[test]
765 fn set_authority() {
766 let vectors = [
767 ("scheme:/path", Some("authority"), "scheme://authority/path"),
768 ("scheme:path", Some("authority"), "scheme://authority/path"),
769 ("scheme://authority//path", None, "scheme:/.//path"),
770 ];
771
772 for (input, authority, expected) in vectors {
773 let mut buffer = IriRefBuf::new(input.to_string()).unwrap();
774 let authority = authority.map(Authority::new).transpose().unwrap();
775 buffer.set_authority(authority);
776 assert_eq!(buffer.as_str(), expected)
778 }
779 }
780
781 #[test]
782 fn path() {
783 for (input, expected) in PARTS {
784 let input = IriRef::new(input).unwrap();
785 assert_eq!(input.path().as_str(), expected.2)
787 }
788 }
789
790 #[test]
791 fn query() {
792 for (input, expected) in PARTS {
793 let input = IriRef::new(input).unwrap();
794 assert_eq!(input.query().map(Query::as_str), expected.3)
796 }
797 }
798
799 #[test]
800 fn fragment() {
801 for (input, expected) in PARTS {
802 let input = IriRef::new(input).unwrap();
803 assert_eq!(input.fragment().map(Fragment::as_str), expected.4)
805 }
806 }
807
808 #[test]
809 fn disambiguate_scheme() {
810 let mut iri_ref = IriRefBuf::new("scheme:a:b/c".to_string()).unwrap();
811 iri_ref.set_scheme(None);
812 assert_eq!(iri_ref.as_str(), "./a:b/c")
813 }
814
815 #[test]
816 fn disambiguate_authority() {
817 let mut iri_ref = IriRefBuf::new("//host//path".to_string()).unwrap();
818 iri_ref.set_authority(None);
819 assert_eq!(iri_ref.as_str(), "/.//path")
820 }
821
822 #[test]
823 fn unambiguous_resolution() {
824 let base_iri = Iri::new("http:/a/b").unwrap();
825 let tests = [("../..//", "http:/")];
826
827 for (relative, absolute) in &tests {
828 assert_eq!(IriRef::new(relative).unwrap().resolved(base_iri), *absolute);
830 }
831 }
832
833 #[test]
834 fn resolution_normal() {
835 let base_iri = Iri::new("http://a/b/c/d;p?q").unwrap();
837
838 let tests = [
839 ("g:h", "g:h"),
840 ("g", "http://a/b/c/g"),
841 ("./g", "http://a/b/c/g"),
842 ("g/", "http://a/b/c/g/"),
843 ("/g", "http://a/g"),
844 ("//g", "http://g"),
845 ("?y", "http://a/b/c/d;p?y"),
846 ("g?y", "http://a/b/c/g?y"),
847 ("#s", "http://a/b/c/d;p?q#s"),
848 ("g#s", "http://a/b/c/g#s"),
849 ("g?y#s", "http://a/b/c/g?y#s"),
850 (";x", "http://a/b/c/;x"),
851 ("g;x", "http://a/b/c/g;x"),
852 ("g;x?y#s", "http://a/b/c/g;x?y#s"),
853 ("", "http://a/b/c/d;p?q"),
854 (".", "http://a/b/c/"),
855 ("./", "http://a/b/c/"),
856 ("..", "http://a/b/"),
857 ("../", "http://a/b/"),
858 ("../g", "http://a/b/g"),
859 ("../..", "http://a/"),
860 ("../../", "http://a/"),
861 ("../../g", "http://a/g"),
862 ];
863
864 for (relative, absolute) in &tests {
865 println!("{} => {}", relative, absolute);
866 assert_eq!(IriRef::new(relative).unwrap().resolved(base_iri), *absolute);
867 }
868 }
869
870 #[test]
871 fn resolution_abnormal() {
872 let base_iri = Iri::new("http://a/b/c/d;p?q").unwrap();
875
876 let tests = [
877 ("../../../g", "http://a/g"),
878 ("../../../../g", "http://a/g"),
879 ("/./g", "http://a/g"),
880 ("/../g", "http://a/g"),
881 ("g.", "http://a/b/c/g."),
882 (".g", "http://a/b/c/.g"),
883 ("g..", "http://a/b/c/g.."),
884 ("..g", "http://a/b/c/..g"),
885 ("./../g", "http://a/b/g"),
886 ("./g/.", "http://a/b/c/g/"),
887 ("g/./h", "http://a/b/c/g/h"),
888 ("g/../h", "http://a/b/c/h"),
889 ("g;x=1/./y", "http://a/b/c/g;x=1/y"),
890 ("g;x=1/../y", "http://a/b/c/y"),
891 ("g?y/./x", "http://a/b/c/g?y/./x"),
892 ("g?y/../x", "http://a/b/c/g?y/../x"),
893 ("g#s/./x", "http://a/b/c/g#s/./x"),
894 ("g#s/../x", "http://a/b/c/g#s/../x"),
895 ("http:g", "http:g"),
896 ];
897
898 for (relative, absolute) in &tests {
899 assert_eq!(IriRef::new(relative).unwrap().resolved(base_iri), *absolute);
901 }
902 }
903
904 #[test]
905 fn more_resolutions1() {
906 let base_iri = Iri::new("http://a/bb/ccc/d;p?q").unwrap();
907
908 let tests = [
909 ("#s", "http://a/bb/ccc/d;p?q#s"),
910 ("", "http://a/bb/ccc/d;p?q"),
911 ];
912
913 for (relative, absolute) in &tests {
914 println!("{} => {}", relative, absolute);
915 let buffer: crate::IriBuf = IriRef::new(relative).unwrap().resolved(base_iri);
916 assert_eq!(buffer.as_str(), *absolute);
917 }
918 }
919
920 #[test]
921 fn more_resolutions2() {
922 let base_iri = Iri::new("http://a/bb/ccc/./d;p?q").unwrap();
923
924 let tests = [
925 ("..", "http://a/bb/"),
926 ("../", "http://a/bb/"),
927 ("../g", "http://a/bb/g"),
928 ("../..", "http://a/"),
929 ("../../", "http://a/"),
930 ("../../g", "http://a/g"),
931 ];
932
933 for (relative, absolute) in &tests {
934 let buffer: crate::IriBuf = IriRef::new(relative).unwrap().resolved(base_iri);
936 assert_eq!(buffer.as_str(), *absolute);
937 }
938 }
939
940 #[test]
941 fn more_resolutions3() {
942 let base_iri = Iri::new("http://ab//de//ghi").unwrap();
943
944 let tests = [
945 ("xyz", "http://ab//de//xyz"),
946 ("./xyz", "http://ab//de//xyz"),
947 ("../xyz", "http://ab//de/xyz"),
948 ];
949
950 for (relative, absolute) in &tests {
951 println!("{} => {}", relative, absolute);
952 let buffer: crate::IriBuf = IriRef::new(relative).unwrap().resolved(base_iri);
953 assert_eq!(buffer.as_str(), *absolute);
954 }
955 }
956
957 #[test]
958 fn more_resolutions4() {
959 let base_iri = Iri::new("http://a/bb/ccc/../d;p?q").unwrap();
960
961 let tests = [("../../", "http://a/")];
962
963 for (relative, absolute) in &tests {
964 let buffer: crate::IriBuf = IriRef::new(relative).unwrap().resolved(base_iri);
966 assert_eq!(buffer.as_str(), *absolute);
967 }
968 }
969
970 #[test]
972 fn reference_resolution_with_scheme_no_disambiguation() {
973 let base = Iri::new("scheme:a:b/").unwrap();
974 let mut iri = IriRefBuf::new("Foo".to_string()).unwrap();
975 iri.resolve(base);
976
977 assert_eq!(iri.to_string(), "scheme:a:b/Foo")
978 }
979
980 #[test]
981 fn relative_to() {
982 let base =
983 IriRef::new("https://w3c.github.io/json-ld-api/tests/compact/0066-in.jsonld").unwrap();
984 let vectors = [
985 (
986 "https://w3c.github.io/json-ld-api/tests/compact/link",
987 "link",
988 ),
989 (
990 "https://w3c.github.io/json-ld-api/tests/compact/0066-in.jsonld#fragment-works",
991 "#fragment-works",
992 ),
993 (
994 "https://w3c.github.io/json-ld-api/tests/compact/0066-in.jsonld?query=works",
995 "?query=works",
996 ),
997 ("https://w3c.github.io/json-ld-api/tests/", "../"),
998 ("https://w3c.github.io/json-ld-api/", "../../"),
999 ("https://w3c.github.io/json-ld-api/parent", "../../parent"),
1000 (
1001 "https://w3c.github.io/json-ld-api/parent#fragment",
1002 "../../parent#fragment",
1003 ),
1004 (
1005 "https://w3c.github.io/parent-parent-eq-root",
1006 "../../../parent-parent-eq-root",
1007 ),
1008 (
1009 "http://example.org/scheme-relative",
1010 "http://example.org/scheme-relative",
1011 ),
1012 (
1013 "https://w3c.github.io/json-ld-api/tests/compact/0066-in.jsonld",
1014 "0066-in.jsonld",
1015 ),
1016 ];
1017
1018 for (input, expected) in &vectors {
1019 let input = IriRef::new(input).unwrap();
1020 assert_eq!(input.relative_to(base), *expected)
1021 }
1022 }
1023}