<commit_before>extern crate html5ever;
extern crate regex;
extern crate hyper;
extern crate string_cache;

use self::html5ever::sink::common::{Document, Doctype, Text, Comment, Element};
use self::html5ever::sink::rcdom::{RcDom, Handle};
use self::html5ever::{parse, one_input, Attribute};
use std::default::Default;
use std::io::Read;

use self::regex::Regex;
use self::hyper::Client;
use self::hyper::header::Connection;
use self::hyper::header::ConnectionOption;

use self::string_cache::namespace::{QualName, Namespace};
use self::string_cache::atom::Atom;

use Provider;
use Track;

pub fn extract_tracks(url: &str) -> Vec<Track> {
    let mut client = Client::new();
     let mut res = client.get(url)
                         .header(Connection(vec![ConnectionOption::Close]))
                         .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let dom: RcDom = parse(one_input(body), Default::default());
    let mut tracks  = Vec::new();
    walk(0, dom.document, &mut tracks);
    return tracks
}

// This is not proper HTML serialization, of course.
fn walk(indent: usize, handle: Handle, tracks: &mut Vec<Track>) {
    let node = handle.borrow();
    match node.node {
        Document         => (),
        Doctype(_, _, _) => (),
        Text(_)          => (),
        Comment(_)       => (),
        Element(ref name, ref attrs) => {
            let tag_name = name.local.as_slice();
            match extract_track(tag_name, attrs) {
                Some(track) => (*tracks).push(track),
                None => {}
            }
        }
    }
    for child in node.children.iter() {
        walk(indent+4, child.clone(), tracks);
    }
}

pub fn extract_track(tag_name: &str, attrs: &Vec<Attribute>) -> Option<Track> {
    if tag_name == "iframe" {
        for attr in attrs.iter() {
            match Regex::new(r"www.youtube.com/embed") {
                Ok(re) =>
                    if re.is_match(&attr.value) {
                        match Regex::new(r"www.youtube.com/embed/(.+)") {
                            Ok(re) => {
                                let cap = re.captures(&attr.value).unwrap();
                                let strs: Vec<&str> = cap.at(1).unwrap().split_str('?').collect();
                                return Some(Track {
                                           id: 0,
                                     provider: Provider::YouTube,
                                        title: strs[0].to_string(),
                                          url: attr.value.to_string(),
                                   identifier: strs[0].to_string()
                                })
                            },
                            Err(_) =>
                                return None
                        }
                    },
                Err(_) =>
                    return None
            };
            match Regex::new(r"api.soundcloud.com/tracks/") {
                Ok(re) =>
                    if re.is_match(&attr.value) {
/*                        println!("SoundCloud {}=\"{}\"",
                                 attr.name.local.as_slice(),
                                 attr.value);*/
                        match Regex::new(r"api.soundcloud.com/tracks/(.+)") {
                            Ok(re) => {
                                let cap = re.captures(&attr.value).unwrap();
                                let strs: Vec<&str> = cap.at(1).unwrap().split_str('&').collect();
//                                println!("id: {} ", strs[0]);
                                return Some(Track {
                                           id: 0,
                                     provider: Provider::SoundCloud,
                                        title: strs[0].to_string(),
                                          url: attr.value.to_string(),
                                   identifier: strs[0].to_string()
                                })
                            },
                            Err(_) =>
                                return None
                        }
                    },
                Err(_) =>
                    return None
            };
        }
    } else if tag_name == "a" {
        for attr in attrs.iter() {
            let href = QualName {
                   ns: Namespace(string_cache::atom::Atom::from_slice("")),
                local: string_cache::atom::Atom::from_slice("href")
            };
            if attr.name == href {
                match Regex::new(r"www.youtube.com/watch\?v=(.+)") {
                    Ok(re) => match re.captures(&attr.value) {
                        Some(cap) => match cap.at(1) {
                            Some(str) => {
                                let strs: Vec<&str> = str.split_str('?').collect();
                                return Some(Track {
                                            id: 0,
                                      provider: Provider::YouTube,
                                         title: strs[0].to_string(),
                                           url: attr.value.to_string(),
                                    identifier: strs[0].to_string()
                                })
                            },
                            None => ()
                        },
                        None => ()
                    },
                    Err(_) => ()
                }
            }
        }
    }
    return None
}
<commit_msg>Refactoring: Remove unused regex match<commit_after>extern crate html5ever;
extern crate regex;
extern crate hyper;
extern crate string_cache;

use self::html5ever::sink::common::{Document, Doctype, Text, Comment, Element};
use self::html5ever::sink::rcdom::{RcDom, Handle};
use self::html5ever::{parse, one_input, Attribute};
use std::default::Default;
use std::io::Read;

use self::regex::Regex;
use self::hyper::Client;
use self::hyper::header::Connection;
use self::hyper::header::ConnectionOption;

use self::string_cache::namespace::{QualName, Namespace};
use self::string_cache::atom::Atom;

use Provider;
use Track;

pub fn extract_tracks(url: &str) -> Vec<Track> {
    let mut client = Client::new();
     let mut res = client.get(url)
                         .header(Connection(vec![ConnectionOption::Close]))
                         .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let dom: RcDom = parse(one_input(body), Default::default());
    let mut tracks  = Vec::new();
    walk(0, dom.document, &mut tracks);
    return tracks
}

// This is not proper HTML serialization, of course.
fn walk(indent: usize, handle: Handle, tracks: &mut Vec<Track>) {
    let node = handle.borrow();
    match node.node {
        Document         => (),
        Doctype(_, _, _) => (),
        Text(_)          => (),
        Comment(_)       => (),
        Element(ref name, ref attrs) => {
            let tag_name = name.local.as_slice();
            match extract_track(tag_name, attrs) {
                Some(track) => (*tracks).push(track),
                None => {}
            }
        }
    }
    for child in node.children.iter() {
        walk(indent+4, child.clone(), tracks);
    }
}

