1mod authority;
4
5use core::num::NonZeroUsize;
6use core::ops::{Range, RangeFrom, RangeTo};
7
8use crate::parser::trusted as trusted_parser;
9use crate::spec::Spec;
10use crate::types::RiReferenceStr;
11
12pub use self::authority::AuthorityComponents;
13
14#[derive(Debug, Clone, Copy)]
16pub(crate) struct Splitter {
17 scheme_end: Option<NonZeroUsize>,
19 authority_end: Option<NonZeroUsize>,
24 query_start: Option<NonZeroUsize>,
26 fragment_start: Option<NonZeroUsize>,
28}
29
30impl Splitter {
31 #[inline]
33 #[must_use]
34 pub(crate) fn new(
35 scheme_end: Option<NonZeroUsize>,
36 authority_end: Option<NonZeroUsize>,
37 query_start: Option<NonZeroUsize>,
38 fragment_start: Option<NonZeroUsize>,
39 ) -> Self {
40 Self {
41 scheme_end,
42 authority_end,
43 query_start,
44 fragment_start,
45 }
46 }
47
48 #[must_use]
50 fn split_into_major(
51 self,
52 s: &str,
53 ) -> (Option<&str>, Option<&str>, &str, Option<&str>, Option<&str>) {
54 let (scheme, next_of_scheme) = match self.scheme_end {
55 Some(end) => (Some(&s[..end.get()]), end.get() + 1),
57 None => (None, 0),
58 };
59 let (authority, next_of_authority) = match self.authority_end {
60 Some(end) => (Some(&s[(next_of_scheme + 2)..end.get()]), end.get()),
62 None => (None, next_of_scheme),
63 };
64 let (fragment, end_of_prev_of_fragment) = match self.fragment_start {
65 Some(start) => (Some(&s[start.get()..]), start.get() - 1),
67 None => (None, s.len()),
68 };
69 let (query, end_of_path) = match self.query_start {
70 Some(start) => (
71 Some(&s[start.get()..end_of_prev_of_fragment]),
72 start.get() - 1,
74 ),
75 None => (None, end_of_prev_of_fragment),
76 };
77 let path = &s[next_of_authority..end_of_path];
78 (scheme, authority, path, query, fragment)
79 }
80
81 #[inline]
83 #[must_use]
84 fn scheme_range(self) -> Option<RangeTo<usize>> {
85 self.scheme_end.map(|end| ..end.get())
86 }
87
88 #[inline]
90 #[must_use]
91 pub(crate) fn scheme_str<'a>(&self, s: &'a str) -> Option<&'a str> {
92 self.scheme_range().map(|range| &s[range])
93 }
94
95 #[inline]
97 #[must_use]
98 pub(crate) fn has_scheme(&self) -> bool {
99 self.scheme_end.is_some()
100 }
101
102 #[inline]
104 #[must_use]
105 fn authority_range(self) -> Option<Range<usize>> {
106 let end = self.authority_end?.get();
107 let start = self.scheme_end.map_or(2, |v| v.get() + 3);
110 Some(start..end)
111 }
112
113 #[inline]
115 #[must_use]
116 pub(crate) fn authority_str<'a>(&self, s: &'a str) -> Option<&'a str> {
117 self.authority_range().map(|range| &s[range])
118 }
119
120 #[inline]
122 #[must_use]
123 pub(crate) fn has_authority(&self) -> bool {
124 self.authority_end.is_some()
125 }
126
127 #[inline]
129 #[must_use]
130 fn path_range(self, full_len: usize) -> Range<usize> {
131 let end = self
133 .query_start
134 .or(self.fragment_start)
135 .map_or(full_len, |v| v.get() - 1);
136 let start = self.authority_end.map_or_else(
137 || self.scheme_end.map_or(0, |v| v.get() + 1),
139 NonZeroUsize::get,
140 );
141
142 start..end
143 }
144
145 #[inline]
147 #[must_use]
148 pub(crate) fn path_str<'a>(&self, s: &'a str) -> &'a str {
149 &s[self.path_range(s.len())]
150 }
151
152 #[inline]
154 #[must_use]
155 pub(crate) fn is_path_empty(&self, full_len: usize) -> bool {
156 self.path_range(full_len).is_empty()
157 }
158
159 #[inline]
161 #[must_use]
162 fn query_range(self, full_len: usize) -> Option<Range<usize>> {
163 let start = self.query_start?.get();
164 let end = self.fragment_start.map_or(full_len, |v| v.get() - 1);
166
167 Some(start..end)
168 }
169
170 #[inline]
172 #[must_use]
173 pub(crate) fn query_str<'a>(&self, s: &'a str) -> Option<&'a str> {
174 self.query_range(s.len()).map(|range| &s[range])
175 }
176
177 #[inline]
179 #[must_use]
180 pub(crate) fn has_query(&self) -> bool {
181 self.query_start.is_some()
182 }
183
184 #[inline]
186 #[must_use]
187 pub(crate) fn fragment_range(self) -> Option<RangeFrom<usize>> {
188 self.fragment_start.map(|v| v.get()..)
189 }
190
191 #[inline]
193 #[must_use]
194 pub(crate) fn fragment_str<'a>(&self, s: &'a str) -> Option<&'a str> {
195 self.fragment_range().map(|range| &s[range])
196 }
197}
198
199#[derive(Debug, Clone, Copy)]
203pub(crate) struct RiReferenceComponents<'a, S: Spec> {
204 pub(crate) iri: &'a RiReferenceStr<S>,
206 pub(crate) splitter: Splitter,
208}
209
210impl<'a, S: Spec> RiReferenceComponents<'a, S> {
211 #[inline]
213 #[must_use]
214 pub(crate) fn to_major(
215 self,
216 ) -> (
217 Option<&'a str>,
218 Option<&'a str>,
219 &'a str,
220 Option<&'a str>,
221 Option<&'a str>,
222 ) {
223 self.splitter.split_into_major(self.iri.as_str())
224 }
225
226 #[inline]
228 #[must_use]
229 pub(crate) fn iri(&self) -> &'a RiReferenceStr<S> {
230 self.iri
231 }
232
233 #[inline]
235 #[must_use]
236 pub(crate) fn scheme_str(&self) -> Option<&str> {
237 self.splitter.scheme_str(self.iri.as_str())
238 }
239
240 #[inline]
242 #[must_use]
243 pub(crate) fn authority_str(&self) -> Option<&str> {
244 self.splitter.authority_str(self.iri.as_str())
245 }
246
247 #[inline]
249 #[must_use]
250 pub(crate) fn path_str(&self) -> &str {
251 self.splitter.path_str(self.iri.as_str())
252 }
253
254 #[inline]
256 #[must_use]
257 pub(crate) fn query_str(&self) -> Option<&str> {
258 self.splitter.query_str(self.iri.as_str())
259 }
260}
261
262impl<'a, S: Spec> From<&'a RiReferenceStr<S>> for RiReferenceComponents<'a, S> {
263 #[inline]
264 fn from(s: &'a RiReferenceStr<S>) -> Self {
265 trusted_parser::decompose_iri_reference(s)
266 }
267}