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}