pub fn extract_track(tag_name: &str, attrs: &Vec<Attribute>) -> Option<Track> {
    if tag_name == "iframe" {
        for attr in attrs.iter() {
            match Regex::new(r"www.youtube.com/embed/(.+)") {
                Ok(re) => match re.captures(&attr.value) {
                    Some(cap) => match (cap.at(1)) {
                        Some(str) => {
                            let strs: Vec<&str> = str.split_str('?').collect();
                            return Some(Track {
                                        id: 0,
                                  provider: Provider::YouTube,
                                     title: strs[0].to_string(),
                                       url: attr.value.to_string(),
                                identifier: strs[0].to_string()
                            })
                        },
                        None => ()
                    },
                    None => ()
                },
                Err(_) => ()
            };
            match Regex::new(r"api.soundcloud.com/tracks/(.+)") {
                Ok(re) => match re.captures(&attr.value) {
                    Some(cap) => match cap.at(1) {
                        Some(str) => {
                            let strs: Vec<&str> = str.split_str('&').collect();
                            return Some(Track {
                                        id: 0,
                                  provider: Provider::SoundCloud,
                                     title: strs[0].to_string(),
                                       url: attr.value.to_string(),
                                identifier: strs[0].to_string()
                            })
                        },
                        None => ()
                    }
                },
                Err(_) => ()
            };
        }
    } else if tag_name == "a" {
        for attr in attrs.iter() {
            let href = QualName {
                   ns: Namespace(string_cache::atom::Atom::from_slice("")),
                local: string_cache::atom::Atom::from_slice("href")
            };
            if attr.name == href {
                match Regex::new(r"www.youtube.com/watch\?v=(.+)") {
                    Ok(re) => match re.captures(&attr.value) {
                        Some(cap) => match cap.at(1) {
                            Some(str) => {
                                let strs: Vec<&str> = str.split_str('?').collect();
                                return Some(Track {
                                            id: 0,
                                      provider: Provider::YouTube,
                                         title: strs[0].to_string(),
                                           url: attr.value.to_string(),
                                    identifier: strs[0].to_string()
                                })
                            },
                            None => ()
                        },
                        None => ()
                    },
                    Err(_) => ()
                }
            }
        }
    }
    return None
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Comments for configuration + injection into output .toml
use std::collections::HashMap;

/// maps entries to Comments that should precede them
fn comments() -> HashMap<String, String> {
	let mut retval = HashMap::new();
	retval.insert(
		"[server]".to_string(),
		"
# Generated Server Configuration File for Grin
#
# When running the grin executable without specifying any command line
# arguments, it will look for this file in two places, in the following
# order:
#
# -The working directory
# -[user home]/.grin
#

#########################################
### SERVER CONFIGURATION              ###
#########################################

#Server connection details
"
		.to_string(),
	);

	retval.insert(
		"api_http_addr".to_string(),
		"
#path of TLS certificate file, self-signed certificates are not supported
#tls_certificate_file = \"\"
#private key for the TLS certificate
#tls_certificate_key = \"\"

#the address on which services will listen, e.g. Transaction Pool
"
		.to_string(),
	);

	retval.insert(
		"api_secret_path".to_string(),
		"
#path of the secret token used by the API to authenticate the calls
#comment the it to disable basic auth
"
		.to_string(),
	);

	retval.insert(
		"db_root".to_string(),
		"
#the directory, relative to current, in which the grin blockchain
#is stored
"
		.to_string(),
	);

	retval.insert(
		"chain_type".to_string(),
		"
#The chain type, which defines the genesis block and the set of cuckoo
#parameters used for mining as well as wallet output coinbase maturity. Can be:
#AutomatedTesting - For CI builds and instant blockchain creation
#UserTesting - For regular user testing (cuckoo 16)
#Floonet - For the long term floonet test network
#Mainnet - For mainnet
"
		.to_string(),
	);

	retval.insert(
		"chain_validation_mode".to_string(),
		"
#the chain validation mode, defines how often (if at all) we
#want to run a full chain validation. Can be:
#\"EveryBlock\" - run full chain validation when processing each block (except during sync)
#\"Disabled\" - disable full chain validation (just run regular block validation)
"
		.to_string(),
	);

	retval.insert(
		"archive_mode".to_string(),
		"
#run the node in \"full archive\" mode (default is fast-sync, pruned node)
"
		.to_string(),
	);

	retval.insert(
		"skip_sync_wait".to_string(),
		"
#skip waiting for sync on startup, (optional param, mostly for testing)
"
		.to_string(),
	);

	retval.insert(
		"run_tui".to_string(),
		"
#whether to run the ncurses TUI. Ncurses must be installed and this
#will also disable logging to stdout
"
		.to_string(),
	);

	retval.insert(
		"run_test_miner".to_string(),
		"
#Whether to run a test miner. This is only for developer testing (chaintype
#usertesting) at cuckoo 16, and will only mine into the default wallet port.
#real mining should use the standalone grin-miner
"
		.to_string(),
	);

	retval.insert(
		"[server.dandelion_config]".to_string(),
		"
#########################################
### DANDELION CONFIGURATION           ###
#########################################
"
		.to_string(),
	);

	retval.insert(
		"epoch_secs".to_string(),
		"
#dandelion epoch duration
"
		.to_string(),
	);

	retval.insert(
		"aggregation_secs".to_string(),
		"
#dandelion aggregation period in secs
"
		.to_string(),
	);

	retval.insert(
		"embargo_secs".to_string(),
		"
#fluff and broadcast after embargo expires if tx not seen on network
"
		.to_string(),
	);

	retval.insert(
		"stem_probability".to_string(),
		"
#dandelion stem probability (stem 90% of the time, fluff 10% of the time)
"
		.to_string(),
	);

	retval.insert(
		"[server.p2p_config]".to_string(),
		"#test miner wallet URL (burns if this doesn't exist)
#test_miner_wallet_url = \"http://127.0.0.1:3415\"

#########################################
### SERVER P2P CONFIGURATION          ###
#########################################
#The P2P server details (i.e. the server that communicates with other
"
		.to_string(),
	);

	retval.insert(
		"host".to_string(),
		"
#The interface on which to listen.
#0.0.0.0 will listen on all interfaces, allowing others to interact
#127.0.0.1 will listen on the local machine only
"
		.to_string(),
	);

	retval.insert(
		"port".to_string(),
		"
#The port on which to listen.
"
		.to_string(),
	);

	retval.insert(
		"seeding_type".to_string(),
		"
#how to seed this server, can be None, List or DNSSeed
"
		.to_string(),
	);

	retval.insert(
		"[server.p2p_config.capabilities]".to_string(),
		"#If the seeding type is List, the list of peers to connect to can
#be specified as follows:
#seeds = [\"192.168.0.1:3414\",\"192.168.0.2:3414\"]

#hardcoded peer lists for allow/deny
#will *only* connect to peers in allow list
#peers_allow = [\"192.168.0.1:3414\", \"192.168.0.2:3414\"]
#will *never* connect to peers in deny list
#peers_deny = [\"192.168.0.3:3414\", \"192.168.0.4:3414\"]
#a list of preferred peers to connect to
#peers_preferred = [\"192.168.0.1:3414\",\"192.168.0.2:3414\"]

#how long a banned peer should stay banned
#ban_window = 10800

#maximum number of peers
#peer_max_count = 125

#preferred minimum number of peers (we'll actively keep trying to add peers
#until we get to at least this number
#peer_min_preferred_count = 8

# 15 = Bit flags for FULL_NODE
#This structure needs to be changed internally, to make it more configurable

# A preferred dandelion_peer, mainly used for testing dandelion
# dandelion_peer = \"10.0.0.1:13144\"

"
		.to_string(),
	);

	retval.insert(
		"[server.pool_config]".to_string(),
		"
#########################################
### MEMPOOL CONFIGURATION             ###
#########################################
"
		.to_string(),
	);

	retval.insert(
		"accept_fee_base".to_string(),
		"
#base fee that's accepted into the pool
"
		.to_string(),
	);

	retval.insert(
		"max_pool_size".to_string(),
		"
#maximum number of transactions allowed in the pool
"
		.to_string(),
	);

	retval.insert(
		"max_stempool_size".to_string(),
		"
#maximum number of transactions allowed in the stempool
"
		.to_string(),
	);

	retval.insert(
		"mineable_max_weight".to_string(),
		"
#maximum total weight of transactions that can get selected to build a block
"
		.to_string(),
	);

	retval.insert(
		"[server.stratum_mining_config]".to_string(),
		"
################################################
### STRATUM MINING SERVER CONFIGURATION      ###
################################################
"
		.to_string(),
	);

	retval.insert(
		"enable_stratum_server".to_string(),
		"
#whether stratum server is enabled
"
		.to_string(),
	);

	retval.insert(
		"stratum_server_addr".to_string(),
		"
#what port and address for the stratum server to listen on
"
		.to_string(),
	);

	retval.insert(
		"attempt_time_per_block".to_string(),
		"
#the amount of time, in seconds, to attempt to mine on a particular
#header before stopping and re-collecting transactions from the pool
"
		.to_string(),
	);

	retval.insert(
		"minimum_share_difficulty".to_string(),
		"
#the minimum acceptable share difficulty to request from miners
"
		.to_string(),
	);

	retval.insert(
		"wallet_listener_url".to_string(),
		"
#the wallet receiver to which coinbase rewards will be sent
"
		.to_string(),
	);

	retval.insert(
		"burn_reward".to_string(),
		"
#whether to ignore the reward (mostly for testing)
"
		.to_string(),
	);

	retval.insert(
		"[logging]".to_string(),
		"
#########################################
### LOGGING CONFIGURATION             ###
#########################################
"
		.to_string(),
	);

	retval.insert(
		"log_to_stdout".to_string(),
		"
#whether to log to stdout
"
		.to_string(),
	);

	retval.insert(
		"stdout_log_level".to_string(),
		"
#log level for stdout: Error, Warning, Info, Debug, Trace
"
		.to_string(),
	);

	retval.insert(
		"log_to_file".to_string(),
		"
#whether to log to a file
"
		.to_string(),
	);

	retval.insert(
		"file_log_level".to_string(),
		"
#log level for file: Error, Warning, Info, Debug, Trace
"
		.to_string(),
	);

	retval.insert(
		"log_file_path".to_string(),
		"
#log file path
"
		.to_string(),
	);

	retval.insert(
		"log_file_append".to_string(),
		"
#whether to append to the log file (true), or replace it on every run (false)
"
		.to_string(),
	);

	retval.insert(
		"log_max_size".to_string(),
		"
#maximum log file size in bytes before performing log rotation
#comment it to disable log rotation
"
		.to_string(),
	);

	retval.insert(
		"log_max_files".to_string(),
		"
#maximum count of the log files to rotate over
"
		.to_string(),
	);

	retval
}

fn get_key(line: &str) -> String {
	if line.contains("[") && line.contains("]") {
		return line.to_owned();
	} else if line.contains("=") {
		return line.split("=").collect::<Vec<&str>>()[0].trim().to_owned();
	} else {
		return "NOT_FOUND".to_owned();
	}
}

pub fn insert_comments(orig: String) -> String {
	let comments = comments();
	let lines: Vec<&str> = orig.split("\n").collect();
	let mut out_lines = vec![];
	for l in lines {
		let key = get_key(l);
		if let Some(v) = comments.get(&key) {
			out_lines.push(v.to_owned());
		}
		out_lines.push(l.to_owned());
		out_lines.push("\n".to_owned());
	}
	let mut ret_val = String::from("");
	for l in out_lines {
		ret_val.push_str(&l);
	}
	ret_val.to_owned()
}
<commit_msg>Add commented webhook config (#2849)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Comments for configuration + injection into output .toml
use std::collections::HashMap;

/// maps entries to Comments that should precede them
fn comments() -> HashMap<String, String> {
	let mut retval = HashMap::new();
	retval.insert(
		"[server]".to_string(),
		"
# Generated Server Configuration File for Grin
#
# When running the grin executable without specifying any command line
# arguments, it will look for this file in two places, in the following
# order:
#
# -The working directory
# -[user home]/.grin
#

#########################################
### SERVER CONFIGURATION              ###
#########################################

#Server connection details
"
		.to_string(),
	);

	retval.insert(
		"api_http_addr".to_string(),
		"
#path of TLS certificate file, self-signed certificates are not supported
#tls_certificate_file = \"\"
#private key for the TLS certificate
#tls_certificate_key = \"\"

#the address on which services will listen, e.g. Transaction Pool
"
		.to_string(),
	);

	retval.insert(
		"api_secret_path".to_string(),
		"
#path of the secret token used by the API to authenticate the calls
#comment the it to disable basic auth
"
		.to_string(),
	);

	retval.insert(
		"db_root".to_string(),
		"
#the directory, relative to current, in which the grin blockchain
#is stored
"
		.to_string(),
	);

	retval.insert(
		"chain_type".to_string(),
		"
#The chain type, which defines the genesis block and the set of cuckoo
#parameters used for mining as well as wallet output coinbase maturity. Can be:
#AutomatedTesting - For CI builds and instant blockchain creation
#UserTesting - For regular user testing (cuckoo 16)
#Floonet - For the long term floonet test network
#Mainnet - For mainnet
"
		.to_string(),
	);

	retval.insert(
		"chain_validation_mode".to_string(),
		"
#the chain validation mode, defines how often (if at all) we
#want to run a full chain validation. Can be:
#\"EveryBlock\" - run full chain validation when processing each block (except during sync)
#\"Disabled\" - disable full chain validation (just run regular block validation)
"
		.to_string(),
	);

	retval.insert(
		"archive_mode".to_string(),
		"
#run the node in \"full archive\" mode (default is fast-sync, pruned node)
"
		.to_string(),
	);

	retval.insert(
		"skip_sync_wait".to_string(),
		"
#skip waiting for sync on startup, (optional param, mostly for testing)
"
		.to_string(),
	);

	retval.insert(
		"run_tui".to_string(),
		"
#whether to run the ncurses TUI. Ncurses must be installed and this
#will also disable logging to stdout
"
		.to_string(),
	);

	retval.insert(
		"run_test_miner".to_string(),
		"
#Whether to run a test miner. This is only for developer testing (chaintype
#usertesting) at cuckoo 16, and will only mine into the default wallet port.
#real mining should use the standalone grin-miner
"
		.to_string(),
	);

	retval.insert(
		"[server.webhook_config]".to_string(),
		"
#########################################
### WEBHOOK CONFIGURATION             ###
#########################################
"
		.to_string(),
	);

	retval.insert(
		"nthreads".to_string(),
		"
#The url where a POST request will be sent when a new block is accepted by our node.
#block_accepted_url = \"http://127.0.0.1:8080/acceptedblock\"

#The url where a POST request will be sent when a new transaction is received by a peer.
#tx_received_url = \"http://127.0.0.1:8080/tx\"

#The url where a POST request will be sent when a new header is received by a peer.
#header_received_url = \"http://127.0.0.1:8080/header\"

#The url where a POST request will be sent when a new block is received by a peer.
#block_received_url = \"http://127.0.0.1:8080/block\"

#The number of worker threads that will be assigned to making the http requests.
"
		.to_string(),
	);

	retval.insert(
		"timeout".to_string(),
		"
#The timeout of the http request in seconds.
"
		.to_string(),
	);

	retval.insert(
		"[server.dandelion_config]".to_string(),
		"
#########################################
### DANDELION CONFIGURATION           ###
#########################################
"
		.to_string(),
	);

	retval.insert(
		"epoch_secs".to_string(),
		"
#dandelion epoch duration
"
		.to_string(),
	);

	retval.insert(
		"aggregation_secs".to_string(),
		"
#dandelion aggregation period in secs
"
		.to_string(),
	);

	retval.insert(
		"embargo_secs".to_string(),
		"
#fluff and broadcast after embargo expires if tx not seen on network
"
		.to_string(),
	);

	retval.insert(
		"stem_probability".to_string(),
		"
#dandelion stem probability (stem 90% of the time, fluff 10% of the time)
"
		.to_string(),
	);

	retval.insert(
		"[server.p2p_config]".to_string(),
		"#test miner wallet URL (burns if this doesn't exist)
#test_miner_wallet_url = \"http://127.0.0.1:3415\"

#########################################
### SERVER P2P CONFIGURATION          ###
#########################################
#The P2P server details (i.e. the server that communicates with other
"
		.to_string(),
	);

	retval.insert(
		"host".to_string(),
		"
#The interface on which to listen.
#0.0.0.0 will listen on all interfaces, allowing others to interact
#127.0.0.1 will listen on the local machine only
"
		.to_string(),
	);

	retval.insert(
		"port".to_string(),
		"
#The port on which to listen.
"
		.to_string(),
	);

	retval.insert(
		"seeding_type".to_string(),
		"
#how to seed this server, can be None, List or DNSSeed
"
		.to_string(),
	);

	retval.insert(
		"[server.p2p_config.capabilities]".to_string(),
		"#If the seeding type is List, the list of peers to connect to can
#be specified as follows:
#seeds = [\"192.168.0.1:3414\",\"192.168.0.2:3414\"]

#hardcoded peer lists for allow/deny
#will *only* connect to peers in allow list
#peers_allow = [\"192.168.0.1:3414\", \"192.168.0.2:3414\"]
#will *never* connect to peers in deny list
#peers_deny = [\"192.168.0.3:3414\", \"192.168.0.4:3414\"]
#a list of preferred peers to connect to
#peers_preferred = [\"192.168.0.1:3414\",\"192.168.0.2:3414\"]

#how long a banned peer should stay banned
#ban_window = 10800

#maximum number of peers
#peer_max_count = 125

#preferred minimum number of peers (we'll actively keep trying to add peers
#until we get to at least this number
#peer_min_preferred_count = 8

# 15 = Bit flags for FULL_NODE
#This structure needs to be changed internally, to make it more configurable

# A preferred dandelion_peer, mainly used for testing dandelion
# dandelion_peer = \"10.0.0.1:13144\"

"
		.to_string(),
	);

	retval.insert(
		"[server.pool_config]".to_string(),
		"
#########################################
### MEMPOOL CONFIGURATION             ###
#########################################
"
		.to_string(),
	);

	retval.insert(
		"accept_fee_base".to_string(),
		"
#base fee that's accepted into the pool
"
		.to_string(),
	);

	retval.insert(
		"max_pool_size".to_string(),
		"
#maximum number of transactions allowed in the pool
"
		.to_string(),
	);

	retval.insert(
		"max_stempool_size".to_string(),
		"
#maximum number of transactions allowed in the stempool
"
		.to_string(),
	);

	retval.insert(
		"mineable_max_weight".to_string(),
		"
#maximum total weight of transactions that can get selected to build a block
"
		.to_string(),
	);

	retval.insert(
		"[server.stratum_mining_config]".to_string(),
		"
################################################
### STRATUM MINING SERVER CONFIGURATION      ###
################################################
"
		.to_string(),
	);

	retval.insert(
		"enable_stratum_server".to_string(),
		"
#whether stratum server is enabled
"
		.to_string(),
	);

	retval.insert(
		"stratum_server_addr".to_string(),
		"
#what port and address for the stratum server to listen on
"
		.to_string(),
	);

	retval.insert(
		"attempt_time_per_block".to_string(),
		"
#the amount of time, in seconds, to attempt to mine on a particular
#header before stopping and re-collecting transactions from the pool
"
		.to_string(),
	);

	retval.insert(
		"minimum_share_difficulty".to_string(),
		"
#the minimum acceptable share difficulty to request from miners
"
		.to_string(),
	);

	retval.insert(
		"wallet_listener_url".to_string(),
		"
#the wallet receiver to which coinbase rewards will be sent
"
		.to_string(),
	);

	retval.insert(
		"burn_reward".to_string(),
		"
#whether to ignore the reward (mostly for testing)
"
		.to_string(),
	);

	retval.insert(
		"[logging]".to_string(),
		"
#########################################
### LOGGING CONFIGURATION             ###
#########################################
"
		.to_string(),
	);

	retval.insert(
		"log_to_stdout".to_string(),
		"
#whether to log to stdout
"
		.to_string(),
	);

	retval.insert(
		"stdout_log_level".to_string(),
		"
#log level for stdout: Error, Warning, Info, Debug, Trace
"
		.to_string(),
	);

	retval.insert(
		"log_to_file".to_string(),
		"
#whether to log to a file
"
		.to_string(),
	);

	retval.insert(
		"file_log_level".to_string(),
		"
#log level for file: Error, Warning, Info, Debug, Trace
"
		.to_string(),
	);

	retval.insert(
		"log_file_path".to_string(),
		"
#log file path
"
		.to_string(),
	);

	retval.insert(
		"log_file_append".to_string(),
		"
#whether to append to the log file (true), or replace it on every run (false)
"
		.to_string(),
	);

	retval.insert(
		"log_max_size".to_string(),
		"
#maximum log file size in bytes before performing log rotation
#comment it to disable log rotation
"
		.to_string(),
	);

	retval.insert(
		"log_max_files".to_string(),
		"
#maximum count of the log files to rotate over
"
		.to_string(),
	);

	retval
}

fn get_key(line: &str) -> String {
	if line.contains("[") && line.contains("]") {
		return line.to_owned();
	} else if line.contains("=") {
		return line.split("=").collect::<Vec<&str>>()[0].trim().to_owned();
	} else {
		return "NOT_FOUND".to_owned();
	}
}

pub fn insert_comments(orig: String) -> String {
	let comments = comments();
	let lines: Vec<&str> = orig.split("\n").collect();
	let mut out_lines = vec![];
	for l in lines {
		let key = get_key(l);
		if let Some(v) = comments.get(&key) {
			out_lines.push(v.to_owned());
		}
		out_lines.push(l.to_owned());
		out_lines.push("\n".to_owned());
	}
	let mut ret_val = String::from("");
	for l in out_lines {
		ret_val.push_str(&l);
	}
	ret_val.to_owned()
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use vector::{distance3, dot3, Vec3f};

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

#[test]
fn test_segment_length() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 0, 0),
                           &vec3f(0, 0, 9));
    assert!(s.length() == 9.0);
}

