1use core::ops::{Index, Range, RangeFrom, RangeFull, RangeTo};
10
11use crate::Url;
12
13impl Index<RangeFull> for Url {
14 type Output = str;
15 fn index(&self, _: RangeFull) -> &str {
16 &self.serialization
17 }
18}
19
20impl Index<RangeFrom<Position>> for Url {
21 type Output = str;
22 fn index(&self, range: RangeFrom<Position>) -> &str {
23 &self.serialization[self.index(range.start)..]
24 }
25}
26
27impl Index<RangeTo<Position>> for Url {
28 type Output = str;
29 fn index(&self, range: RangeTo<Position>) -> &str {
30 &self.serialization[..self.index(range.end)]
31 }
32}
33
34impl Index<Range<Position>> for Url {
35 type Output = str;
36 fn index(&self, range: Range<Position>) -> &str {
37 &self.serialization[self.index(range.start)..self.index(range.end)]
38 }
39}
40
41fn count_digits(n: u16) -> usize {
43 match n {
44 0..=9 => 1,
45 10..=99 => 2,
46 100..=999 => 3,
47 1000..=9999 => 4,
48 10000..=65535 => 5,
49 }
50}
51
52#[test]
53fn test_count_digits() {
54 assert_eq!(count_digits(0), 1);
55 assert_eq!(count_digits(1), 1);
56 assert_eq!(count_digits(9), 1);
57 assert_eq!(count_digits(10), 2);
58 assert_eq!(count_digits(99), 2);
59 assert_eq!(count_digits(100), 3);
60 assert_eq!(count_digits(9999), 4);
61 assert_eq!(count_digits(65535), 5);
62}
63
64#[derive(Copy, Clone, Debug)]
105pub enum Position {
106 BeforeScheme,
107 AfterScheme,
108 BeforeUsername,
109 AfterUsername,
110 BeforePassword,
111 AfterPassword,
112 BeforeHost,
113 AfterHost,
114 BeforePort,
115 AfterPort,
116 BeforePath,
117 AfterPath,
118 BeforeQuery,
119 AfterQuery,
120 BeforeFragment,
121 AfterFragment,
122}
123
124impl Url {
125 #[inline]
126 fn index(&self, position: Position) -> usize {
127 match position {
128 Position::BeforeScheme => 0,
129
130 Position::AfterScheme => self.scheme_end as usize,
131
132 Position::BeforeUsername => {
133 if self.has_authority() {
134 self.scheme_end as usize + "://".len()
135 } else {
136 debug_assert!(self.byte_at(self.scheme_end) == b':');
137 debug_assert!(self.scheme_end + ":".len() as u32 == self.username_end);
138 self.scheme_end as usize + ":".len()
139 }
140 }
141
142 Position::AfterUsername => self.username_end as usize,
143
144 Position::BeforePassword => {
145 if self.has_authority() && self.byte_at(self.username_end) == b':' {
146 self.username_end as usize + ":".len()
147 } else {
148 debug_assert!(self.username_end == self.host_start);
149 self.username_end as usize
150 }
151 }
152
153 Position::AfterPassword => {
154 if self.has_authority() && self.byte_at(self.username_end) == b':' {
155 debug_assert!(self.byte_at(self.host_start - "@".len() as u32) == b'@');
156 self.host_start as usize - "@".len()
157 } else {
158 debug_assert!(self.username_end == self.host_start);
159 self.host_start as usize
160 }
161 }
162
163 Position::BeforeHost => self.host_start as usize,
164
165 Position::AfterHost => self.host_end as usize,
166
167 Position::BeforePort => {
168 if self.port.is_some() {
169 debug_assert!(self.byte_at(self.host_end) == b':');
170 self.host_end as usize + ":".len()
171 } else {
172 self.host_end as usize
173 }
174 }
175
176 Position::AfterPort => {
177 if let Some(port) = self.port {
178 debug_assert!(self.byte_at(self.host_end) == b':');
179 self.host_end as usize + ":".len() + count_digits(port)
180 } else {
181 self.host_end as usize
182 }
183 }
184
185 Position::BeforePath => self.path_start as usize,
186
187 Position::AfterPath => match (self.query_start, self.fragment_start) {
188 (Some(q), _) => q as usize,
189 (None, Some(f)) => f as usize,
190 (None, None) => self.serialization.len(),
191 },
192
193 Position::BeforeQuery => match (self.query_start, self.fragment_start) {
194 (Some(q), _) => {
195 debug_assert!(self.byte_at(q) == b'?');
196 q as usize + "?".len()
197 }
198 (None, Some(f)) => f as usize,
199 (None, None) => self.serialization.len(),
200 },
201
202 Position::AfterQuery => match self.fragment_start {
203 None => self.serialization.len(),
204 Some(f) => f as usize,
205 },
206
207 Position::BeforeFragment => match self.fragment_start {
208 Some(f) => {
209 debug_assert!(self.byte_at(f) == b'#');
210 f as usize + "#".len()
211 }
212 None => self.serialization.len(),
213 },
214
215 Position::AfterFragment => self.serialization.len(),
216 }
217 }
218}