1 // Copyright 2016 The rust-url developers.
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
9 use std
::ops
::{Range, RangeFrom, RangeTo, RangeFull, Index}
;
12 impl Index
<RangeFull
> for Url
{
14 fn index(&self, _
: RangeFull
) -> &str {
19 impl Index
<RangeFrom
<Position
>> for Url
{
21 fn index(&self, range
: RangeFrom
<Position
>) -> &str {
22 &self.serialization
[self.index(range
.start
)..]
26 impl Index
<RangeTo
<Position
>> for Url
{
28 fn index(&self, range
: RangeTo
<Position
>) -> &str {
29 &self.serialization
[..self.index(range
.end
)]
33 impl Index
<Range
<Position
>> for Url
{
35 fn index(&self, range
: Range
<Position
>) -> &str {
36 &self.serialization
[self.index(range
.start
)..self.index(range
.end
)]
40 /// Indicates a position within a URL based on its components.
42 /// A range of positions can be used for slicing `Url`:
45 /// # use url::{Url, Position};
46 /// # fn something(some_url: Url) {
47 /// let serialization: &str = &some_url[..];
48 /// let serialization_without_fragment: &str = &some_url[..Position::AfterQuery];
49 /// let authority: &str = &some_url[Position::BeforeUsername..Position::AfterPort];
50 /// let data_url_payload: &str = &some_url[Position::BeforePath..Position::AfterQuery];
51 /// let scheme_relative: &str = &some_url[Position::BeforeUsername..];
55 /// In a pseudo-grammar (where `[`…`]?` makes a sub-sequence optional),
56 /// URL components and delimiters that separate them are:
61 /// [ "//" [ username [ ":" password ]? "@" ]? host [ ":" port ]? ]?
62 /// path [ "?" query ]? [ "#" fragment ]?
65 /// When a given component is not present,
66 /// its "before" and "after" position are the same
67 /// (so that `&some_url[BeforeFoo..AfterFoo]` is the empty string)
68 /// and component ordering is preserved
69 /// (so that a missing query "is between" a path and a fragment).
71 /// The end of a component and the start of the next are either the same or separate
73 /// (Not that the initial `/` of a path is considered part of the path here, not a delimiter.)
74 /// For example, `&url[..BeforeFragment]` would include a `#` delimiter (if present in `url`),
75 /// so `&url[..AfterQuery]` might be desired instead.
77 /// `BeforeScheme` and `AfterFragment` are always the start and end of the entire URL,
78 /// so `&url[BeforeScheme..X]` is the same as `&url[..X]`
79 /// and `&url[X..AfterFragment]` is the same as `&url[X..]`.
80 #[derive(Copy, Clone, Debug)]
102 fn index(&self, position
: Position
) -> usize {
104 Position
::BeforeScheme
=> 0,
106 Position
::AfterScheme
=> self.scheme_end
as usize,
108 Position
::BeforeUsername
=> if self.has_authority() {
109 self.scheme_end
as usize + "://".len()
111 debug_assert
!(self.byte_at(self.scheme_end
) == b'
:'
);
112 debug_assert
!(self.scheme_end
+ ":".len() as u32 == self.username_end
);
113 self.scheme_end
as usize + ":".len()
116 Position
::AfterUsername
=> self.username_end
as usize,
118 Position
::BeforePassword
=> if self.has_authority() &&
119 self.byte_at(self.username_end
) == b'
:'
{
120 self.username_end
as usize + ":".len()
122 debug_assert
!(self.username_end
== self.host_start
);
123 self.username_end
as usize
126 Position
::AfterPassword
=> if self.has_authority() &&
127 self.byte_at(self.username_end
) == b'
:'
{
128 debug_assert
!(self.byte_at(self.host_start
- "@".len() as u32) == b'@'
);
129 self.host_start
as usize - "@".len()
131 debug_assert
!(self.username_end
== self.host_start
);
132 self.host_start
as usize
135 Position
::BeforeHost
=> self.host_start
as usize,
137 Position
::AfterHost
=> self.host_end
as usize,
139 Position
::BeforePort
=> if self.port
.is_some() {
140 debug_assert
!(self.byte_at(self.host_end
) == b'
:'
);
141 self.host_end
as usize + ":".len()
143 self.host_end
as usize
146 Position
::AfterPort
=> self.path_start
as usize,
148 Position
::BeforePath
=> self.path_start
as usize,
150 Position
::AfterPath
=> match (self.query_start
, self.fragment_start
) {
151 (Some(q
), _
) => q
as usize,
152 (None
, Some(f
)) => f
as usize,
153 (None
, None
) => self.serialization
.len(),
156 Position
::BeforeQuery
=> match (self.query_start
, self.fragment_start
) {
158 debug_assert
!(self.byte_at(q
) == b'?'
);
159 q
as usize + "?".len()
161 (None
, Some(f
)) => f
as usize,
162 (None
, None
) => self.serialization
.len(),
165 Position
::AfterQuery
=> match self.fragment_start
{
166 None
=> self.serialization
.len(),
167 Some(f
) => f
as usize,
170 Position
::BeforeFragment
=> match self.fragment_start
{
172 debug_assert
!(self.byte_at(f
) == b'
#');
173 f
as usize + "#".len()
175 None
=> self.serialization
.len(),
178 Position
::AfterFragment
=> self.serialization
.len(),