#[test]
fn test_segment_distance_to_parametric_delta() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 1, 0),
                           &vec3f(0, 7, 0));
    assert!(s.distance_to_parametric_delta(0.0) == 0.0);
    assert!(s.distance_to_parametric_delta(6.0) == 1.0);
    assert!(s.distance_to_parametric_delta(12.0) == 2.0);
    assert!(s.distance_to_parametric_delta(-3.0) == -0.5);
}

#[test]
fn test_segment_closest_point_to_point() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(2, 0, 0),
                           &vec3f(3, 0, 0));
    assert!(s.closest_point_to_point(&vec3f(1, 0, 0)) ==
            (0.0, vec3f(2, 0, 0)));
    assert!(s.closest_point_to_point(&vec3f(4, 0, 0)) ==
            (1.0, vec3f(3, 0, 0)));
    assert!(s.closest_point_to_point(&vec3f(2.5, 1, 0)) ==
            (0.5, vec3f(2.5, 0, 0)));
}
<commit_msg>Add segment distance_from_parametric_delta<commit_after>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use vector::{distance3, dot3, Vec3f};

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

#[test]
fn test_segment_length() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 0, 0),
                           &vec3f(0, 0, 9));
    assert!(s.length() == 9.0);
}

#[test]
fn test_segment_distance_to_parametric_delta() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 1, 0),
                           &vec3f(0, 7, 0));
    assert!(s.distance_to_parametric_delta(0.0) == 0.0);
    assert!(s.distance_to_parametric_delta(6.0) == 1.0);
    assert!(s.distance_to_parametric_delta(12.0) == 2.0);
    assert!(s.distance_to_parametric_delta(-3.0) == -0.5);
}

#[test]
fn test_segment_closest_point_to_point() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(2, 0, 0),
                           &vec3f(3, 0, 0));
    assert!(s.closest_point_to_point(&vec3f(1, 0, 0)) ==
            (0.0, vec3f(2, 0, 0)));
    assert!(s.closest_point_to_point(&vec3f(4, 0, 0)) ==
            (1.0, vec3f(3, 0, 0)));
    assert!(s.closest_point_to_point(&vec3f(2.5, 1, 0)) ==
            (0.5, vec3f(2.5, 0, 0)));
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops;
use std::ops::{Range, RangeFrom, RangeTo, RangeFull};

use super::util;

// This is useful til the RangeArgument is made stable
trait FromRange {
    #[inline(always)]
    fn from_range(&self, seg: &Segment) -> (usize, usize);
}

impl FromRange for RangeFull {
    #[inline(always)]
    fn from_range(&self, seg: &Segment) -> (usize, usize) {
        return (0, seg.len());
    }
}

impl FromRange for Range<usize> {
    #[inline(always)]
    fn from_range(&self, _: &Segment) -> (usize, usize) {
        return (self.start, self.end);
    }
}

impl FromRange for RangeFrom<usize> {
    #[inline(always)]
    fn from_range(&self, seg: &Segment) -> (usize, usize) {
        return (self.start, seg.len());
    }
}

impl FromRange for RangeTo<usize> {
    #[inline(always)]
    fn from_range(&self, _: &Segment) -> (usize, usize) {
        return (0, self.end);
    }
}

pub struct Segment {
    vecs: Vec<Vec<u8>>,
    length: usize,
}

#[derive(Copy, Clone)]
struct Index {
    outer: usize,
    inner: usize,
}

pub struct Items<'a> {
    seg: &'a Segment,
    index: Index,
    num_elem: Option<usize>,
}

pub struct MutItems<'a> {
    seg: &'a mut Segment,
    index: Index,
    num_elem: Option<usize>,
}

pub struct Slices<'a> {
    seg: &'a Segment,
    outer: usize,
}

static MIN_BLOCK_SIZE: usize = 1024 * 1024;
static MAX_BLOCK_SIZE: usize = 4 * 1024 * 1024;

impl Segment {
    pub fn new() -> Segment {
        Segment {
            vecs: Vec::new(),
            length: 0,
        }
    }
    pub fn from_vec(values: Vec<u8>) -> Segment {
        let len = values.len();
        Segment {
            vecs: vec!(values),
            length: len,
        }
    }

