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