Skip to content

Commit

Permalink
Made most of the URL functions pure.
Browse files Browse the repository at this point in the history
This closes rust-lang#3782.
  • Loading branch information
jesse99 committed Nov 17, 2012
1 parent b4f802e commit 7720531
Showing 1 changed file with 40 additions and 34 deletions.
74 changes: 40 additions & 34 deletions src/libstd/net_url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ type UserInfo = {

pub type Query = ~[(~str, ~str)];

pub fn Url(scheme: ~str, user: Option<UserInfo>, host: ~str,
pub pure fn Url(scheme: ~str, user: Option<UserInfo>, host: ~str,
port: Option<~str>, path: ~str, query: Query,
fragment: Option<~str>) -> Url {
Url { scheme: move scheme, user: move user, host: move host,
port: move port, path: move path, query: move query,
fragment: move fragment }
}

fn UserInfo(user: ~str, pass: Option<~str>) -> UserInfo {
pure fn UserInfo(user: ~str, pass: Option<~str>) -> UserInfo {
{user: move user, pass: move pass}
}

Expand Down Expand Up @@ -84,8 +84,9 @@ fn encode_inner(s: &str, full_url: bool) -> ~str {
*
* This function is compliant with RFC 3986.
*/
pub fn encode(s: &str) -> ~str {
encode_inner(s, true)
pub pure fn encode(s: &str) -> ~str {
// unsafe only because encode_inner does (string) IO
unsafe {encode_inner(s, true)}
}

/**
Expand All @@ -95,8 +96,9 @@ pub fn encode(s: &str) -> ~str {
* This function is compliant with RFC 3986.
*/

pub fn encode_component(s: &str) -> ~str {
encode_inner(s, false)
pub pure fn encode_component(s: &str) -> ~str {
// unsafe only because encode_inner does (string) IO
unsafe {encode_inner(s, false)}
}

fn decode_inner(s: &str, full_url: bool) -> ~str {
Expand Down Expand Up @@ -142,15 +144,17 @@ fn decode_inner(s: &str, full_url: bool) -> ~str {
*
* This will only decode escape sequences generated by encode_uri.
*/
pub fn decode(s: &str) -> ~str {
decode_inner(s, true)
pub pure fn decode(s: &str) -> ~str {
// unsafe only because decode_inner does (string) IO
unsafe {decode_inner(s, true)}
}

/**
* Decode a string encoded with percent encoding.
*/
pub fn decode_component(s: &str) -> ~str {
decode_inner(s, false)
pub pure fn decode_component(s: &str) -> ~str {
// unsafe only because decode_inner does (string) IO
unsafe {decode_inner(s, false)}
}

fn encode_plus(s: &str) -> ~str {
Expand Down Expand Up @@ -264,19 +268,21 @@ pub fn decode_form_urlencoded(s: ~[u8]) ->
}


fn split_char_first(s: &str, c: char) -> (~str, ~str) {
pure fn split_char_first(s: &str, c: char) -> (~str, ~str) {
let len = str::len(s);
let mut index = len;
let mut mat = 0;
do io::with_str_reader(s) |rdr| {
let mut ch : char;
while !rdr.eof() {
ch = rdr.read_byte() as char;
if ch == c {
// found a match, adjust markers
index = rdr.tell()-1;
mat = 1;
break;
unsafe {
do io::with_str_reader(s) |rdr| {
let mut ch : char;
while !rdr.eof() {
ch = rdr.read_byte() as char;
if ch == c {
// found a match, adjust markers
index = rdr.tell()-1;
mat = 1;
break;
}
}
}
}
Expand All @@ -288,7 +294,7 @@ fn split_char_first(s: &str, c: char) -> (~str, ~str) {
}
}

fn userinfo_from_str(uinfo: &str) -> UserInfo {
pure fn userinfo_from_str(uinfo: &str) -> UserInfo {
let (user, p) = split_char_first(uinfo, ':');
let pass = if str::len(p) == 0 {
option::None
Expand All @@ -315,12 +321,12 @@ impl UserInfo : Eq {
pure fn ne(other: &UserInfo) -> bool { !self.eq(other) }
}

fn query_from_str(rawquery: &str) -> Query {
pure fn query_from_str(rawquery: &str) -> Query {
let mut query: Query = ~[];
if str::len(rawquery) != 0 {
for str::split_char(rawquery, '&').each |p| {
let (k, v) = split_char_first(*p, '=');
query.push((decode_component(k), decode_component(v)));
unsafe {query.push((decode_component(k), decode_component(v)));}
};
}
return query;
Expand All @@ -340,7 +346,7 @@ pub pure fn query_to_str(query: Query) -> ~str {
}
// returns the scheme and the rest of the url, or a parsing error
pub fn get_scheme(rawurl: &str) -> result::Result<(~str, ~str), @~str> {
pub pure fn get_scheme(rawurl: &str) -> result::Result<(~str, ~str), @~str> {
for str::each_chari(rawurl) |i,c| {
match c {
'A' .. 'Z' | 'a' .. 'z' => loop,
Expand Down Expand Up @@ -387,7 +393,7 @@ impl Input : Eq {
}

// returns userinfo, host, port, and unparsed part, or an error
fn get_authority(rawurl: &str) ->
pure fn get_authority(rawurl: &str) ->
result::Result<(Option<UserInfo>, ~str, Option<~str>, ~str), @~str> {
if !str::starts_with(rawurl, ~"//") {
// there is no authority.
Expand Down Expand Up @@ -517,7 +523,7 @@ fn get_authority(rawurl: &str) ->

let end = end; // make end immutable so it can be captured

let host_is_end_plus_one: &fn() -> bool = || {
let host_is_end_plus_one: &pure fn() -> bool = || {
end+1 == len
&& !['?', '#', '/'].contains(&(rawurl[end] as char))
};
Expand Down Expand Up @@ -556,7 +562,7 @@ fn get_authority(rawurl: &str) ->


// returns the path and unparsed part of url, or an error
fn get_path(rawurl: &str, authority : bool) ->
pure fn get_path(rawurl: &str, authority : bool) ->
result::Result<(~str, ~str), @~str> {
let len = str::len(rawurl);
let mut end = len;
Expand Down Expand Up @@ -587,7 +593,7 @@ fn get_path(rawurl: &str, authority : bool) ->
}

// returns the parsed query and the fragment, if present
fn get_query_fragment(rawurl: &str) ->
pure fn get_query_fragment(rawurl: &str) ->
result::Result<(Query, Option<~str>), @~str> {
if !str::starts_with(rawurl, ~"?") {
if str::starts_with(rawurl, ~"#") {
Expand Down Expand Up @@ -619,42 +625,42 @@ fn get_query_fragment(rawurl: &str) ->
*
*/
pub fn from_str(rawurl: &str) -> result::Result<Url, ~str> {
pub pure fn from_str(rawurl: &str) -> result::Result<Url, ~str> {
// scheme
let mut schm = get_scheme(rawurl);
if result::is_err(&schm) {
return result::Err(copy *result::get_err(&schm));
}
let (scheme, rest) = result::unwrap(schm);
let (scheme, rest) = schm.get();
// authority
let mut auth = get_authority(rest);
if result::is_err(&auth) {
return result::Err(copy *result::get_err(&auth));
}
let (userinfo, host, port, rest) = result::unwrap(auth);
let (userinfo, host, port, rest) = auth.get();
// path
let has_authority = if host == ~"" { false } else { true };
let mut pth = get_path(rest, has_authority);
if result::is_err(&pth) {
return result::Err(copy *result::get_err(&pth));
}
let (path, rest) = result::unwrap(pth);
let (path, rest) = pth.get();

// query and fragment
let mut qry = get_query_fragment(rest);
if result::is_err(&qry) {
return result::Err(copy *result::get_err(&qry));
}
let (query, fragment) = result::unwrap(qry);
let (query, fragment) = qry.get();

return result::Ok(Url(scheme, userinfo, host,
port, path, query, fragment));
}

impl Url : FromStr {
static fn from_str(s: &str) -> Option<Url> {
static pure fn from_str(s: &str) -> Option<Url> {
match from_str(s) {
Ok(move url) => Some(url),
Err(_) => None
Expand Down

0 comments on commit 7720531

Please sign in to comment.