    pub fn from_slice(values: &[u8]) -> Segment {
        Segment {
            vecs: vec!(values.into()),
            length: values.len(),
        }
    }

    pub fn len(&self) -> usize {
        self.length
    }

    fn calc_len(&mut self) {
        self.length = 0;
        for len in self.vecs.iter().map(|v| v.len()) {
            self.length += len
        }
    }

    fn pos_to_index(&self, pos: usize, for_insert: bool) -> Index {
        if pos == 0 {
            return Index { outer: 0, inner: 0 };
        }

        let mut cur_pos = pos;
        for (i, vec) in self.vecs.iter().enumerate() {
            if cur_pos < vec.len() || (for_insert && cur_pos == vec.len()) {
                return Index {
                    outer: i,
                    inner: cur_pos,
                }
            }
            cur_pos -= vec.len();
        }

        panic!("Position {} is out of bounds", pos);
    }

    pub fn iter_range<'a, R: FromRange>(&'a self, range: R) -> Items<'a> {
        let (from, to) = range.from_range(self);
        if to < from {
            panic!("to ({}) is smaller than from ({})!", to, from);
        }

        let idx = self.pos_to_index(from, false);
        Items {
            seg: self,
            index: idx,
            num_elem: Some(to - from),
        }
    }

    pub fn mut_iter_range<'a, R: FromRange>(&'a mut self, range: R) -> MutItems<'a> {
        let (from, to) = range.from_range(self);
        if to < from {
            panic!("to ({}) is smaller than from ({})!", to, from);
        }

        let idx = self.pos_to_index(from, false);
        MutItems {
            seg: self,
            index: idx,
            num_elem: Some(to - from),
        }
    }

    pub fn iter_slices<'a>(&'a self) -> Slices<'a> {
        Slices {
            seg: self,
            outer: 0,
        }
    }

    fn prepare_insert(&mut self, index: Index) -> Index {
        // TODO: Get self.vecs.get(index.outer) into a local variable without ruining lifetimes?
        if index.outer >= self.vecs.len() {
            self.vecs.push(Vec::new());
        }

        if self.vecs[index.outer].len() < MAX_BLOCK_SIZE {
            return index;
        }

        let page_start_idx = (index.inner / MIN_BLOCK_SIZE) * MIN_BLOCK_SIZE;
        if page_start_idx == 0 {
            if self.vecs[index.outer].len() > MAX_BLOCK_SIZE {
                let insert_vec: Vec < _ >= self.vecs[index.outer][MIN_BLOCK_SIZE..].into();
                self.vecs.insert(index.outer + 1, insert_vec);
                self.vecs[index.outer].truncate(MIN_BLOCK_SIZE);
            }

            return index;
        } else {
            let insert_vec: Vec<_> = self.vecs[index.outer][page_start_idx..].into();
            self.vecs.insert(index.outer + 1, insert_vec);
            self.vecs[index.outer].truncate(page_start_idx);
            return self.prepare_insert(Index {
                outer: index.outer + 1,
                inner: index.inner - page_start_idx
            })
        }
    }

    pub fn insert(&mut self, offset: usize, values: &[u8]) {
        let mut index = self.pos_to_index(offset, true);
        index = self.prepare_insert(index);

        // This is needed for the mut borrow vec
        {
            let vec = &mut self.vecs[index.outer];
            // TODO: There has to be a better way for this range
            for val in values.into_iter().rev() {
                vec.insert(index.inner, *val);
            }
        }

        self.calc_len();
    }

    // TODO: Convert to drain when that settles
    pub fn move_out_slice(&mut self, start_offset: usize, end_offset: usize) -> Vec<u8> {
        assert!(start_offset <= end_offset);
        let mut res = Vec::new();
        let mut index = self.pos_to_index(start_offset, false);
        let num_elem = end_offset - start_offset;

        for _ in 0..num_elem {
            let c = self.vecs[index.outer].remove(index.inner);
            res.push(c);

            if index.inner >= self.vecs[index.outer].len() {
                if self.vecs[index.outer].len() == 0 {
                    self.vecs.remove(index.outer);
                } else {
                    index.inner = 0;
                    index.outer += 1;
                }
            }
        }

        self.calc_len();

        res
    }

    pub fn find_slice(&self, needle: &[u8]) -> Option<usize> {
        self.find_slice_from(0, needle)
    }

    pub fn find_slice_from(&self, from: usize, needle: &[u8]) -> Option<usize> {
        for i in from..self.len() {
            if util::iter_equals(self.iter_range(i..i+needle.len()), needle.iter()) {
                return Some(i);
            }
        }
        None
    }

    #[cfg(test)]
    fn get_lengths(&self) -> Vec<usize> {
        self.vecs.iter().map(|v| v.len()).collect::<Vec<usize>>()
    }
}

impl ops::Index<usize> for Segment {
    type Output = u8;
    fn index<'a>(&'a self, _index: usize) -> &'a u8 {
        let idx = self.pos_to_index(_index, false);
        &self.vecs[idx.outer][idx.inner]
    }
}

impl ops::IndexMut<usize> for Segment {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut u8 {
        let idx = self.pos_to_index(_index, false);
        &mut self.vecs[idx.outer][idx.inner]
    }
}

impl fmt::Debug for Segment {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.vecs.fmt(f)
    }
}

impl<'a> Iterator for Items<'a> {
    type Item = &'a u8;
    fn next(&mut self) -> Option<&'a u8> {
        if self.index.outer >= self.seg.vecs.len() {
            return None;
        }
        if let Some(ref mut num_elem) = self.num_elem {
            if *num_elem <= 0 {
                return None;
            }
            *num_elem -= 1;
        }

        let elem = {
            let vv = &self.seg.vecs[self.index.outer];
            &vv[self.index.inner]
        };

        self.index.inner += 1;
        if self.index.inner >= self.seg.vecs[self.index.outer].len() {
            self.index.inner = 0;
            self.index.outer += 1;
        }

        Some(elem)
    }
}

impl<'a> Iterator for MutItems<'a> {
    type Item = &'a mut u8;
    fn next(&mut self) -> Option<&'a mut u8> {
        if self.index.outer >= self.seg.vecs.len() {
            return None;
        }
        if let Some(ref mut num_elem) = self.num_elem {
            if *num_elem <= 0 {
                return None;
            }
            *num_elem -= 1;
        }

        let elem_raw: *mut u8 = {
            let vv = &mut self.seg.vecs[self.index.outer];
            &mut vv[self.index.inner]
        };

        self.index.inner += 1;
        if self.index.inner >= self.seg.vecs[self.index.outer].len() {
            self.index.inner = 0;
            self.index.outer += 1;
        }

        Some(unsafe { &mut *elem_raw })
    }
}

impl<'a> Iterator for Slices<'a> {
    type Item = &'a [u8];
    fn next(&mut self) -> Option<&'a [u8]> {
        if self.outer >= self.seg.vecs.len() {
            None
        } else {
            let i = self.outer;
            self.outer += 1;
            Some(&self.seg.vecs[i])
        }
    }
}

#[test]
fn test_segment() {
    let mut s = Segment::from_slice(&[1, 2, 3, 4]);
    s.insert_slice(0, &[7, 7, 7, 7, 7]);
}
<commit_msg>Add some initial really basic tests to the segment<commit_after>use std::fmt;
use std::ops;
use std::ops::{Range, RangeFrom, RangeTo, RangeFull};

use super::util;

// This is useful til the RangeArgument is made stable
trait FromRange {
    #[inline(always)]
    fn from_range(&self, seg: &Segment) -> (usize, usize);
}

impl FromRange for RangeFull {
    #[inline(always)]
    fn from_range(&self, seg: &Segment) -> (usize, usize) {
        return (0, seg.len());
    }
}

impl FromRange for Range<usize> {
    #[inline(always)]
    fn from_range(&self, _: &Segment) -> (usize, usize) {
        return (self.start, self.end);
    }
}

impl FromRange for RangeFrom<usize> {
    #[inline(always)]
    fn from_range(&self, seg: &Segment) -> (usize, usize) {
        return (self.start, seg.len());
    }
}

impl FromRange for RangeTo<usize> {
    #[inline(always)]
    fn from_range(&self, _: &Segment) -> (usize, usize) {
        return (0, self.end);
    }
}

pub struct Segment {
    vecs: Vec<Vec<u8>>,
    length: usize,
}

#[derive(Copy, Clone)]
struct Index {
    outer: usize,
    inner: usize,
}

pub struct Items<'a> {
    seg: &'a Segment,
    index: Index,
    num_elem: Option<usize>,
}

pub struct MutItems<'a> {
    seg: &'a mut Segment,
    index: Index,
    num_elem: Option<usize>,
}

pub struct Slices<'a> {
    seg: &'a Segment,
    outer: usize,
}

static MIN_BLOCK_SIZE: usize = 1024 * 1024;
static MAX_BLOCK_SIZE: usize = 4 * 1024 * 1024;

impl Segment {
    pub fn new() -> Segment {
        Segment {
            vecs: Vec::new(),
            length: 0,
        }
    }
    pub fn from_vec(values: Vec<u8>) -> Segment {
        let len = values.len();
        Segment {
            vecs: vec!(values),
            length: len,
        }
    }

    pub fn from_slice(values: &[u8]) -> Segment {
        Segment {
            vecs: vec!(values.into()),
            length: values.len(),
        }
    }

    pub fn len(&self) -> usize {
        self.length
    }

    fn calc_len(&mut self) {
        self.length = 0;
        for len in self.vecs.iter().map(|v| v.len()) {
            self.length += len
        }
    }

    fn pos_to_index(&self, pos: usize, for_insert: bool) -> Index {
        if pos == 0 {
            return Index { outer: 0, inner: 0 };
        }

        let mut cur_pos = pos;
        for (i, vec) in self.vecs.iter().enumerate() {
            if cur_pos < vec.len() || (for_insert && cur_pos == vec.len()) {
                return Index {
                    outer: i,
                    inner: cur_pos,
                }
            }
            cur_pos -= vec.len();
        }

        panic!("Position {} is out of bounds", pos);
    }

    pub fn iter_range<'a, R: FromRange>(&'a self, range: R) -> Items<'a> {
        let (from, to) = range.from_range(self);
        if to < from {
            panic!("to ({}) is smaller than from ({})!", to, from);
        }

        let idx = self.pos_to_index(from, false);
        Items {
            seg: self,
            index: idx,
            num_elem: Some(to - from),
        }
    }

    pub fn mut_iter_range<'a, R: FromRange>(&'a mut self, range: R) -> MutItems<'a> {
        let (from, to) = range.from_range(self);
        if to < from {
            panic!("to ({}) is smaller than from ({})!", to, from);
        }

        let idx = self.pos_to_index(from, false);
        MutItems {
            seg: self,
            index: idx,
            num_elem: Some(to - from),
        }
    }

    pub fn iter_slices<'a>(&'a self) -> Slices<'a> {
        Slices {
            seg: self,
            outer: 0,
        }
    }

    fn prepare_insert(&mut self, index: Index) -> Index {
        // TODO: Get self.vecs.get(index.outer) into a local variable without ruining lifetimes?
        if index.outer >= self.vecs.len() {
            self.vecs.push(Vec::new());
        }

        if self.vecs[index.outer].len() < MAX_BLOCK_SIZE {
            return index;
        }

        let page_start_idx = (index.inner / MIN_BLOCK_SIZE) * MIN_BLOCK_SIZE;
        if page_start_idx == 0 {
            if self.vecs[index.outer].len() > MAX_BLOCK_SIZE {
                let insert_vec: Vec < _ >= self.vecs[index.outer][MIN_BLOCK_SIZE..].into();
                self.vecs.insert(index.outer + 1, insert_vec);
                self.vecs[index.outer].truncate(MIN_BLOCK_SIZE);
            }

            return index;
        } else {
            let insert_vec: Vec<_> = self.vecs[index.outer][page_start_idx..].into();
            self.vecs.insert(index.outer + 1, insert_vec);
            self.vecs[index.outer].truncate(page_start_idx);
            return self.prepare_insert(Index {
                outer: index.outer + 1,
                inner: index.inner - page_start_idx
            })
        }
    }

    pub fn insert(&mut self, offset: usize, values: &[u8]) {
        let mut index = self.pos_to_index(offset, true);
        index = self.prepare_insert(index);

        // This is needed for the mut borrow vec
        {
            let vec = &mut self.vecs[index.outer];
            // TODO: There has to be a better way for this range
            for val in values.into_iter().rev() {
                vec.insert(index.inner, *val);
            }
        }

        self.calc_len();
    }

    // TODO: Convert to drain when that settles
    pub fn move_out_slice(&mut self, start_offset: usize, end_offset: usize) -> Vec<u8> {
        assert!(start_offset <= end_offset);
        let mut res = Vec::new();
        let mut index = self.pos_to_index(start_offset, false);
        let num_elem = end_offset - start_offset;

        for _ in 0..num_elem {
            let c = self.vecs[index.outer].remove(index.inner);
            res.push(c);

            if index.inner >= self.vecs[index.outer].len() {
                if self.vecs[index.outer].len() == 0 {
                    self.vecs.remove(index.outer);
                } else {
                    index.inner = 0;
                    index.outer += 1;
                }
            }
        }

        self.calc_len();

        res
    }

    pub fn find_slice(&self, needle: &[u8]) -> Option<usize> {
        self.find_slice_from(0, needle)
    }

    pub fn find_slice_from(&self, from: usize, needle: &[u8]) -> Option<usize> {
        for i in from..self.len() {
            if util::iter_equals(self.iter_range(i..i+needle.len()), needle.iter()) {
                return Some(i);
            }
        }
        None
    }

    #[cfg(test)]
    fn get_lengths(&self) -> Vec<usize> {
        self.vecs.iter().map(|v| v.len()).collect::<Vec<usize>>()
    }
}

impl ops::Index<usize> for Segment {
    type Output = u8;
    fn index<'a>(&'a self, _index: usize) -> &'a u8 {
        let idx = self.pos_to_index(_index, false);
        &self.vecs[idx.outer][idx.inner]
    }
}

impl ops::IndexMut<usize> for Segment {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut u8 {
        let idx = self.pos_to_index(_index, false);
        &mut self.vecs[idx.outer][idx.inner]
    }
}

impl fmt::Debug for Segment {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.vecs.fmt(f)
    }
}

impl<'a> Iterator for Items<'a> {
    type Item = &'a u8;
    fn next(&mut self) -> Option<&'a u8> {
        if self.index.outer >= self.seg.vecs.len() {
            return None;
        }
        if let Some(ref mut num_elem) = self.num_elem {
            if *num_elem <= 0 {
                return None;
            }
            *num_elem -= 1;
        }

        let elem = {
            let vv = &self.seg.vecs[self.index.outer];
            &vv[self.index.inner]
        };

        self.index.inner += 1;
        if self.index.inner >= self.seg.vecs[self.index.outer].len() {
            self.index.inner = 0;
            self.index.outer += 1;
        }

        Some(elem)
    }
}

impl<'a> Iterator for MutItems<'a> {
    type Item = &'a mut u8;
    fn next(&mut self) -> Option<&'a mut u8> {
        if self.index.outer >= self.seg.vecs.len() {
            return None;
        }
        if let Some(ref mut num_elem) = self.num_elem {
            if *num_elem <= 0 {
                return None;
            }
            *num_elem -= 1;
        }

        let elem_raw: *mut u8 = {
            let vv = &mut self.seg.vecs[self.index.outer];
            &mut vv[self.index.inner]
        };

        self.index.inner += 1;
        if self.index.inner >= self.seg.vecs[self.index.outer].len() {
            self.index.inner = 0;
            self.index.outer += 1;
        }

        Some(unsafe { &mut *elem_raw })
    }
}

impl<'a> Iterator for Slices<'a> {
    type Item = &'a [u8];
    fn next(&mut self) -> Option<&'a [u8]> {
        if self.outer >= self.seg.vecs.len() {
            None
        } else {
            let i = self.outer;
            self.outer += 1;
            Some(&self.seg.vecs[i])
        }
    }
}

#[test]
fn test_small_segment() {
    let size = 1024;
    let mut seg = Segment::from_vec(vec![1, 2, 3, 4, 5]);
    assert_eq!(Some(4), seg.find_slice(&[5]));

    let seg_len = seg.len();
    seg.insert(seg_len/2, &vec![1 as u8; size]);

    assert_eq!(Some(size + 4), seg.find_slice(&[5]));
}

#[test]
fn test_large_segment() {
    let big_size = 4*1024*1024;
    let small_size = 1024;
    let mut seg = Segment::from_vec(vec![0; big_size]);

    seg.insert(big_size/2, &vec![1 as u8; small_size]);

    assert_eq!(Some(big_size/2 -1), seg.find_slice(&[0, 1]));

    // Make sure we actually tested a "split" version
    let seg_lengths = seg.get_lengths();
    assert_eq!(2, seg_lengths.len());
    let index = seg_lengths[0];
    let sentinal = 100;
    seg[index] = sentinal;
    seg[index+1] = sentinal +1;
    assert_eq!(Some(index), seg.find_slice(&[sentinal, sentinal+1]));
}
<|endoftext|>


<commit_before>//! `i686`'s Streaming SIMD Extensions 4a (SSE4a)

use core::mem;
use v128::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.x86.sse4a.extrq"]
    fn extrq(x: i64x2, y: i8x16) -> i64x2;
    #[link_name = "llvm.x86.sse4a.insertq"]
    fn insertq(x: i64x2, y: i64x2) -> i64x2;
    #[link_name = "llvm.x86.sse4a.movnt.sd"]
    fn movntsd(x: *mut f64, y: f64x2);
    #[link_name = "llvm.x86.sse4a.movnt.ss"]
    fn movntss(x: *mut f32, y: f32x4);
}

// FIXME(blocked on #248): _mm_extracti_si64(x, len, idx) // EXTRQ
// FIXME(blocked on #248): _mm_inserti_si64(x, y, len, idx) // INSERTQ

/// Extracts the bit range specified by `y` from the lower 64 bits of `x`.
///
/// The [13:8] bits of `y` specify the index of the bit-range to extract. The
/// [5:0] bits of `y` specify the length of the bit-range to extract. All other
/// bits are ignored.
///
/// If the length is zero, it is interpreted as `64`. If the length and index
/// are zero, the lower 64 bits of `x` are extracted.
///
/// If `length == 0 && index > 0` or `lenght + index > 64` the result is
/// undefined.
#[inline(always)]
#[target_feature = "+sse4a"]
#[cfg_attr(test, assert_instr(extrq))]
pub unsafe fn _mm_extract_si64(x: i64x2, y: i64x2) -> i64x2 {
    extrq(x, mem::transmute(y))
}

/// Inserts the `[length:0]` bits of `y` into `x` at `index`.
///
/// The bits of `y`:
///
/// - `[69:64]` specify the `length`,
/// - `[77:72]` specify the index.
///
/// If the `length` is zero it is interpreted as `64`. If `index + length > 64`
/// or `index > 0 && length == 0` the result is undefined.
#[inline(always)]
#[target_feature = "+sse4a"]
#[cfg_attr(test, assert_instr(insertq))]
pub unsafe fn _mm_insert_si64(x: i64x2, y: i64x2) -> i64x2 {
    insertq(x, mem::transmute(y))
}

/// Non-temporal store of `a.1` into `p`.
#[inline(always)]
#[target_feature = "+sse4a"]
#[cfg_attr(test, assert_instr(movntsd))]
pub unsafe fn _mm_stream_sd(p: *mut f64, a: f64x2) {
    movntsd(p, a);
}

/// Non-temporal store of `a.3` into `p`.
#[inline(always)]
#[target_feature = "+sse4a"]
#[cfg_attr(test, assert_instr(movntss))]
pub unsafe fn _mm_stream_ss(p: *mut f32, a: f32x4) {
    movntss(p, a);
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;
    use x86::i686::sse4a;
    use v128::*;

    #[simd_test = "sse4a"]
    unsafe fn _mm_extract_si64() {
        let b = 0b0110_0000_0000_i64;
        //        ^^^^ bit range extracted
        let x = i64x2::new(b, 0);
        let v = 0b001000___00___000100_i64;
        //        ^idx: 2^3 = 8 ^length = 2^2 = 4
        let y = i64x2::new(v, 0);
        let e = i64x2::new(0b0110_i64, 0);
        let r = sse4a::_mm_extract_si64(x, y);
        assert_eq!(r, e);
    }

    #[simd_test = "sse4a"]
    unsafe fn _mm_insert_si64() {
        let i = 0b0110_i64;
        //        ^^^^ bit range inserted
        let z = 0b1010_1010_1010i64;
        //        ^^^^ bit range replaced
        let e = 0b0110_1010_1010i64;
        //        ^^^^ replaced 1010 with 0110
        let x = i64x2::new(z, 0);
        let expected = i64x2::new(e, 0);
        let v = 0b001000___00___000100_i64;
        //        ^idx: 2^3 = 8 ^length = 2^2 = 4
        let y = i64x2::new(i, v);
        let r = sse4a::_mm_insert_si64(x, y);
        assert_eq!(r, expected);
    }

    #[repr(align(16))]
    struct MemoryF64 {
        data: [f64; 2],
    }

    #[simd_test = "sse4a"]
    unsafe fn _mm_stream_sd() {
        let mut mem = MemoryF64 {
            data: [1.0_f64, 2.0],
        };
        {
            let vals = &mut mem.data;
            let d = vals.as_mut_ptr();

            let x = f64x2::new(3.0, 4.0);

            sse4a::_mm_stream_sd(d, x);
        }
        assert_eq!(mem.data[0], 4.0);
        assert_eq!(mem.data[1], 2.0);
    }

    #[repr(align(16))]
    struct MemoryF32 {
        data: [f32; 4],
    }

    #[simd_test = "sse4a"]
    unsafe fn _mm_stream_ss() {
        let mut mem = MemoryF32 {
            data: [1.0_f32, 2.0, 3.0, 4.0],
        };
        {
            let vals = &mut mem.data;
            let d = vals.as_mut_ptr();

            let x = f32x4::new(5.0, 6.0, 7.0, 8.0);

            sse4a::_mm_stream_ss(d, x);
        }
        assert_eq!(mem.data[0], 8.0);
        assert_eq!(mem.data[1], 2.0);
        assert_eq!(mem.data[2], 3.0);
        assert_eq!(mem.data[3], 4.0);
    }
}
<commit_msg>fix sse4a _mm_stream_{ss, sd} tests and docs<commit_after>//! `i686`'s Streaming SIMD Extensions 4a (SSE4a)

use core::mem;
use v128::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.x86.sse4a.extrq"]
    fn extrq(x: i64x2, y: i8x16) -> i64x2;
    #[link_name = "llvm.x86.sse4a.insertq"]
    fn insertq(x: i64x2, y: i64x2) -> i64x2;
    #[link_name = "llvm.x86.sse4a.movnt.sd"]
    fn movntsd(x: *mut f64, y: f64x2);
    #[link_name = "llvm.x86.sse4a.movnt.ss"]
    fn movntss(x: *mut f32, y: f32x4);
}

// FIXME(blocked on #248): _mm_extracti_si64(x, len, idx) // EXTRQ
// FIXME(blocked on #248): _mm_inserti_si64(x, y, len, idx) // INSERTQ

/// Extracts the bit range specified by `y` from the lower 64 bits of `x`.
///
/// The [13:8] bits of `y` specify the index of the bit-range to extract. The
/// [5:0] bits of `y` specify the length of the bit-range to extract. All other
/// bits are ignored.
///
/// If the length is zero, it is interpreted as `64`. If the length and index
/// are zero, the lower 64 bits of `x` are extracted.
///
/// If `length == 0 && index > 0` or `lenght + index > 64` the result is
/// undefined.
#[inline(always)]
#[target_feature = "+sse4a"]
#[cfg_attr(test, assert_instr(extrq))]
pub unsafe fn _mm_extract_si64(x: i64x2, y: i64x2) -> i64x2 {
    extrq(x, mem::transmute(y))
}

/// Inserts the `[length:0]` bits of `y` into `x` at `index`.
///
/// The bits of `y`:
///
/// - `[69:64]` specify the `length`,
/// - `[77:72]` specify the index.
///
/// If the `length` is zero it is interpreted as `64`. If `index + length > 64`
/// or `index > 0 && length == 0` the result is undefined.
#[inline(always)]
#[target_feature = "+sse4a"]
#[cfg_attr(test, assert_instr(insertq))]
pub unsafe fn _mm_insert_si64(x: i64x2, y: i64x2) -> i64x2 {
    insertq(x, mem::transmute(y))
}

/// Non-temporal store of `a.0` into `p`.
#[inline(always)]
#[target_feature = "+sse4a"]
#[cfg_attr(test, assert_instr(movntsd))]
pub unsafe fn _mm_stream_sd(p: *mut f64, a: f64x2) {
    movntsd(p, a);
}

/// Non-temporal store of `a.0` into `p`.
#[inline(always)]
#[target_feature = "+sse4a"]
#[cfg_attr(test, assert_instr(movntss))]
pub unsafe fn _mm_stream_ss(p: *mut f32, a: f32x4) {
    movntss(p, a);
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;
    use x86::i686::sse4a;
    use v128::*;

    #[simd_test = "sse4a"]
    unsafe fn _mm_extract_si64() {
        let b = 0b0110_0000_0000_i64;
        //        ^^^^ bit range extracted
        let x = i64x2::new(b, 0);
        let v = 0b001000___00___000100_i64;
        //        ^idx: 2^3 = 8 ^length = 2^2 = 4
        let y = i64x2::new(v, 0);
        let e = i64x2::new(0b0110_i64, 0);
        let r = sse4a::_mm_extract_si64(x, y);
        assert_eq!(r, e);
    }

    #[simd_test = "sse4a"]
    unsafe fn _mm_insert_si64() {
        let i = 0b0110_i64;
        //        ^^^^ bit range inserted
        let z = 0b1010_1010_1010i64;
        //        ^^^^ bit range replaced
        let e = 0b0110_1010_1010i64;
        //        ^^^^ replaced 1010 with 0110
        let x = i64x2::new(z, 0);
        let expected = i64x2::new(e, 0);
        let v = 0b001000___00___000100_i64;
        //        ^idx: 2^3 = 8 ^length = 2^2 = 4
        let y = i64x2::new(i, v);
        let r = sse4a::_mm_insert_si64(x, y);
        assert_eq!(r, expected);
    }

    #[repr(align(16))]
    struct MemoryF64 {
        data: [f64; 2],
    }

    #[simd_test = "sse4a"]
    unsafe fn _mm_stream_sd() {
        let mut mem = MemoryF64 {
            data: [1.0_f64, 2.0],
        };
        {
            let vals = &mut mem.data;
            let d = vals.as_mut_ptr();

            let x = f64x2::new(3.0, 4.0);

            sse4a::_mm_stream_sd(d, x);
        }
        assert_eq!(mem.data[0], 3.0);
        assert_eq!(mem.data[1], 2.0);
    }

    #[repr(align(16))]
    struct MemoryF32 {
        data: [f32; 4],
    }

    #[simd_test = "sse4a"]
    unsafe fn _mm_stream_ss() {
        let mut mem = MemoryF32 {
            data: [1.0_f32, 2.0, 3.0, 4.0],
        };
        {
            let vals = &mut mem.data;
            let d = vals.as_mut_ptr();

            let x = f32x4::new(5.0, 6.0, 7.0, 8.0);

            sse4a::_mm_stream_ss(d, x);
        }
        assert_eq!(mem.data[0], 5.0);
        assert_eq!(mem.data[1], 2.0);
        assert_eq!(mem.data[2], 3.0);
        assert_eq!(mem.data[3], 4.0);
    }
}
<|endoftext|>


<commit_before>extern crate path_slash;
extern crate url;

use crate::env::EnvConfig;
use crate::error::{Error, Result};
use crate::page::{DiffOp, Line, Page};
use url::Url;

#[cfg(target_os = "windows")]
fn to_slash<S: AsRef<str>>(s: &S) -> String {
    use path_slash::PathExt;
    use std::path::Path;
    Path::new(s.as_ref()).to_slash_lossy()
}

// Do nothing on Windows
#[cfg(not(target_os = "windows"))]
fn to_slash<S: AsRef<str>>(s: &S) -> &str {
    s.as_ref()
}

fn build_github_like_url(
    host: &str,
    user: &str,
    repo: &str,
    branch: &Option<String>,
    page: &Page,
) -> String {
    match page {
        Page::Open => {
            if let Some(ref b) = branch {
                format!("https://{}/{}/{}/tree/{}", host, user, repo, b)
            } else {
                format!("https://{}/{}/{}", host, user, repo)
            }
        }
        Page::Diff {
            ref lhs,
            ref rhs,
            ref op,
        } => format!(
            "https://{}/{}/{}/compare/{}{}{}",
            host, user, repo, lhs, op, rhs,
        ),
        Page::Commit { ref hash } => format!("https://{}/{}/{}/commit/{}", host, user, repo, hash),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: None,
        } => format!(
            "https://{}/{}/{}/blob/{}/{}",
            host,
            user,
            repo,
            hash,
            to_slash(relative_path),
        ),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: Some(Line::At(line)),
        } => format!(
            "https://{}/{}/{}/blob/{}/{}#L{}",
            host,
            user,
            repo,
            hash,
            to_slash(relative_path),
            line,
        ),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: Some(Line::Range(start, end)),
        } => format!(
            "https://{}/{}/{}/blob/{}/{}#L{}-L{}",
            host,
            user,
            repo,
            hash,
            to_slash(relative_path),
            start,
            end,
        ),
        Page::Issue { number } => format!("https://{}/{}/{}/issues/{}", host, user, repo, number),
    }
}

fn build_custom_github_like_url(
    host: &str,
    user: &str,
    repo: &str,
    branch: &Option<String>,
    page: &Page,
    ssh_port: &Option<u16>,
) -> String {
    match ssh_port {
        Some(ref p) => build_github_like_url(
            &format!("{}:{}", host, p).as_str(),
            user,
            repo,
            branch,
            page,
        ),
        _ => build_github_like_url(host, user, repo, branch, page),
    }
}

fn build_gitlab_url(
    host: &str,
    user: &str,
    repo: &str,
    branch: &Option<String>,
    page: &Page,
) -> Result<String> {
    if let Page::Diff { op, .. } = page {
        if *op == DiffOp::TwoDots {
            return Err(Error::GitLabDiffNotSupported);
        }
    }
    Ok(build_github_like_url(host, user, repo, branch, page))
}

fn build_bitbucket_url(
    user: &str,
    repo: &str,
    branch: &Option<String>,
    page: &Page,
) -> Result<String> {
    match page {
        Page::Open => {
            if let Some(ref b) = branch {
                Ok(format!(
                    "https://bitbucket.org/{}/{}/branch/{}",
                    user, repo, b,
                ))
            } else {
                Ok(format!("https://bitbucket.org/{}/{}", user, repo))
            }
        }
        Page::Diff { .. } => Err(Error::BitbucketDiffNotSupported),
        Page::Commit { ref hash } => Ok(format!(
            "https://bitbucket.org/{}/{}/commits/{}",
            user, repo, hash,
        )),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: None,
        } => Ok(format!(
            "https://bitbucket.org/{}/{}/src/{}/{}",
            user,
            repo,
            hash,
            to_slash(relative_path),
        )),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: Some(Line::At(line)),
        } => Ok(format!(
            "https://bitbucket.org/{}/{}/src/{}/{}#lines-{}",
            user,
            repo,
            hash,
            to_slash(relative_path),
            line,
        )),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: Some(Line::Range(start, end)),
        } => Ok(format!(
            "https://bitbucket.org/{}/{}/src/{}/{}#lines-{}:{}",
            user,
            repo,
            hash,
            to_slash(relative_path),
            start,
            end,
        )),
        Page::Issue { number } => Ok(format!(
            "https://bitbucket.org/{}/{}/issues/{}",
            user, repo, number,
        )),
    }
}

// Note: Parse '/user/repo.git' or '/user/repo' or 'user/repo' into 'user' and 'repo'
pub fn slug_from_path<'a>(path: &'a str) -> Result<(&'a str, &'a str)> {
    let mut split = path.split('/').skip_while(|s| s.is_empty());
    let user = split.next().ok_or_else(|| Error::NoUserInPath {
        path: path.to_string(),
    })?;
    let mut repo = split.next().ok_or_else(|| Error::NoRepoInPath {
        path: path.to_string(),
    })?;
    if repo.ends_with(".git") {
        // Slice '.git' from 'repo.git'
        repo = &repo[0..repo.len() - 4];
    }
    Ok((user, repo))
}

// Known URL formats
//  1. https://hosting_service.com/user/repo.git
//  2. git@hosting_service.com:user/repo.git (-> ssh://git@hosting_service.com:22/user/repo.git)
pub fn build_page_url(
    repo: &str,
    page: &Page,
    branch: &Option<String>,
    env: &EnvConfig,
) -> Result<String> {
    let url = Url::parse(repo).map_err(|e| Error::BrokenUrl {
        url: repo.to_string(),
        msg: format!("{}", e),
    })?;
    let path = url.path();
    let (user, repo_name) = slug_from_path(path)?;
    let host = url.host_str().ok_or_else(|| Error::BrokenUrl {
        url: repo.to_string(),
        msg: "No host in URL".to_string(),
    })?;
    match host {
        "github.com" => Ok(build_github_like_url(host, user, repo_name, branch, page)),
        "gitlab.com" => build_gitlab_url(host, user, repo_name, branch, page),
        "bitbucket.org" => build_bitbucket_url(user, repo_name, branch, page),
        _ => {
            let port = if host.starts_with("github.") {
                &env.ghe_ssh_port
            } else if host.starts_with("gitlab.") {
                &env.gitlab_ssh_port
            } else {
                match env.ghe_url_host {
                    Some(ref v) if v == host => &env.ghe_ssh_port,
                    _ => {
                        return Err(Error::UnknownHostingService {
                            url: repo.to_string(),
                        });
                    }
                }
            };
            Ok(build_custom_github_like_url(
                host, user, repo_name, branch, page, port,
            ))
        }
    }
}
<commit_msg>deal with Option<u16> by copy<commit_after>extern crate path_slash;
extern crate url;

use crate::env::EnvConfig;
use crate::error::{Error, Result};
use crate::page::{DiffOp, Line, Page};
use url::Url;

#[cfg(target_os = "windows")]
fn to_slash<S: AsRef<str>>(s: &S) -> String {
    use path_slash::PathExt;
    use std::path::Path;
    Path::new(s.as_ref()).to_slash_lossy()
}

// Do nothing on Windows
#[cfg(not(target_os = "windows"))]
fn to_slash<S: AsRef<str>>(s: &S) -> &str {
    s.as_ref()
}

fn build_github_like_url(
    host: &str,
    user: &str,
    repo: &str,
    branch: &Option<String>,
    page: &Page,
) -> String {
    match page {
        Page::Open => {
            if let Some(ref b) = branch {
                format!("https://{}/{}/{}/tree/{}", host, user, repo, b)
            } else {
                format!("https://{}/{}/{}", host, user, repo)
            }
        }
        Page::Diff {
            ref lhs,
            ref rhs,
            ref op,
        } => format!(
            "https://{}/{}/{}/compare/{}{}{}",
            host, user, repo, lhs, op, rhs,
        ),
        Page::Commit { ref hash } => format!("https://{}/{}/{}/commit/{}", host, user, repo, hash),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: None,
        } => format!(
            "https://{}/{}/{}/blob/{}/{}",
            host,
            user,
            repo,
            hash,
            to_slash(relative_path),
        ),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: Some(Line::At(line)),
        } => format!(
            "https://{}/{}/{}/blob/{}/{}#L{}",
            host,
            user,
            repo,
            hash,
            to_slash(relative_path),
            line,
        ),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: Some(Line::Range(start, end)),
        } => format!(
            "https://{}/{}/{}/blob/{}/{}#L{}-L{}",
            host,
            user,
            repo,
            hash,
            to_slash(relative_path),
            start,
            end,
        ),
        Page::Issue { number } => format!("https://{}/{}/{}/issues/{}", host, user, repo, number),
    }
}

fn build_custom_github_like_url(
    host: &str,
    user: &str,
    repo: &str,
    branch: &Option<String>,
    page: &Page,
    ssh_port: Option<u16>,
) -> String {
    match ssh_port {
        Some(ref p) => build_github_like_url(
            &format!("{}:{}", host, p).as_str(),
            user,
            repo,
            branch,
            page,
        ),
        _ => build_github_like_url(host, user, repo, branch, page),
    }
}

fn build_gitlab_url(
    host: &str,
    user: &str,
    repo: &str,
    branch: &Option<String>,
    page: &Page,
) -> Result<String> {
    if let Page::Diff { op, .. } = page {
        if *op == DiffOp::TwoDots {
            return Err(Error::GitLabDiffNotSupported);
        }
    }
    Ok(build_github_like_url(host, user, repo, branch, page))
}

fn build_bitbucket_url(
    user: &str,
    repo: &str,
    branch: &Option<String>,
    page: &Page,
) -> Result<String> {
    match page {
        Page::Open => {
            if let Some(ref b) = branch {
                Ok(format!(
                    "https://bitbucket.org/{}/{}/branch/{}",
                    user, repo, b,
                ))
            } else {
                Ok(format!("https://bitbucket.org/{}/{}", user, repo))
            }
        }
        Page::Diff { .. } => Err(Error::BitbucketDiffNotSupported),
        Page::Commit { ref hash } => Ok(format!(
            "https://bitbucket.org/{}/{}/commits/{}",
            user, repo, hash,
        )),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: None,
        } => Ok(format!(
            "https://bitbucket.org/{}/{}/src/{}/{}",
            user,
            repo,
            hash,
            to_slash(relative_path),
        )),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: Some(Line::At(line)),
        } => Ok(format!(
            "https://bitbucket.org/{}/{}/src/{}/{}#lines-{}",
            user,
            repo,
            hash,
            to_slash(relative_path),
            line,
        )),
        Page::FileOrDir {
            ref relative_path,
            ref hash,
            line: Some(Line::Range(start, end)),
        } => Ok(format!(
            "https://bitbucket.org/{}/{}/src/{}/{}#lines-{}:{}",
            user,
            repo,
            hash,
            to_slash(relative_path),
            start,
            end,
        )),
        Page::Issue { number } => Ok(format!(
            "https://bitbucket.org/{}/{}/issues/{}",
            user, repo, number,
        )),
    }
}

// Note: Parse '/user/repo.git' or '/user/repo' or 'user/repo' into 'user' and 'repo'
pub fn slug_from_path<'a>(path: &'a str) -> Result<(&'a str, &'a str)> {
    let mut split = path.split('/').skip_while(|s| s.is_empty());
    let user = split.next().ok_or_else(|| Error::NoUserInPath {
        path: path.to_string(),
    })?;
    let mut repo = split.next().ok_or_else(|| Error::NoRepoInPath {
        path: path.to_string(),
    })?;
    if repo.ends_with(".git") {
        // Slice '.git' from 'repo.git'
        repo = &repo[0..repo.len() - 4];
    }
    Ok((user, repo))
}

// Known URL formats
//  1. https://hosting_service.com/user/repo.git
//  2. git@hosting_service.com:user/repo.git (-> ssh://git@hosting_service.com:22/user/repo.git)
pub fn build_page_url(
    repo: &str,
    page: &Page,
    branch: &Option<String>,
    env: &EnvConfig,
) -> Result<String> {
    let url = Url::parse(repo).map_err(|e| Error::BrokenUrl {
        url: repo.to_string(),
        msg: format!("{}", e),
    })?;
    let path = url.path();
    let (user, repo_name) = slug_from_path(path)?;
    let host = url.host_str().ok_or_else(|| Error::BrokenUrl {
        url: repo.to_string(),
        msg: "No host in URL".to_string(),
    })?;
    match host {
        "github.com" => Ok(build_github_like_url(host, user, repo_name, branch, page)),
        "gitlab.com" => build_gitlab_url(host, user, repo_name, branch, page),
        "bitbucket.org" => build_bitbucket_url(user, repo_name, branch, page),
        _ => {
            let port = if host.starts_with("github.") {
                env.ghe_ssh_port
            } else if host.starts_with("gitlab.") {
                env.gitlab_ssh_port
            } else {
                match env.ghe_url_host {
                    Some(ref v) if v == host => env.ghe_ssh_port,
                    _ => {
                        return Err(Error::UnknownHostingService {
                            url: repo.to_string(),
                        });
                    }
                }
            };
            Ok(build_custom_github_like_url(
                host, user, repo_name, branch, page, port,
            ))
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012, Ben Noordhuis <info@bnoordhuis.nl>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#[license = "ISC"];

#[link(name = "epoll",
       vers = "1.0",
       author = "Ben Noordhuis <info@bnoordhuis.nl>")];

//export EPOLL_NONBLOCK;
export EPOLL_CLOEXEC;
export EPOLL_CTL_ADD;
export EPOLL_CTL_DEL;
export EPOLLIN;
export EPOLLPRI;
export EPOLLOUT;
export EPOLLERR;
export EPOLLHUP;
export EPOLLONESHOT;
export EPOLLET;
export epoll_event;
export epoll_create1;
export epoll_ctl;
export epoll_wait;

use std; // required by the tests

import c_int = ctypes::c_int;

//const EPOLL_NONBLOCK: int = 0x800;
const EPOLL_CLOEXEC: int = 0x80000;

const EPOLL_CTL_ADD: int = 1;
const EPOLL_CTL_DEL: int = 2;
const EPOLL_CTL_MOD: int = 3;

const EPOLLIN: i32 = 0x01i32;
const EPOLLPRI: i32 = 0x02i32;
const EPOLLOUT: i32 = 0x04i32;
const EPOLLERR: i32 = 0x08i32;
const EPOLLHUP: i32 = 0x10i32;
const EPOLLONESHOT: i32 = 0x40000000i32;
const EPOLLET: i32 = 0x80000000i32;

type epoll_event = {
  events: i32,
  data: u64
};

#[nolink]
native mod __glibc {
  fn epoll_create1(flags: c_int) -> c_int;
  /*
  fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: epoll_event) -> c_int;
  fn epoll_wait(epfd: c_int,
                events: *mutable epoll_event,
                maxevents: c_int,
                timeout: c_int) -> c_int;
  */
  fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *u8) -> c_int;
  fn epoll_wait(epfd: c_int,
                events: *mutable u8,
                maxevents: c_int,
                timeout: c_int) -> c_int;
}

fn epoll_create1(flags: int) -> int {
  __glibc::epoll_create1(flags as c_int) as int
}

fn epoll_ctl(epfd: int, op: int, fd: int, event: epoll_event) -> int {
  /*
  __glibc::epoll_ctl(epfd as c_int, op as c_int, fd as c_int, event) as int
  */

  let buf: [mutable u8] = vec::init_elt_mut(12u, 0u8);

  // rust as of 2012-02-06 does not support packed types, hence we have to do
  // the packing and unpacking ourselves
  unsafe {
    let p1: *mutable i32 = unsafe::reinterpret_cast(ptr::mut_addr_of(buf[0]));
    let p2: *mutable u64 = unsafe::reinterpret_cast(ptr::mut_addr_of(buf[4]));
    *p1 = event.events;
    *p2 = event.data;
  }

  ret __glibc::epoll_ctl(epfd as c_int,
                         op as c_int,
                         fd as c_int,
                         ptr::addr_of(buf[0])) as int
}

fn epoll_wait(epfd: int, events: [mutable epoll_event], timeout: int) -> int {
  /*
  let pevents: *mutable epoll_event = ptr::mut_addr_of(events[0]);
  let maxevents: c_int = vec::len(events) as c_int;
  ret __glibc::epoll_wait(epfd as c_int,
                          pevents,
                          maxevents,
                          timeout as c_int) as int;
  */

  let buf: [mutable u8] = vec::init_elt_mut(12u * vec::len(events), 0u8);

  let nevents = __glibc::epoll_wait(epfd as c_int,
                                    ptr::mut_addr_of(buf[0]),
                                    vec::len(events) as c_int,
                                    timeout as c_int) as int;

  if (nevents == -1) {
    ret -1;
  }

  // rust as of 2012-02-06 does not support packed types, hence we have to do
  // the packing and unpacking ourselves
  let i = 0;
  while (i < nevents) {
    unsafe {
      let p1: *i32 = unsafe::reinterpret_cast(ptr::addr_of(buf[i * 12]));
      let p2: *u64 = unsafe::reinterpret_cast(ptr::addr_of(buf[i * 12 + 4]));
      events[i] = {events: *p1, data: *p2};
    }
    i += 1;
  }

  ret nevents;
}

#[test]
fn test_epoll_create1() {
  assert epoll_create1(0) >= 0;
  assert epoll_create1(EPOLL_CLOEXEC) >= 0;
  assert epoll_create1(-1) == -1;
}

#[test]
fn test_epoll_ctl() {
  let epfd = epoll_create1(0);
  assert epfd >= 0;

  assert epoll_ctl(epfd, EPOLL_CTL_ADD, 0, {events:EPOLLIN, data:0u64}) == 0;
  assert epoll_ctl(epfd, EPOLL_CTL_ADD, 0, {events:EPOLLIN, data:0u64}) == -1;
  assert epoll_ctl(epfd, EPOLL_CTL_MOD, 0, {events:EPOLLOUT, data:0u64}) == 0;
  assert epoll_ctl(epfd, EPOLL_CTL_DEL, 0, {events:EPOLLIN, data:0u64}) == 0;

  assert epoll_ctl(epfd, EPOLL_CTL_ADD, -1, {events:EPOLLIN, data:0u64}) == -1;
  assert epoll_ctl(epfd, EPOLL_CTL_MOD, -1, {events:EPOLLIN, data:0u64}) == -1;
  assert epoll_ctl(epfd, EPOLL_CTL_DEL, -1, {events:EPOLLIN, data:0u64}) == -1;
}

#[test]
fn test_epoll_wait() {
  // add stdout to epoll set and wait for it to become writable
  // should be immediate, it's an error if we hit the 50 ms timeout
  let epfd = epoll_create1(0);
  assert epfd >= 0;

  let magic = 42u64;
  assert epoll_ctl(epfd, EPOLL_CTL_ADD, 1, {events:EPOLLOUT, data:magic}) == 0;
  assert epoll_ctl(epfd, EPOLL_CTL_ADD, 2, {events:EPOLLOUT, data:magic}) == 0;

  let events: [mutable epoll_event] = [
    mutable {events:0i32, data:0u64}, {events:0i32, data:0u64}];

  let n = epoll_wait(epfd, events, 50);
  assert n == 2;
  assert events[0].data == magic;
  assert events[0].events & EPOLLOUT == EPOLLOUT;
}
<commit_msg>Add epoll_create().<commit_after>/*
 * Copyright (c) 2012, Ben Noordhuis <info@bnoordhuis.nl>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#[license = "ISC"];

#[link(name = "epoll",
       vers = "1.0",
       author = "Ben Noordhuis <info@bnoordhuis.nl>")];

//export EPOLL_NONBLOCK;
export EPOLL_CLOEXEC;
export EPOLL_CTL_ADD;
export EPOLL_CTL_DEL;
export EPOLLIN;
export EPOLLPRI;
export EPOLLOUT;
export EPOLLERR;
export EPOLLHUP;
export EPOLLONESHOT;
export EPOLLET;
export epoll_event;
export epoll_create;
export epoll_create1;
export epoll_ctl;
export epoll_wait;

use std; // required by the tests

import c_int = ctypes::c_int;

//const EPOLL_NONBLOCK: int = 0x800;
const EPOLL_CLOEXEC: int = 0x80000;

const EPOLL_CTL_ADD: int = 1;
const EPOLL_CTL_DEL: int = 2;
const EPOLL_CTL_MOD: int = 3;

const EPOLLIN: i32 = 0x01i32;
const EPOLLPRI: i32 = 0x02i32;
const EPOLLOUT: i32 = 0x04i32;
const EPOLLERR: i32 = 0x08i32;
const EPOLLHUP: i32 = 0x10i32;
const EPOLLONESHOT: i32 = 0x40000000i32;
const EPOLLET: i32 = 0x80000000i32;

type epoll_event = {
  events: i32,
  data: u64
};

#[nolink]
native mod __glibc {
  fn epoll_create1(flags: c_int) -> c_int;
  /*
  fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: epoll_event) -> c_int;
  fn epoll_wait(epfd: c_int,
                events: *mutable epoll_event,
                maxevents: c_int,
                timeout: c_int) -> c_int;
  */
  fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *u8) -> c_int;
  fn epoll_wait(epfd: c_int,
                events: *mutable u8,
                maxevents: c_int,
                timeout: c_int) -> c_int;
}

fn epoll_create() -> int {
  epoll_create1(0)
}

fn epoll_create1(flags: int) -> int {
  __glibc::epoll_create1(flags as c_int) as int
}

fn epoll_ctl(epfd: int, op: int, fd: int, event: epoll_event) -> int {
  /*
  __glibc::epoll_ctl(epfd as c_int, op as c_int, fd as c_int, event) as int
  */

  let buf: [mutable u8] = vec::init_elt_mut(12u, 0u8);

  // rust as of 2012-02-06 does not support packed types, hence we have to do
  // the packing and unpacking ourselves
  unsafe {
    let p1: *mutable i32 = unsafe::reinterpret_cast(ptr::mut_addr_of(buf[0]));
    let p2: *mutable u64 = unsafe::reinterpret_cast(ptr::mut_addr_of(buf[4]));
    *p1 = event.events;
    *p2 = event.data;
  }

  ret __glibc::epoll_ctl(epfd as c_int,
                         op as c_int,
                         fd as c_int,
                         ptr::addr_of(buf[0])) as int
}

fn epoll_wait(epfd: int, events: [mutable epoll_event], timeout: int) -> int {
  /*
  let pevents: *mutable epoll_event = ptr::mut_addr_of(events[0]);
  let maxevents: c_int = vec::len(events) as c_int;
  ret __glibc::epoll_wait(epfd as c_int,
                          pevents,
                          maxevents,
                          timeout as c_int) as int;
  */

  let buf: [mutable u8] = vec::init_elt_mut(12u * vec::len(events), 0u8);

  let nevents = __glibc::epoll_wait(epfd as c_int,
                                    ptr::mut_addr_of(buf[0]),
                                    vec::len(events) as c_int,
                                    timeout as c_int) as int;

  if (nevents == -1) {
    ret -1;
  }

  // rust as of 2012-02-06 does not support packed types, hence we have to do
  // the packing and unpacking ourselves
  let i = 0;
  while (i < nevents) {
    unsafe {
      let p1: *i32 = unsafe::reinterpret_cast(ptr::addr_of(buf[i * 12]));
      let p2: *u64 = unsafe::reinterpret_cast(ptr::addr_of(buf[i * 12 + 4]));
      events[i] = {events: *p1, data: *p2};
    }
    i += 1;
  }

  ret nevents;
}

#[test]
fn test_epoll_create1() {
  assert epoll_create1(0) >= 0;
  assert epoll_create1(EPOLL_CLOEXEC) >= 0;
  assert epoll_create1(-1) == -1;
}

#[test]
fn test_epoll_ctl() {
  let epfd = epoll_create1(0);
  assert epfd >= 0;

  assert epoll_ctl(epfd, EPOLL_CTL_ADD, 0, {events:EPOLLIN, data:0u64}) == 0;
  assert epoll_ctl(epfd, EPOLL_CTL_ADD, 0, {events:EPOLLIN, data:0u64}) == -1;
  assert epoll_ctl(epfd, EPOLL_CTL_MOD, 0, {events:EPOLLOUT, data:0u64}) == 0;
  assert epoll_ctl(epfd, EPOLL_CTL_DEL, 0, {events:EPOLLIN, data:0u64}) == 0;

  assert epoll_ctl(epfd, EPOLL_CTL_ADD, -1, {events:EPOLLIN, data:0u64}) == -1;
  assert epoll_ctl(epfd, EPOLL_CTL_MOD, -1, {events:EPOLLIN, data:0u64}) == -1;
  assert epoll_ctl(epfd, EPOLL_CTL_DEL, -1, {events:EPOLLIN, data:0u64}) == -1;
}

#[test]
fn test_epoll_wait() {
  // add stdout to epoll set and wait for it to become writable
  // should be immediate, it's an error if we hit the 50 ms timeout
  let epfd = epoll_create1(0);
  assert epfd >= 0;

  let magic = 42u64;
  assert epoll_ctl(epfd, EPOLL_CTL_ADD, 1, {events:EPOLLOUT, data:magic}) == 0;
  assert epoll_ctl(epfd, EPOLL_CTL_ADD, 2, {events:EPOLLOUT, data:magic}) == 0;

  let events: [mutable epoll_event] = [
    mutable {events:0i32, data:0u64}, {events:0i32, data:0u64}];

  let n = epoll_wait(epfd, events, 50);
  assert n == 2;
  assert events[0].data == magic;
  assert events[0].events & EPOLLOUT == EPOLLOUT;
}
<|endoftext|>