<commit_before>#[macro_use]
extern crate clap;
extern crate requests;
extern crate json;

mod crates;

use clap::{App, SubCommand, Arg, AppSettings, ArgMatches};

const CARGO: &'static str = "cargo";

#[derive(Debug, PartialEq)]
enum Flag {
    Repository,
    Documentation,
    Downloads,
    Homepage,
    Default,
}

#[derive(Debug)]
struct Report {
    flags: Vec<Flag>,
    verbose: bool,
    json: bool,
}

impl Report {
    pub fn new(info: &ArgMatches) -> Self {

        let mut flags: Vec<Flag> = vec![];
        if info.is_present("repository") {
            flags.push(Flag::Repository);
        }
        if info.is_present("documentation") {
            flags.push(Flag::Documentation);
        }
        if info.is_present("downloads") {
            flags.push(Flag::Downloads);
        }
        if info.is_present("homepage") {
            flags.push(Flag::Homepage);
        }

        if flags.is_empty() {
            flags.push(Flag::Default);
        }

        Report {
            flags: flags,
            verbose: info.is_present("verbose"),
            json: info.is_present("json"),
        }
    }

    pub fn report(&self, name: &str) {
        if let Ok(response) = query(name) {
            if self.json {
                self.report_json(&response);
            } else {
                if let Some(krate) = get_crate(&response) {
                    self.report_crate(&krate);
                }
            }
        }
    }

    pub fn report_json(&self, response: &requests::Response) {
        if self.verbose {
            if let Ok(json) = response.json() {
                println!("{}", json.pretty(2));
            }
        } else {
            if let Some(json) = response.text() {
                println!("{}", json);
            }
        }
    }

    pub fn report_crate(&self, krate: &crates::Crate) {
        for flag in &self.flags {
            match *flag {
                Flag::Repository => krate.print_repository(self.verbose),
                Flag::Documentation => krate.print_documentation(self.verbose),
                Flag::Downloads => krate.print_downloads(self.verbose),
                Flag::Homepage => krate.print_homepage(self.verbose),
                Flag::Default => reportv(krate, self.verbose),
            }
        }
    }
}

fn reportv(krate: &crates::Crate, verbose: bool) {
    if verbose {
        println!("{:#}", krate);
    } else {
        println!("{}", krate);
    }
}

fn query(krate: &str) -> requests::RequestsResult {
    requests::get(&format!("http://crates.io/api/v1/crates/{}", krate))
}

fn get_crate(response: &requests::Response) -> Option<crates::Crate> {
    response.json().ok().map(|k| crates::Crate::new(k["crate"].clone()))
}

// use std::fmt;
// fn debug<T>(item: &T)
//     where T: fmt::Debug
// {
//     println!("{:#?}", item);
// }

fn main() {

    let matches = App::new(CARGO)
        .bin_name(CARGO)
        .author(crate_authors!())
        .version(crate_version!())
        .about("Query crates.io registry for crates details")
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .subcommand(SubCommand::with_name("info")
            .setting(AppSettings::ArgRequiredElseHelp)
            .setting(AppSettings::TrailingVarArg)
            .arg(Arg::with_name("documentation")
                .short("d")
                .long("documentation")
                .help("Report documentation URL"))
            .arg(Arg::with_name("downloads")
                .short("D")
                .long("downloads")
                .help("Report number of crate downloads"))
            .arg(Arg::with_name("homepage")
                .short("H")
                .long("homepage")
                .help("Report home page URL"))
            .arg(Arg::with_name("repository")
                .short("r")
                .long("repository")
                .help("Report crate repository URL"))
            .arg(Arg::with_name("json")
                .short("j")
                .long("json")
                .help("Report raw JSON data from crates.io")
                .conflicts_with_all(&["documentation", "downloads", "homepage", "repository"]))
            .arg(Arg::with_name("verbose")
                .short("v")
                .long("verbose")
                .help("Report more details"))
            .arg_from_usage("<crate>... 'crate to query'"))
        .get_matches();

    if let Some(info) = matches.subcommand_matches("info") {
        if let Some(crates) = info.values_of("crate") {
            let rep = Report::new(info);
            for krate in crates {
                // debug(&krate);
                rep.report(krate);
            }
        }
    }
}
<commit_msg>Use new json Display trait to print its pretty content<commit_after>#[macro_use]
extern crate clap;
extern crate requests;
extern crate json;

mod crates;

use clap::{App, SubCommand, Arg, AppSettings, ArgMatches};

const CARGO: &'static str = "cargo";

#[derive(Debug, PartialEq)]
enum Flag {
    Repository,
    Documentation,
    Downloads,
    Homepage,
    Default,
}

#[derive(Debug)]
struct Report {
    flags: Vec<Flag>,
    verbose: bool,
    json: bool,
}

impl Report {
    pub fn new(info: &ArgMatches) -> Self {

        let mut flags: Vec<Flag> = vec![];
        if info.is_present("repository") {
            flags.push(Flag::Repository);
        }
        if info.is_present("documentation") {
            flags.push(Flag::Documentation);
        }
        if info.is_present("downloads") {
            flags.push(Flag::Downloads);
        }
        if info.is_present("homepage") {
            flags.push(Flag::Homepage);
        }

        if flags.is_empty() {
            flags.push(Flag::Default);
        }

        Report {
            flags: flags,
            verbose: info.is_present("verbose"),
            json: info.is_present("json"),
        }
    }

    pub fn report(&self, name: &str) {
        if let Ok(response) = query(name) {
            if self.json {
                self.report_json(&response);
            } else {
                if let Some(krate) = get_crate(&response) {
                    self.report_crate(&krate);
                }
            }
        }
    }

    pub fn report_json(&self, response: &requests::Response) {
        if self.verbose {
            if let Ok(json) = response.json() {
                println!("{:#}", json);
            }
        } else {
            if let Some(json) = response.text() {
                println!("{}", json);
            }
        }
    }

    pub fn report_crate(&self, krate: &crates::Crate) {
        for flag in &self.flags {
            match *flag {
                Flag::Repository => krate.print_repository(self.verbose),
                Flag::Documentation => krate.print_documentation(self.verbose),
                Flag::Downloads => krate.print_downloads(self.verbose),
                Flag::Homepage => krate.print_homepage(self.verbose),
                Flag::Default => reportv(krate, self.verbose),
            }
        }
    }
}

fn reportv(krate: &crates::Crate, verbose: bool) {
    if verbose {
        println!("{:#}", krate);
    } else {
        println!("{}", krate);
    }
}

fn query(krate: &str) -> requests::RequestsResult {
    requests::get(&format!("http://crates.io/api/v1/crates/{}", krate))
}

fn get_crate(response: &requests::Response) -> Option<crates::Crate> {
    response.json().ok().map(|k| crates::Crate::new(k["crate"].clone()))
}

// use std::fmt;
// fn debug<T>(item: &T)
//     where T: fmt::Debug
// {
//     println!("{:#?}", item);
// }

fn main() {

    let matches = App::new(CARGO)
        .bin_name(CARGO)
        .author(crate_authors!())
        .version(crate_version!())
        .about("Query crates.io registry for crates details")
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .subcommand(SubCommand::with_name("info")
            .setting(AppSettings::ArgRequiredElseHelp)
            .setting(AppSettings::TrailingVarArg)
            .arg(Arg::with_name("documentation")
                .short("d")
                .long("documentation")
                .help("Report documentation URL"))
            .arg(Arg::with_name("downloads")
                .short("D")
                .long("downloads")
                .help("Report number of crate downloads"))
            .arg(Arg::with_name("homepage")
                .short("H")
                .long("homepage")
                .help("Report home page URL"))
            .arg(Arg::with_name("repository")
                .short("r")
                .long("repository")
                .help("Report crate repository URL"))
            .arg(Arg::with_name("json")
                .short("j")
                .long("json")
                .help("Report raw JSON data from crates.io")
                .conflicts_with_all(&["documentation", "downloads", "homepage", "repository"]))
            .arg(Arg::with_name("verbose")
                .short("v")
                .long("verbose")
                .help("Report more details"))
            .arg_from_usage("<crate>... 'crate to query'"))
        .get_matches();

    if let Some(info) = matches.subcommand_matches("info") {
        if let Some(crates) = info.values_of("crate") {
            let rep = Report::new(info);
            for krate in crates {
                // debug(&krate);
                rep.report(krate);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate kernel32;
extern crate user32;
extern crate winapi;
extern crate libc;

use winapi::windef::HWND;
use winapi::windef::HMENU;
use winapi::windef::HBRUSH;
use winapi::minwindef::HINSTANCE;

use winapi::minwindef::UINT;
use winapi::minwindef::DWORD;
use winapi::minwindef::WPARAM;
use winapi::minwindef::LPARAM;
use winapi::minwindef::LRESULT;
use winapi::winnt::LPCWSTR;

use winapi::winuser::WS_OVERLAPPEDWINDOW;
use winapi::winuser::WS_VISIBLE;
use winapi::winuser::WNDCLASSW;

use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;

// convert normal string to wide string
fn to_wstring(str: &str) -> *const u16 {
	let v: Vec<u16> = OsStr::new(str).encode_wide() . chain(Some(0).into_iter()).collect();
	v.as_ptr()
}

// This is our window message handler function. Currently,
// it only processes the WM_DESTROY message to exit our window properly on close event.
pub unsafe extern "system" fn window_proc(h_wnd: HWND, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
	if msg == winapi::winuser::WM_DESTROY {
		user32::PostQuitMessage(0);
	}
	user32::DefWindowProcW(h_wnd, msg, w_param, l_param)
}

// The following function hides the Console Window since we are building a GUI application.
fn hide_console_window() {
	let window = unsafe {
		kernel32::GetConsoleWindow()
	};

	if window != std::ptr::null_mut() {
		unsafe {
			user32::ShowWindow(window, winapi::SW_HIDE)
		};
	}
}

fn main() {
	// Here our unsafe code goes
	unsafe {
		// First we hide the console window
		hide_console_window();

		// Then we initialize the WNDCLASS structure
		let class_name = to_wstring("my_window");
		let wnd = WNDCLASSW {
			style: 0,
			lpfnWndProc: Some(window_proc),
			cbClsExtra: 0,
			cbWndExtra: 0,
			hInstance: 0 as HINSTANCE,
			hIcon: user32::LoadIconW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
			hCursor: user32::LoadCursorW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
			hbrBackground: 16 as HBRUSH,
			lpszMenuName: 0 as LPCWSTR,
			lpszClassName: class_name,
		};

		// Register our class
		user32::RegisterClassW(&wnd);

		let h_wnd_desktop = user32::GetDesktopWindow();

		user32::CreateWindowExA(0, "my_window".as_ptr() as *mut _,
			"Simple Window".as_ptr() as *mut _, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
			0, 0, 400, 400, h_wnd_desktop, 0 as HMENU, 0 as HINSTANCE,
			std::ptr::null_mut());

		let mut msg = winapi::winuser::MSG {
			hwnd: 0 as HWND,
			message: 0 as UINT,
			wParam: 0 as WPARAM,
			lParam: 0 as LPARAM,
			time: 0 as DWORD,
			pt : winapi::windef::POINT { x: 0, y: 0, },
		};

		// Kick off the application loop
		loop {
			let pm = user32::PeekMessageW(&mut msg, 0 as HWND, 0, 0, winapi::winuser::PM_REMOTE);

			if pm == 0 {
				continue;
			}

			if msg.message == winapi::winuser::WM_QUIT {
				break;
			}

			user32::TranslateMessage(&mut msg);
			user32::DispatchMessageW(&mut msg);
		}
	}
}<commit_msg>Remove<commit_after>extern crate kernel32;
extern crate user32;
extern crate winapi;
extern crate libc;

use winapi::windef::HWND;
use winapi::windef::HMENU;
use winapi::windef::HBRUSH;
use winapi::minwindef::HINSTANCE;

use winapi::minwindef::UINT;
use winapi::minwindef::DWORD;
use winapi::minwindef::WPARAM;
use winapi::minwindef::LPARAM;
use winapi::minwindef::LRESULT;
use winapi::winnt::LPCWSTR;

use winapi::winuser::WS_OVERLAPPEDWINDOW;
use winapi::winuser::WS_VISIBLE;
use winapi::winuser::WNDCLASSW;

use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;

// convert normal string to wide string
fn to_wstring(str: &str) -> *const u16 {
	let v: Vec<u16> = OsStr::new(str).encode_wide() . chain(Some(0).into_iter()).collect();
	v.as_ptr()
}

// This is our window message handler function. Currently,
// it only processes the WM_DESTROY message to exit our window properly on close event.
pub unsafe extern "system" fn window_proc(h_wnd: HWND, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
	if msg == winapi::winuser::WM_DESTROY {
		user32::PostQuitMessage(0);
	}
	user32::DefWindowProcW(h_wnd, msg, w_param, l_param)
}

// The following function hides the Console Window since we are building a GUI application.
fn hide_console_window() {
	let window = unsafe {
		kernel32::GetConsoleWindow()
	};

	if window != std::ptr::null_mut() {
		unsafe {
			user32::ShowWindow(window, winapi::SW_HIDE)
		};
	}
}

fn main() {
	// Here our unsafe code goes
	unsafe {
		// First we hide the console window
		hide_console_window();

		// Then we initialize the WNDCLASS structure
		let class_name = to_wstring("my_window");
		let wnd = WNDCLASSW {
			style: 0,
			lpfnWndProc: Some(window_proc),
			cbClsExtra: 0,
			cbWndExtra: 0,
			hInstance: 0 as HINSTANCE,
			hIcon: user32::LoadIconW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
			hCursor: user32::LoadCursorW(0 as HINSTANCE, winapi::winuser::IDI_APPLICATION),
			hbrBackground: 16 as HBRUSH,
			lpszMenuName: 0 as LPCWSTR,
			lpszClassName: class_name,
		};

		// Register our class
		user32::RegisterClassW(&wnd);

		let h_wnd_desktop = user32::GetDesktopWindow();

		user32::CreateWindowExA(0, "my_window".as_ptr() as *mut _,
			"Simple Window".as_ptr() as *mut _, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
			0, 0, 400, 400, h_wnd_desktop, 0 as HMENU, 0 as HINSTANCE,
			std::ptr::null_mut());

		let mut msg = winapi::winuser::MSG {
			hwnd: 0 as HWND,
			message: 0 as UINT,
			wParam: 0 as WPARAM,
			lParam: 0 as LPARAM,
			time: 0 as DWORD,
			pt : winapi::windef::POINT { x: 0, y: 0, },
		};

		// Kick off the application loop
		loop {
			let pm = user32::PeekMessageW(&mut msg, 0 as HWND, 0, 0, winapi::winuser::PM_REMOVE);

			if pm == 0 {
				continue;
			}

			if msg.message == winapi::winuser::WM_QUIT {
				break;
			}

			user32::TranslateMessage(&mut msg);
			user32::DispatchMessageW(&mut msg);
		}
	}
}<|endoftext|>


<commit_before>use crate::config::Config;
use crate::error::{Error, ExpectedNumberOfArgs, Result};
use crate::git::Git;
use std::fmt;
use std::fs;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DiffOp {
    TwoDots,   // '..'
    ThreeDots, // '...'
}

impl fmt::Display for DiffOp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DiffOp::TwoDots => write!(f, ".."),
            DiffOp::ThreeDots => write!(f, "..."),
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Line {
    At(usize),
    Range(usize, usize), // start and end
}

#[derive(Debug, PartialEq)]
pub enum Page {
    Open {
        website: bool,
        pull_request: bool,
    },
    Diff {
        lhs: String,
        rhs: String,
        op: DiffOp, // '...' or '..'
    },
    Commit {
        hash: String,
    },
    FileOrDir {
        relative_path: String,
        hash: String,
        line: Option<Line>,
        blame: bool,
    },
    Issue {
        number: usize,
    },
    Tag {
        tagname: String,
        commit: String,
    },
}

struct BrowsePageParser<'a> {
    cfg: &'a Config,
    git: Git<'a>,
}

impl<'a> BrowsePageParser<'a> {
    fn wrong_number_of_args(&self, expected: ExpectedNumberOfArgs, kind: &str) -> Result<Page> {
        Err(Error::WrongNumberOfArgs {
            expected,
            actual: self.cfg.args.len(),
            kind: kind.to_string(),
        })
    }

    fn try_parse_commit(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "commit")
        } else {
            let hash = self.git.hash(&self.cfg.args[0])?;
            Ok(Page::Commit { hash })
        }
    }

    fn try_parse_tag(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "tag name")
        } else {
            let hash = self.git.tag_hash(&self.cfg.args[0])?;
            Ok(Page::Tag {
                tagname: self.cfg.args[0].clone(),
                commit: hash,
            })
        }
    }

    fn try_parse_diff(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "diff");
        }

        let arg = &self.cfg.args[0];
        let dots = if arg.contains("...") {
            "..."
        } else if arg.contains("..") {
            ".."
        } else {
            return Err(Error::DiffDotsNotFound);
        };

        let mut split = arg.splitn(2, dots);
        let lhs = split.next().unwrap();
        let rhs = split.next().unwrap();

        if lhs.is_empty() || rhs.is_empty() {
            return Err(Error::DiffHandIsEmpty {
                input: arg.to_string(),
            });
        }

        Ok(Page::Diff {
            lhs: self.git.hash(&lhs)?,
            rhs: self.git.hash(&rhs)?,
            op: if dots == ".." {
                DiffOp::TwoDots
            } else {
                DiffOp::ThreeDots
            },
        })
    }

    fn parse_path_and_line(&self) -> (&str, Option<Line>) {
        let arg = &self.cfg.args[0];

        let line_start = match arg.find('#') {
            Some(i) => i,
            None => return (arg.as_str(), None),
        };

        let mut idx = line_start;
        if arg.chars().nth(idx + 1) == Some('L') {
            // Skip 'L' of file#L123
            idx += 1;
        }

        let path = &arg[..line_start];
        let line_spec = &arg[idx + 1..];
        if let Some(mut dash_idx) = line_spec.find('-') {
            let start = (&line_spec[..dash_idx]).parse().ok();

            if line_spec.chars().nth(dash_idx + 1) == Some('L') {
                // Skip second 'L' of file#L123-L345
                dash_idx += 1;
            }
            let end = (&line_spec[dash_idx + 1..]).parse().ok();

            (
                path,
                start.map(|s| match end {
                    Some(e) => Line::Range(s, e),
                    None => Line::At(s),
                }),
            )
        } else {
            let line = line_spec.parse().ok();
            (path, line.map(Line::At))
        }
    }

    fn try_parse_file_or_dir(&self) -> Result<Page> {
        let len = self.cfg.args.len();
        if len != 1 && len != 2 {
            return self
                .wrong_number_of_args(ExpectedNumberOfArgs::Range(1, 2), "file or directory");
        }

        let (path, line) = self.parse_path_and_line();
        let path = fs::canonicalize(path)?;

        if path.is_dir() {
            if self.cfg.blame {
                return Err(Error::CannotBlameDirectory {
                    dir: path.to_string_lossy().into(),
                });
            }
            if line.is_some() {
                return Err(Error::LineSpecifiedForDir(path));
            }
        }

        let repo_root = self.git.root_dir()?;
        let relative_path = path
            .strip_prefix(&repo_root)
            .map_err(|_| Error::FileDirNotInRepo {
                repo_root: repo_root.to_owned(),
                path: path.clone(),
            })?
            .to_str()
            .expect("Failed to convert path into UTF-8 string")
            .to_string();

        let mut hash = if len == 2 {
            self.git.hash(self.cfg.args[1].as_str())?
        } else {
            self.git.hash("HEAD")?
        };

        // Fall back into branch name when the commit is not existing in remote branch (#12)
        //
        // Ignore this check when the local branch does not point to any branch
        let remote_contains_hash = match self.git.remote_branch(&self.cfg.remote, &self.cfg.branch)
        {
            Ok(remote_branch) => self.git.remote_contains(&hash, &remote_branch)?,
            Err(_) => false,
        };
        if !remote_contains_hash {
            hash = match &self.cfg.branch {
                Some(b) => b.clone(),
                None => self.git.current_branch()?,
            };
        };

        Ok(Page::FileOrDir {
            relative_path,
            hash,
            line,
            blame: self.cfg.blame,
        })
    }

    fn try_parse_issue_number(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "issue number");
        }

        let arg = &self.cfg.args[0];
        if !arg.starts_with('#') {
            return Err(Error::InvalidIssueNumberFormat);
        }
        let arg = &arg[1..];
        let number: usize = arg.parse().map_err(|_| Error::InvalidIssueNumberFormat)?;
        Ok(Page::Issue { number })
    }
}

pub fn parse_page(cfg: &Config) -> Result<Page> {
    let mut attempts = Vec::with_capacity(5);

    // Note: Ignore any arguments when opening a website
    if cfg.args.is_empty() || cfg.website || cfg.pull_request {
        if cfg.blame {
            return Err(Error::BlameWithoutFilePath);
        }

        return Ok(Page::Open {
            website: cfg.website,
            pull_request: cfg.pull_request,
        });
    }

    let git = cfg.git().ok_or_else(|| Error::NoLocalRepoFound {
        operation: format!("opening URL with options {:?}", cfg.args),
    })?;

    let parser = BrowsePageParser { cfg, git };

    match parser.try_parse_issue_number() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Issue number", e)),
    }

    // Note: Early return for --blame
    match parser.try_parse_file_or_dir() {
        Ok(p) => return Ok(p),
        err @ Err(Error::CannotBlameDirectory { .. }) => return err,
        Err(..) if cfg.blame => return Err(Error::BlameWithoutFilePath),
        Err(e) => attempts.push(("File or dir", e)),
    }

    match parser.try_parse_diff() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Diff", e)),
    }

    match parser.try_parse_tag() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Tag", e)),
    }

    match parser.try_parse_commit() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Commit", e)),
    }

    Err(Error::PageParseError {
        args: cfg.args.clone(),
        attempts,
    })
}
<commit_msg>ignore remote branch check for commit hash when local branch is not pointing to remote branch<commit_after>use crate::config::Config;
use crate::error::{Error, ExpectedNumberOfArgs, Result};
use crate::git::Git;
use std::fmt;
use std::fs;

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum DiffOp {
    TwoDots,   // '..'
    ThreeDots, // '...'
}

impl fmt::Display for DiffOp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DiffOp::TwoDots => write!(f, ".."),
            DiffOp::ThreeDots => write!(f, "..."),
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Line {
    At(usize),
    Range(usize, usize), // start and end
}

#[derive(Debug, PartialEq)]
pub enum Page {
    Open {
        website: bool,
        pull_request: bool,
    },
    Diff {
        lhs: String,
        rhs: String,
        op: DiffOp, // '...' or '..'
    },
    Commit {
        hash: String,
    },
    FileOrDir {
        relative_path: String,
        hash: String,
        line: Option<Line>,
        blame: bool,
    },
    Issue {
        number: usize,
    },
    Tag {
        tagname: String,
        commit: String,
    },
}

struct BrowsePageParser<'a> {
    cfg: &'a Config,
    git: Git<'a>,
}

impl<'a> BrowsePageParser<'a> {
    fn wrong_number_of_args(&self, expected: ExpectedNumberOfArgs, kind: &str) -> Result<Page> {
        Err(Error::WrongNumberOfArgs {
            expected,
            actual: self.cfg.args.len(),
            kind: kind.to_string(),
        })
    }

    fn try_parse_commit(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "commit")
        } else {
            let hash = self.git.hash(&self.cfg.args[0])?;
            Ok(Page::Commit { hash })
        }
    }

    fn try_parse_tag(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "tag name")
        } else {
            let hash = self.git.tag_hash(&self.cfg.args[0])?;
            Ok(Page::Tag {
                tagname: self.cfg.args[0].clone(),
                commit: hash,
            })
        }
    }

    fn try_parse_diff(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "diff");
        }

        let arg = &self.cfg.args[0];
        let dots = if arg.contains("...") {
            "..."
        } else if arg.contains("..") {
            ".."
        } else {
            return Err(Error::DiffDotsNotFound);
        };

        let mut split = arg.splitn(2, dots);
        let lhs = split.next().unwrap();
        let rhs = split.next().unwrap();

        if lhs.is_empty() || rhs.is_empty() {
            return Err(Error::DiffHandIsEmpty {
                input: arg.to_string(),
            });
        }

        Ok(Page::Diff {
            lhs: self.git.hash(&lhs)?,
            rhs: self.git.hash(&rhs)?,
            op: if dots == ".." {
                DiffOp::TwoDots
            } else {
                DiffOp::ThreeDots
            },
        })
    }

    fn parse_path_and_line(&self) -> (&str, Option<Line>) {
        let arg = &self.cfg.args[0];

        let line_start = match arg.find('#') {
            Some(i) => i,
            None => return (arg.as_str(), None),
        };

        let mut idx = line_start;
        if arg.chars().nth(idx + 1) == Some('L') {
            // Skip 'L' of file#L123
            idx += 1;
        }

        let path = &arg[..line_start];
        let line_spec = &arg[idx + 1..];
        if let Some(mut dash_idx) = line_spec.find('-') {
            let start = (&line_spec[..dash_idx]).parse().ok();

            if line_spec.chars().nth(dash_idx + 1) == Some('L') {
                // Skip second 'L' of file#L123-L345
                dash_idx += 1;
            }
            let end = (&line_spec[dash_idx + 1..]).parse().ok();

            (
                path,
                start.map(|s| match end {
                    Some(e) => Line::Range(s, e),
                    None => Line::At(s),
                }),
            )
        } else {
            let line = line_spec.parse().ok();
            (path, line.map(Line::At))
        }
    }

    fn try_parse_file_or_dir(&self) -> Result<Page> {
        let len = self.cfg.args.len();
        if len != 1 && len != 2 {
            return self
                .wrong_number_of_args(ExpectedNumberOfArgs::Range(1, 2), "file or directory");
        }

        let (path, line) = self.parse_path_and_line();
        let path = fs::canonicalize(path)?;

        if path.is_dir() {
            if self.cfg.blame {
                return Err(Error::CannotBlameDirectory {
                    dir: path.to_string_lossy().into(),
                });
            }
            if line.is_some() {
                return Err(Error::LineSpecifiedForDir(path));
            }
        }

        let repo_root = self.git.root_dir()?;
        let relative_path = path
            .strip_prefix(&repo_root)
            .map_err(|_| Error::FileDirNotInRepo {
                repo_root: repo_root.to_owned(),
                path: path.clone(),
            })?
            .to_str()
            .expect("Failed to convert path into UTF-8 string")
            .to_string();

        let mut hash = if len == 2 {
            self.git.hash(self.cfg.args[1].as_str())?
        } else {
            self.git.hash("HEAD")?
        };

        // Fall back into branch name when the commit is not existing in remote branch (#12)
        //
        // Ignore this check when the local branch does not point to any remote branch
        let remote_contains_hash = match self.git.remote_branch(&self.cfg.remote, &self.cfg.branch)
        {
            Ok(remote_branch) => self.git.remote_contains(&hash, &remote_branch)?,
            Err(_) => true, // Ignore check
        };
        if !remote_contains_hash {
            hash = match &self.cfg.branch {
                Some(b) => b.clone(),
                None => self.git.current_branch()?,
            };
        };

        Ok(Page::FileOrDir {
            relative_path,
            hash,
            line,
            blame: self.cfg.blame,
        })
    }

    fn try_parse_issue_number(&self) -> Result<Page> {
        if self.cfg.args.len() != 1 {
            return self.wrong_number_of_args(ExpectedNumberOfArgs::Single(1), "issue number");
        }

        let arg = &self.cfg.args[0];
        if !arg.starts_with('#') {
            return Err(Error::InvalidIssueNumberFormat);
        }
        let arg = &arg[1..];
        let number: usize = arg.parse().map_err(|_| Error::InvalidIssueNumberFormat)?;
        Ok(Page::Issue { number })
    }
}

pub fn parse_page(cfg: &Config) -> Result<Page> {
    let mut attempts = Vec::with_capacity(5);

    // Note: Ignore any arguments when opening a website
    if cfg.args.is_empty() || cfg.website || cfg.pull_request {
        if cfg.blame {
            return Err(Error::BlameWithoutFilePath);
        }

        return Ok(Page::Open {
            website: cfg.website,
            pull_request: cfg.pull_request,
        });
    }

    let git = cfg.git().ok_or_else(|| Error::NoLocalRepoFound {
        operation: format!("opening URL with options {:?}", cfg.args),
    })?;

    let parser = BrowsePageParser { cfg, git };

    match parser.try_parse_issue_number() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Issue number", e)),
    }

    // Note: Early return for --blame
    match parser.try_parse_file_or_dir() {
        Ok(p) => return Ok(p),
        err @ Err(Error::CannotBlameDirectory { .. }) => return err,
        Err(..) if cfg.blame => return Err(Error::BlameWithoutFilePath),
        Err(e) => attempts.push(("File or dir", e)),
    }

    match parser.try_parse_diff() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Diff", e)),
    }

    match parser.try_parse_tag() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Tag", e)),
    }

    match parser.try_parse_commit() {
        Ok(p) => return Ok(p),
        Err(e) => attempts.push(("Commit", e)),
    }

    Err(Error::PageParseError {
        args: cfg.args.clone(),
        attempts,
    })
}
<|endoftext|>


<commit_before>use hyper::Client;
use kuchiki::{Html, NodeRef, NodeDataRef, ElementData};

pub struct DictDef {
    pub word: String,
    pub def: String
}

impl DictDef {
    pub fn new (word: String, def: String) -> DictDef {
        DictDef {
            word: word,
            def: def
        }
    }
}

fn urban_dict_url (word: &str) -> String {
    let mut s = String::new();
    s.push_str("http://www.urbandictionary.com/define.php?term=");
    s.push_str(word);
    s
}

fn get_first_match(node: &NodeRef, selector: &str) -> Option<NodeDataRef<ElementData>> {
    if let Ok(mut eles) = node.select(selector) {
        eles.next()
    } else {
        None
    }
}

pub fn find_on_urban_dict (word: &str) -> Option<DictDef> {
    let url = urban_dict_url(word);

    let client = Client::new();

    let mut response = client.get(&url).send().unwrap();

    if let Ok(html) = Html::from_stream(&mut response) {
        let doc = html.parse();

        if let Some(panel_ele) = get_first_match(&doc, "div.def-panel") {
            let panel = panel_ele.as_node();
            if let Some(word_ele) = get_first_match(panel, "a.word") {
                let word_node = word_ele.as_node();
                let word = word_node.first_child().unwrap();
                let word_text = word.as_text().unwrap().borrow();

                let def_ele = get_first_match(panel, "div.meaning").unwrap();
                let def_node = def_ele.as_node();
                let def = def_node.first_child().unwrap();
                let def_text = def.as_text().unwrap().borrow();

                return Some(DictDef::new(word_text.trim().to_owned(),
                                         def_text.trim().to_owned()));
            }
        }
    }

    None
}
<commit_msg>(fix) fix text extraction<commit_after>use hyper::Client;
use kuchiki::{Html, NodeRef, NodeDataRef, ElementData};

pub struct DictDef {
    pub word: String,
    pub def: String,
    pub example: Option<String>
}

impl DictDef {
    pub fn new (word: String, def: String, example: Option<String>) -> DictDef {
        DictDef {
            word: word,
            def: def,
            example: example
        }
    }
}

fn urban_dict_url (word: &str) -> String {
    let mut s = String::new();
    s.push_str("http://www.urbandictionary.com/define.php?term=");
    s.push_str(word);
    s
}

fn get_first_match(node: &NodeRef, selector: &str) -> Option<NodeDataRef<ElementData>> {
    if let Ok(mut eles) = node.select(selector) {
        eles.next()
    } else {
        None
    }
}

pub fn find_on_urban_dict (word: &str) -> Option<DictDef> {
    let url = urban_dict_url(word);

    let client = Client::new();

    let mut response = client.get(&url).send().unwrap();

    if let Ok(html) = Html::from_stream(&mut response) {
        let doc = html.parse();

        if let Some(panel_ele) = get_first_match(&doc, "div.def-panel") {
            let panel = panel_ele.as_node();
            if let Some(word_ele) = get_first_match(panel, "a.word") {
                let word_node = word_ele.as_node();
                let word_text = word_node.text_contents();

                let def_ele = get_first_match(panel, "div.meaning").unwrap();
                let def_node = def_ele.as_node();
                let def_text = def_node.text_contents();

                return Some(DictDef::new(word_text.trim().to_owned(),
                                         def_text.trim().to_owned(),
                                         None));
            }
        }
    }

    None
}
<|endoftext|>


<commit_before>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "pcre", vers = "0.1")];
#[crate_type = "lib"];

use std::libc::{c_int, c_uchar, c_void};
use std::option::{None, Option, Some};
use std::ptr::{is_not_null, null};
use std::vec::{from_elem};
use std::vec::raw::{to_mut_ptr};

pub type options = c_int;

pub static PCRE_CASELESS: options = 0x00000001;
pub static PCRE_MULTILINE: options = 0x00000002;
pub static PCRE_DOTALL: options = 0x00000004;
pub static PCRE_EXTENDED: options = 0x00000008;
pub static PCRE_ANCHORED: options = 0x00000010;
pub static PCRE_DOLLAR_ENDONLY: options = 0x00000020;
pub static PCRE_EXTRA: options = 0x00000040;
pub static PCRE_NOTBOL: options = 0x00000080;
pub static PCRE_NOTEOL: options = 0x00000100;
pub static PCRE_UNGREEDY: options = 0x00000200;
pub static PCRE_NOTEMPTY: options = 0x00000400;
pub static PCRE_UTF8: options = 0x00000800;
pub static PCRE_UTF16: options = 0x00000800;
pub static PCRE_UTF32: options = 0x00000800;
pub static PCRE_NO_AUTO_CAPTURE: options = 0x00001000;
pub static PCRE_NO_UTF8_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF16_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF32_CHECK: options = 0x00002000;
pub static PCRE_AUTO_CALLOUT: options = 0x00004000;
pub static PCRE_PARTIAL_SOFT: options = 0x00008000;
pub static PCRE_PARTIAL: options = 0x00008000;
pub static PCRE_NEVER_UTF: options = 0x00010000;
pub static PCRE_DFA_SHORTEST: options = 0x00010000;
pub static PCRE_DFA_RESTART: options = 0x00020000;
pub static PCRE_FIRSTLINE: options = 0x00040000;
pub static PCRE_DUPNAMES: options = 0x00080000;
pub static PCRE_NEWLINE_CR: options = 0x00100000;
pub static PCRE_NEWLINE_LF: options = 0x00200000;
pub static PCRE_NEWLINE_CRLF: options = 0x00300000;
pub static PCRE_NEWLINE_ANY: options = 0x00400000;
pub static PCRE_NEWLINE_ANYCRLF: options = 0x00500000;
pub static PCRE_BSR_ANYCRLF: options = 0x00800000;
pub static PCRE_BSR_UNICODE: options = 0x01000000;
pub static PCRE_JAVASCRIPT_COMPAT: options = 0x02000000;
pub static PCRE_NO_START_OPTIMIZE: options = 0x04000000;
pub static PCRE_NO_START_OPTIMISE: options = 0x04000000;
pub static PCRE_PARTIAL_HARD: options = 0x08000000;
pub static PCRE_NOTEMPTY_ATSTART: options = 0x10000000;
pub static PCRE_UCP: options = 0x20000000;

mod detail {

    use std::c_str::*;
    use std::libc::*;
    use std::ptr::*;

    pub type fullinfo_field = c_int;
    pub type pcre = c_void;
    pub type pcre_error = c_int;
    pub type pcre_extra = c_void;

    pub static PCRE_ERROR_NOMATCH: pcre_error = -1;
    pub static PCRE_ERROR_NULL: pcre_error = -2;

    pub static PCRE_INFO_CAPTURECOUNT: fullinfo_field = 2;

    mod native {

        use std::libc::*;

        #[link_args = "-lpcre.1"]
        extern {
            static pcre_free: extern "C" fn(ptr: *c_void);

            fn pcre_compile(pattern: *c_char, options: ::options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *::detail::pcre;
            fn pcre_exec(code: *::detail::pcre, extra: *::detail::pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: ::options, ovector: *mut c_int, ovecsize: c_int) -> ::detail::pcre_error;
            fn pcre_free_study(extra: *::detail::pcre_extra);
            fn pcre_fullinfo(code: *::detail::pcre, extra: *::detail::pcre_extra, what: ::detail::fullinfo_field, where: *mut c_void) -> c_int;
        }

    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_compile(pattern: *c_char, options: ::options, tableptr: *c_uchar) -> *pcre {
        assert!(is_not_null(pattern));
        let mut err: *c_char = null();
        let mut erroffset: c_int = 0;
        let code = unsafe { native::pcre_compile(pattern, options, &mut err, &mut erroffset, tableptr) };

        if is_null(code) {
            // "Otherwise, if  compilation  of  a  pattern fails, pcre_compile() returns
            // NULL, and sets the variable pointed to by errptr to point to a textual
            // error message. This is a static string that is part of the library. You
            // must not try to free it."
            // http://pcre.org/pcre.txt
            unsafe {
                let err_cstring = CString::new(err, false);
                error!("pcre_compile() failed at offset %u: %s", erroffset as uint, err_cstring.as_str().unwrap());
            }
            fail!("pcre_compile");
        }
        assert!(is_not_null(code) && erroffset == 0);

        code
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: ::options, ovector: *mut c_int, ovecsize: c_int) -> bool {
        assert!(is_not_null(code));
        assert!(ovecsize >= 0 && ovecsize % 3 == 0);
        let rc = unsafe { native::pcre_exec(code, extra, subject, length, startoffset, options, ovector, ovecsize) };
        if rc == PCRE_ERROR_NOMATCH {
            return false;
        } else if rc < 0 && rc != PCRE_ERROR_NULL {
            fail!("pcre_exec");
        }

        true
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_free(ptr: *c_void) {
        native::pcre_free(ptr);
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_free_study(extra: *pcre_extra) {
        unsafe { native::pcre_free_study(extra); }
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_fullinfo(code: *pcre, extra: *pcre_extra, what: fullinfo_field, where: *mut c_void) {
        assert!(is_not_null(code));
        let rc = unsafe { native::pcre_fullinfo(code, extra, what, where) };
        if rc < 0 && rc != PCRE_ERROR_NULL {
            fail!("pcre_fullinfo");
        }
    }

} // End `mod detail`.

pub struct Pcre {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    capture_count: uint

}

pub struct Match<'self> {

    priv subject: &'self str,

    priv ovector: ~[c_int]

}

impl Pcre {
    fn compile(pattern: &str) -> Pcre {
        Pcre::compile_with_options(pattern, 0)
    }

    fn compile_with_options(pattern: &str, options: options) -> Pcre {
        do pattern.with_c_str |pattern_c_str| {
            // Use the default character tables.
            let tableptr: *c_uchar = null();
            let code = detail::pcre_compile(pattern_c_str, options, tableptr);
            assert!(is_not_null(code));

            let extra: *detail::pcre_extra = null();

            let mut capture_count: c_int = 0;
            detail::pcre_fullinfo(code, extra, detail::PCRE_INFO_CAPTURECOUNT, &mut capture_count as *mut c_int as *mut c_void);

            Pcre {
                code: code,
                extra: extra,
                capture_count: capture_count as uint
            }
        }
    }

    fn exec<'a>(&self, subject: &'a str) -> Option<Match<'a>> {
        self.exec_from(subject, 0)
    }

    fn exec_from<'a>(&self, subject: &'a str, startoffset: uint) -> Option<Match<'a>> {
        self.exec_from_with_options(subject, startoffset, 0)
    }

    fn exec_from_with_options<'a>(&self, subject: &'a str, startoffset: uint, options: options) -> Option<Match<'a>> {
        let ovecsize = (self.capture_count + 1) * 3;
        let mut ovector: ~[c_int] = from_elem(ovecsize, 0 as c_int);

        unsafe {
            do subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'a>> {
                if detail::pcre_exec(self.code, self.extra, subject_c_str, subject.len() as c_int, startoffset as c_int, options, to_mut_ptr(ovector), ovecsize as c_int) {
                    Some(Match {
                        subject: subject,
                        // TODO: Is it possible to avoid to_owned()?
                        // Probably need multiple lifetime parameters:
                        // https://mail.mozilla.org/pipermail/rust-dev/2013-September/005829.html
                        ovector: ovector.slice_to((self.capture_count + 1) * 2).to_owned()
                    })
                } else {
                    None
                }
            }
        }
    }
}

impl Drop for Pcre {
    fn drop(&mut self) {
        if is_not_null(self.extra) {
            detail::pcre_free_study(self.extra);
            self.extra = null();
        }
        detail::pcre_free(self.code);
        self.code = null();
    }
}

impl<'self> Match<'self> {

    fn group_start(&self, n: uint) -> uint {
        self.ovector[(n * 2) as uint] as uint
    }

    fn group_end(&self, n: uint) -> uint {
        self.ovector[(n * 2 + 1) as uint] as uint
    }

    fn group_len(&self, n: uint) -> uint {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        (group_offsets[1] - group_offsets[0]) as uint
    }

    fn group(&self, n: uint) -> &'self str {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        let start = group_offsets[0];
        let end = group_offsets[1];
        self.subject.slice(start as uint, end as uint)
    }

}

#[cfg(test)]
mod tests {

    #[test]
    #[should_fail]
    fn test_compile_nul() {
        // Nul bytes are not allowed in the pattern string.
        ::Pcre::compile("\0abc");
    }

    #[test]
    #[should_fail]
    fn test_compile_bad_pattern() {
        ::Pcre::compile("[");
    }

    #[test]
    fn test_compile_capture_count() {
        let re = ::Pcre::compile("(?:abc)(def)");
        assert_eq!(re.capture_count, 1u);
    }

    #[test]
    fn test_exec_basic() {
        let re = ::Pcre::compile("^...$");
        assert_eq!(re.capture_count, 0u);
        let m = re.exec("abc").unwrap();
        assert_eq!(m.group(0), "abc");
    }

    #[test]
    fn test_exec_no_match() {
        let re = ::Pcre::compile("abc");
        assert!(re.exec("def").is_none());
    }

    #[test]
    fn test_exec_nul_byte() {
        // Nul bytes *are* allowed in subject strings, however.
        let re = ::Pcre::compile("abc\\0def");
        let m = re.exec("abc\0def").unwrap();
        assert_eq!(m.group(0), "abc\0def");
    }

    #[test]
    fn test_exec_from_basic() {
        let re = ::Pcre::compile("abc");
        let subject = "abcabc";
        let m1 = re.exec_from(subject, 1u).unwrap();
        assert_eq!(m1.group_start(0u), 3u);
        assert_eq!(m1.group_end(0u), 6u);
        assert_eq!(m1.group_len(0u), 3u);
        let m2 = re.exec(subject).unwrap();
        assert_eq!(m2.group_start(0u), 0u);
    }
}
<commit_msg>Remove a duplicate is_not_null() check.<commit_after>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "pcre", vers = "0.1")];
#[crate_type = "lib"];

use std::libc::{c_int, c_uchar, c_void};
use std::option::{None, Option, Some};
use std::ptr::{is_not_null, null};
use std::vec::{from_elem};
use std::vec::raw::{to_mut_ptr};

pub type options = c_int;

pub static PCRE_CASELESS: options = 0x00000001;
pub static PCRE_MULTILINE: options = 0x00000002;
pub static PCRE_DOTALL: options = 0x00000004;
pub static PCRE_EXTENDED: options = 0x00000008;
pub static PCRE_ANCHORED: options = 0x00000010;
pub static PCRE_DOLLAR_ENDONLY: options = 0x00000020;
pub static PCRE_EXTRA: options = 0x00000040;
pub static PCRE_NOTBOL: options = 0x00000080;
pub static PCRE_NOTEOL: options = 0x00000100;
pub static PCRE_UNGREEDY: options = 0x00000200;
pub static PCRE_NOTEMPTY: options = 0x00000400;
pub static PCRE_UTF8: options = 0x00000800;
pub static PCRE_UTF16: options = 0x00000800;
pub static PCRE_UTF32: options = 0x00000800;
pub static PCRE_NO_AUTO_CAPTURE: options = 0x00001000;
pub static PCRE_NO_UTF8_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF16_CHECK: options = 0x00002000;
pub static PCRE_NO_UTF32_CHECK: options = 0x00002000;
pub static PCRE_AUTO_CALLOUT: options = 0x00004000;
pub static PCRE_PARTIAL_SOFT: options = 0x00008000;
pub static PCRE_PARTIAL: options = 0x00008000;
pub static PCRE_NEVER_UTF: options = 0x00010000;
pub static PCRE_DFA_SHORTEST: options = 0x00010000;
pub static PCRE_DFA_RESTART: options = 0x00020000;
pub static PCRE_FIRSTLINE: options = 0x00040000;
pub static PCRE_DUPNAMES: options = 0x00080000;
pub static PCRE_NEWLINE_CR: options = 0x00100000;
pub static PCRE_NEWLINE_LF: options = 0x00200000;
pub static PCRE_NEWLINE_CRLF: options = 0x00300000;
pub static PCRE_NEWLINE_ANY: options = 0x00400000;
pub static PCRE_NEWLINE_ANYCRLF: options = 0x00500000;
pub static PCRE_BSR_ANYCRLF: options = 0x00800000;
pub static PCRE_BSR_UNICODE: options = 0x01000000;
pub static PCRE_JAVASCRIPT_COMPAT: options = 0x02000000;
pub static PCRE_NO_START_OPTIMIZE: options = 0x04000000;
pub static PCRE_NO_START_OPTIMISE: options = 0x04000000;
pub static PCRE_PARTIAL_HARD: options = 0x08000000;
pub static PCRE_NOTEMPTY_ATSTART: options = 0x10000000;
pub static PCRE_UCP: options = 0x20000000;

mod detail {

    use std::c_str::*;
    use std::libc::*;
    use std::ptr::*;

    pub type fullinfo_field = c_int;
    pub type pcre = c_void;
    pub type pcre_error = c_int;
    pub type pcre_extra = c_void;

    pub static PCRE_ERROR_NOMATCH: pcre_error = -1;
    pub static PCRE_ERROR_NULL: pcre_error = -2;

    pub static PCRE_INFO_CAPTURECOUNT: fullinfo_field = 2;

    mod native {

        use std::libc::*;

        #[link_args = "-lpcre.1"]
        extern {
            static pcre_free: extern "C" fn(ptr: *c_void);

            fn pcre_compile(pattern: *c_char, options: ::options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *::detail::pcre;
            fn pcre_exec(code: *::detail::pcre, extra: *::detail::pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: ::options, ovector: *mut c_int, ovecsize: c_int) -> ::detail::pcre_error;
            fn pcre_free_study(extra: *::detail::pcre_extra);
            fn pcre_fullinfo(code: *::detail::pcre, extra: *::detail::pcre_extra, what: ::detail::fullinfo_field, where: *mut c_void) -> c_int;
        }

    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_compile(pattern: *c_char, options: ::options, tableptr: *c_uchar) -> *pcre {
        assert!(is_not_null(pattern));
        let mut err: *c_char = null();
        let mut erroffset: c_int = 0;
        let code = unsafe { native::pcre_compile(pattern, options, &mut err, &mut erroffset, tableptr) };

        if is_null(code) {
            // "Otherwise, if  compilation  of  a  pattern fails, pcre_compile() returns
            // NULL, and sets the variable pointed to by errptr to point to a textual
            // error message. This is a static string that is part of the library. You
            // must not try to free it."
            // http://pcre.org/pcre.txt
            unsafe {
                let err_cstring = CString::new(err, false);
                error!("pcre_compile() failed at offset %u: %s", erroffset as uint, err_cstring.as_str().unwrap());
            }
            fail!("pcre_compile");
        }
        assert!(is_not_null(code) && erroffset == 0);

        code
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: ::options, ovector: *mut c_int, ovecsize: c_int) -> bool {
        assert!(is_not_null(code));
        assert!(ovecsize >= 0 && ovecsize % 3 == 0);
        let rc = unsafe { native::pcre_exec(code, extra, subject, length, startoffset, options, ovector, ovecsize) };
        if rc == PCRE_ERROR_NOMATCH {
            return false;
        } else if rc < 0 && rc != PCRE_ERROR_NULL {
            fail!("pcre_exec");
        }

        true
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_free(ptr: *c_void) {
        native::pcre_free(ptr);
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_free_study(extra: *pcre_extra) {
        unsafe { native::pcre_free_study(extra); }
    }

    #[fixed_stack_segment]
    #[inline(never)]
    pub fn pcre_fullinfo(code: *pcre, extra: *pcre_extra, what: fullinfo_field, where: *mut c_void) {
        assert!(is_not_null(code));
        let rc = unsafe { native::pcre_fullinfo(code, extra, what, where) };
        if rc < 0 && rc != PCRE_ERROR_NULL {
            fail!("pcre_fullinfo");
        }
    }

} // End `mod detail`.

pub struct Pcre {

    priv code: *detail::pcre,

    priv extra: *detail::pcre_extra,

    capture_count: uint

}

pub struct Match<'self> {

    priv subject: &'self str,

    priv ovector: ~[c_int]

}

impl Pcre {
    fn compile(pattern: &str) -> Pcre {
        Pcre::compile_with_options(pattern, 0)
    }

    fn compile_with_options(pattern: &str, options: options) -> Pcre {
        do pattern.with_c_str |pattern_c_str| {
            // Use the default character tables.
            let tableptr: *c_uchar = null();
            let code = detail::pcre_compile(pattern_c_str, options, tableptr);
            assert!(is_not_null(code));

            let extra: *detail::pcre_extra = null();

            let mut capture_count: c_int = 0;
            detail::pcre_fullinfo(code, extra, detail::PCRE_INFO_CAPTURECOUNT, &mut capture_count as *mut c_int as *mut c_void);

            Pcre {
                code: code,
                extra: extra,
                capture_count: capture_count as uint
            }
        }
    }

    fn exec<'a>(&self, subject: &'a str) -> Option<Match<'a>> {
        self.exec_from(subject, 0)
    }

    fn exec_from<'a>(&self, subject: &'a str, startoffset: uint) -> Option<Match<'a>> {
        self.exec_from_with_options(subject, startoffset, 0)
    }

    fn exec_from_with_options<'a>(&self, subject: &'a str, startoffset: uint, options: options) -> Option<Match<'a>> {
        let ovecsize = (self.capture_count + 1) * 3;
        let mut ovector: ~[c_int] = from_elem(ovecsize, 0 as c_int);

        unsafe {
            do subject.with_c_str_unchecked |subject_c_str| -> Option<Match<'a>> {
                if detail::pcre_exec(self.code, self.extra, subject_c_str, subject.len() as c_int, startoffset as c_int, options, to_mut_ptr(ovector), ovecsize as c_int) {
                    Some(Match {
                        subject: subject,
                        // TODO: Is it possible to avoid to_owned()?
                        // Probably need multiple lifetime parameters:
                        // https://mail.mozilla.org/pipermail/rust-dev/2013-September/005829.html
                        ovector: ovector.slice_to((self.capture_count + 1) * 2).to_owned()
                    })
                } else {
                    None
                }
            }
        }
    }
}

impl Drop for Pcre {
    fn drop(&mut self) {
        detail::pcre_free_study(self.extra);
        self.extra = null();
        detail::pcre_free(self.code);
        self.code = null();
    }
}

impl<'self> Match<'self> {

    fn group_start(&self, n: uint) -> uint {
        self.ovector[(n * 2) as uint] as uint
    }

    fn group_end(&self, n: uint) -> uint {
        self.ovector[(n * 2 + 1) as uint] as uint
    }

    fn group_len(&self, n: uint) -> uint {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        (group_offsets[1] - group_offsets[0]) as uint
    }

    fn group(&self, n: uint) -> &'self str {
        let group_offsets = self.ovector.slice_from((n * 2) as uint);
        let start = group_offsets[0];
        let end = group_offsets[1];
        self.subject.slice(start as uint, end as uint)
    }

}

#[cfg(test)]
mod tests {

    #[test]
    #[should_fail]
    fn test_compile_nul() {
        // Nul bytes are not allowed in the pattern string.
        ::Pcre::compile("\0abc");
    }

    #[test]
    #[should_fail]
    fn test_compile_bad_pattern() {
        ::Pcre::compile("[");
    }

    #[test]
    fn test_compile_capture_count() {
        let re = ::Pcre::compile("(?:abc)(def)");
        assert_eq!(re.capture_count, 1u);
    }

    #[test]
    fn test_exec_basic() {
        let re = ::Pcre::compile("^...$");
        assert_eq!(re.capture_count, 0u);
        let m = re.exec("abc").unwrap();
        assert_eq!(m.group(0), "abc");
    }

    #[test]
    fn test_exec_no_match() {
        let re = ::Pcre::compile("abc");
        assert!(re.exec("def").is_none());
    }

    #[test]
    fn test_exec_nul_byte() {
        // Nul bytes *are* allowed in subject strings, however.
        let re = ::Pcre::compile("abc\\0def");
        let m = re.exec("abc\0def").unwrap();
        assert_eq!(m.group(0), "abc\0def");
    }

    #[test]
    fn test_exec_from_basic() {
        let re = ::Pcre::compile("abc");
        let subject = "abcabc";
        let m1 = re.exec_from(subject, 1u).unwrap();
        assert_eq!(m1.group_start(0u), 3u);
        assert_eq!(m1.group_end(0u), 6u);
        assert_eq!(m1.group_len(0u), 3u);
        let m2 = re.exec(subject).unwrap();
        assert_eq!(m2.group_start(0u), 0u);
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::io;

use byteorder::{BigEndian, WriteBytesExt};

use mio;

use EventLoop;
use Message;
use protocol::Protocol as Protocol;
use transport::Connection as Connection;

pub enum SendStatus {
    Rejected(Message),   // Message can't be sent at the moment
    Completed,       // Message has been successfully sent
    Started          // Message has been partially sent, will finish later
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum State {
	Handshake,
	Connected
}

// A pipe is responsible for handshaking with its peer and transfering messages over a connection.
// That means adding the size prefix to message bytes transfering the bytes
// according to the connection readiness and the operation progress
pub struct Pipe {
	addr: String,
	state: State,
	handshake_state: HandshakePipeState,
	connected_state: ConnectedPipeState
}

impl Pipe {

	pub fn new(id: usize, addr: String, protocol: &Protocol, connection: Box<Connection>) -> Pipe {
		let conn_ref = Rc::new(RefCell::new(connection));

		Pipe {
			addr: addr,
			state: State::Handshake,
			handshake_state: HandshakePipeState::new(id, protocol, conn_ref.clone()),
			connected_state: ConnectedPipeState::new(id, conn_ref.clone())
		}
	}

	// result can be :
	//  - can't send (write prefix would block), transfer back msg ownership
	//  - message successfully sent
	//  - message partially sent, will finish later
	//  - tried to send, but an error occured while sending or write prefix partial write, msg is lost

	pub fn send(&mut self, event_loop: &mut EventLoop, msg: Message) -> io::Result<SendStatus> {
		self.get_state().send(event_loop, msg)
	}

	pub fn addr(self) -> String {
		self.addr
	}

	fn get_state<'a>(&'a mut self) -> &'a mut PipeState {
		match self.state {
			State::Handshake => &mut self.handshake_state,
			State::Connected => &mut self.connected_state
		}
	}

	fn set_state(&mut self, state: State, event_loop: &mut EventLoop) -> io::Result<()> {
		self.state = state;
		self.get_state().enter(event_loop)
	}

	pub fn init(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		self.set_state(State::Handshake, event_loop)
	}

	pub fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<()> {
		if events.is_hup() {
			return Err(io::Error::new(io::ErrorKind::ConnectionReset, "hup"));
		}

		if events.is_error() {
			return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "hup"));
		}

		if let Some(new_state) = try!(self.get_state().ready(event_loop, events)) {
			return self.set_state(new_state, event_loop);
		}

		Ok(())
	}

}

trait PipeState {
	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()>;
	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>>;

	fn send(&mut self, event_loop: &mut EventLoop, msg: Message) -> io::Result<SendStatus>;
}

struct HandshakePipeState {
	id: usize,
	protocol_id: u16,
	protocol_peer_id: u16,
	connection: Rc<RefCell<Box<Connection>>>,
	sent: bool,
	received: bool
}

impl HandshakePipeState {

	fn new(id: usize, protocol: &Protocol, connection: Rc<RefCell<Box<Connection>>>) -> HandshakePipeState {
		HandshakePipeState {
			id: id,
			protocol_id: protocol.id(),
			protocol_peer_id: protocol.peer_id(),
			connection: connection,
			sent: false,
			received: false }
	}

	fn check_received_handshake(&self, handshake: &[u8; 8]) -> io::Result<()> {
		let mut expected_handshake = vec!(0, 83, 80, 0);
		try!(expected_handshake.write_u16::<BigEndian>(self.protocol_peer_id));
		try!(expected_handshake.write_u16::<BigEndian>(0));
		let mut both = handshake.iter().zip(expected_handshake.iter());

		if both.all(|(l,r)| l == r) {
			Ok(())
		} else {
			Err(io::Error::new(io::ErrorKind::InvalidData, "received wrong handshake"))
		}
	}

	fn check_sent_handshake(&self, written: Option<usize>) -> io::Result<()> {
		match written {
			Some(8) => Ok(()),
			_ => Err(io::Error::new(io::ErrorKind::Other, "failed to send handshake"))
		}
	}

	fn read_handshake(&mut self) -> io::Result<()> {
		let mut handshake = [0u8; 8];
		let mut connection = self.connection.borrow_mut();
		try!(
			connection.try_read(&mut handshake).
			and_then(|_| self.check_received_handshake(&handshake)));
		debug!("[{}] handshake received.", self.id);
		self.received = true;
		Ok(())
	}

	fn write_handshake(&mut self) -> io::Result<()> {
		// handshake is Zero, 'S', 'P', Version, Proto, Rsvd
		let mut handshake = vec!(0, 83, 80, 0);
		try!(handshake.write_u16::<BigEndian>(self.protocol_id));
		try!(handshake.write_u16::<BigEndian>(0));
		let mut connection = self.connection.borrow_mut();
		try!(
			connection.try_write(&handshake).
			and_then(|w| self.check_sent_handshake(w)));
		debug!("[{}] handshake sent.", self.id);
		self.sent = true;
		Ok(())
	}

	fn register(&self, event_loop: &mut EventLoop, interest: mio::EventSet, poll_opt: mio::PollOpt) -> io::Result<()> {
		let token = mio::Token(self.id);
		let connection = self.connection.borrow();
		let fd = connection.as_evented();

		event_loop.register_opt(fd, token, interest, poll_opt)
	}

	fn reregister(&self, event_loop: &mut EventLoop, interest: mio::EventSet, poll_opt: mio::PollOpt) -> io::Result<()> {
		let token = mio::Token(self.id);
		let connection = self.connection.borrow();
		let fd = connection.as_evented();

		event_loop.reregister(fd, token, interest, poll_opt)
	}

}

impl PipeState for HandshakePipeState {

	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		debug!("[{}] enter handshake state", self.id);
		self.sent = false;
		self.received = false;

		let interest = mio::EventSet::readable() | mio::EventSet::writable() | mio::EventSet::hup();
		let poll_opt = mio::PollOpt::oneshot();

		try!(self.register(event_loop, interest, poll_opt));

		Ok(())
	}

	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>> {
		if !self.received && events.is_readable() {
			try!(self.read_handshake());
		}

		if !self.sent && events.is_writable() {
			try!(self.write_handshake());
		}

		if self.received && self.sent {
			return Ok(Some(State::Connected));
		}

		let mut interest = mio::EventSet::hup();
		let poll_opt = mio::PollOpt::oneshot();

		if !self.received {
			interest = interest | mio::EventSet::readable();
		}
		if !self.sent {
			interest = interest | mio::EventSet::writable();
		}

		try!(self.reregister(event_loop, interest, poll_opt));

		Ok(None)
	}

	fn send(&mut self, event_loop: &mut EventLoop, msg: Message) -> io::Result<SendStatus> {
		Ok(SendStatus::Rejected(msg))
	}
}

struct ConnectedPipeState {
	id: usize,
	connection: Rc<RefCell<Box<Connection>>>
}

impl ConnectedPipeState {
	fn new(id: usize, connection: Rc<RefCell<Box<Connection>>>) -> ConnectedPipeState {
		ConnectedPipeState {
			id: id,
			connection: connection
		}
	}
}

impl PipeState for ConnectedPipeState {
	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		debug!("[{}] enter connected state", self.id);
		let token = mio::Token(self.id);
		let connection = self.connection.borrow_mut();
		let fd = connection.as_evented();
		let interest = mio::EventSet::hup() | mio::EventSet::error();
		let poll_opt = mio::PollOpt::edge();
		try!(event_loop.reregister(fd, token, interest, poll_opt));
		Ok(())
	}

	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>> {
		Ok(None)
	}

	fn send(&mut self, event_loop: &mut EventLoop, msg: Message) -> io::Result<SendStatus> {
		Ok(SendStatus::Rejected(msg))
	}

	/*fn send(&mut self, msg: Message) -> io::Result<()> {
		let mut connection = self.connection.borrow_mut();
		let mut prefix = Vec::with_capacity(8);
		try!(prefix.write_u64::<BigEndian>(msg.len() as u64));

		try!(connection.try_write(&prefix));

		if msg.get_header().len() > 0 {
			try!(connection.try_write(msg.get_header()));
		}

		if msg.get_body().len() > 0 {
			try!(connection.try_write(msg.get_body()));
		}

		debug!("msg sent !");
		Ok(())
	}*/
}
<commit_msg>Start working and sending for push<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::io;

use byteorder::{BigEndian, WriteBytesExt};

use mio;

use EventLoop;
use Message;
use protocol::Protocol as Protocol;
use transport::Connection as Connection;

// this is wrong, it works only for Push
// Pub for example wants all pipe to acquire the message
// So this logic must be in a pipe sender held by the protocol
// Shit !!!
pub enum SendStatus {
    Rejected(Message),   // Message can't be sent at the moment
    Completed,       // Message has been successfully sent
    Started          // Message has been partially sent, will finish later
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum State {
	Handshake,
	Connected
}

// A pipe is responsible for handshaking with its peer and transfering messages over a connection.
// That means adding the size prefix to message bytes transfering the bytes
// according to the connection readiness and the operation progress
pub struct Pipe {
	addr: String,
	state: State,
	handshake_state: HandshakePipeState,
	connected_state: ConnectedPipeState
}

impl Pipe {

	pub fn new(id: usize, addr: String, protocol: &Protocol, connection: Box<Connection>) -> Pipe {
		let conn_ref = Rc::new(RefCell::new(connection));

		Pipe {
			addr: addr,
			state: State::Handshake,
			handshake_state: HandshakePipeState::new(id, protocol, conn_ref.clone()),
			connected_state: ConnectedPipeState::new(id, conn_ref.clone())
		}
	}

	// result can be :
	//  - can't send (write prefix would block), transfer back msg ownership
	//  - message successfully sent
	//  - message partially sent, will finish later
	//  - tried to send, but an error occured while sending or write prefix partial write, msg is lost

	pub fn send(&mut self, event_loop: &mut EventLoop, msg: Message) -> io::Result<SendStatus> {
		self.get_state().send(event_loop, msg)
	}

	pub fn addr(self) -> String {
		self.addr
	}

	fn get_state<'a>(&'a mut self) -> &'a mut PipeState {
		match self.state {
			State::Handshake => &mut self.handshake_state,
			State::Connected => &mut self.connected_state
		}
	}

	fn set_state(&mut self, state: State, event_loop: &mut EventLoop) -> io::Result<()> {
		self.state = state;
		self.get_state().enter(event_loop)
	}

	pub fn init(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		self.set_state(State::Handshake, event_loop)
	}

	pub fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<()> {
		if events.is_hup() {
			return Err(io::Error::new(io::ErrorKind::ConnectionReset, "hup"));
		}

		if events.is_error() {
			return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "hup"));
		}

		if let Some(new_state) = try!(self.get_state().ready(event_loop, events)) {
			return self.set_state(new_state, event_loop);
		}

		Ok(())
	}

}

trait PipeState {
	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()>;
	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>>;

	fn send(&mut self, event_loop: &mut EventLoop, msg: Message) -> io::Result<SendStatus>;
}

struct HandshakePipeState {
	id: usize,
	protocol_id: u16,
	protocol_peer_id: u16,
	connection: Rc<RefCell<Box<Connection>>>,
	sent: bool,
	received: bool
}

impl HandshakePipeState {

	fn new(id: usize, protocol: &Protocol, connection: Rc<RefCell<Box<Connection>>>) -> HandshakePipeState {
		HandshakePipeState {
			id: id,
			protocol_id: protocol.id(),
			protocol_peer_id: protocol.peer_id(),
			connection: connection,
			sent: false,
			received: false }
	}

	fn check_received_handshake(&self, handshake: &[u8; 8]) -> io::Result<()> {
		let mut expected_handshake = vec!(0, 83, 80, 0);
		try!(expected_handshake.write_u16::<BigEndian>(self.protocol_peer_id));
		try!(expected_handshake.write_u16::<BigEndian>(0));
		let mut both = handshake.iter().zip(expected_handshake.iter());

		if both.all(|(l,r)| l == r) {
			Ok(())
		} else {
			Err(io::Error::new(io::ErrorKind::InvalidData, "received wrong handshake"))
		}
	}

	fn check_sent_handshake(&self, written: Option<usize>) -> io::Result<()> {
		match written {
			Some(8) => Ok(()),
			_ => Err(io::Error::new(io::ErrorKind::Other, "failed to send handshake"))
		}
	}

	fn read_handshake(&mut self) -> io::Result<()> {
		let mut handshake = [0u8; 8];
		let mut connection = self.connection.borrow_mut();
		try!(
			connection.try_read(&mut handshake).
			and_then(|_| self.check_received_handshake(&handshake)));
		debug!("[{}] handshake received.", self.id);
		self.received = true;
		Ok(())
	}

	fn write_handshake(&mut self) -> io::Result<()> {
		// handshake is Zero, 'S', 'P', Version, Proto, Rsvd
		let mut handshake = vec!(0, 83, 80, 0);
		try!(handshake.write_u16::<BigEndian>(self.protocol_id));
		try!(handshake.write_u16::<BigEndian>(0));
		let mut connection = self.connection.borrow_mut();
		try!(
			connection.try_write(&handshake).
			and_then(|w| self.check_sent_handshake(w)));
		debug!("[{}] handshake sent.", self.id);
		self.sent = true;
		Ok(())
	}

	fn register(&self, event_loop: &mut EventLoop, interest: mio::EventSet, poll_opt: mio::PollOpt) -> io::Result<()> {
		let token = mio::Token(self.id);
		let connection = self.connection.borrow();
		let fd = connection.as_evented();

		event_loop.register_opt(fd, token, interest, poll_opt)
	}

	fn reregister(&self, event_loop: &mut EventLoop, interest: mio::EventSet, poll_opt: mio::PollOpt) -> io::Result<()> {
		let token = mio::Token(self.id);
		let connection = self.connection.borrow();
		let fd = connection.as_evented();

		event_loop.reregister(fd, token, interest, poll_opt)
	}

}

impl PipeState for HandshakePipeState {

	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		debug!("[{}] enter handshake state", self.id);
		self.sent = false;
		self.received = false;

		let interest = mio::EventSet::readable() | mio::EventSet::writable() | mio::EventSet::hup();
		let poll_opt = mio::PollOpt::oneshot();

		try!(self.register(event_loop, interest, poll_opt));

		Ok(())
	}

	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>> {
		if !self.received && events.is_readable() {
			try!(self.read_handshake());
		}

		if !self.sent && events.is_writable() {
			try!(self.write_handshake());
		}

		if self.received && self.sent {
			return Ok(Some(State::Connected));
		}

		let mut interest = mio::EventSet::hup();
		let poll_opt = mio::PollOpt::oneshot();

		if !self.received {
			interest = interest | mio::EventSet::readable();
		}
		if !self.sent {
			interest = interest | mio::EventSet::writable();
		}

		try!(self.reregister(event_loop, interest, poll_opt));

		Ok(None)
	}

	fn send(&mut self, event_loop: &mut EventLoop, msg: Message) -> io::Result<SendStatus> {
		Ok(SendStatus::Rejected(msg))
	}
}

struct ConnectedPipeState {
	id: usize,
	connection: Rc<RefCell<Box<Connection>>>
}

impl ConnectedPipeState {
	fn new(id: usize, connection: Rc<RefCell<Box<Connection>>>) -> ConnectedPipeState {
		ConnectedPipeState {
			id: id,
			connection: connection
		}
	}
}

impl PipeState for ConnectedPipeState {
	fn enter(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
		debug!("[{}] enter connected state", self.id);
		let token = mio::Token(self.id);
		let connection = self.connection.borrow_mut();
		let fd = connection.as_evented();
		let interest = mio::EventSet::hup() | mio::EventSet::error();
		let poll_opt = mio::PollOpt::edge();
		try!(event_loop.reregister(fd, token, interest, poll_opt));
		Ok(())
	}

	fn ready(&mut self, event_loop: &mut EventLoop, events: mio::EventSet)-> io::Result<Option<State>> {
		Ok(None)
	}

	fn send(&mut self, event_loop: &mut EventLoop, msg: Message) -> io::Result<SendStatus> {
		Ok(SendStatus::Rejected(msg))
	}

	/*fn send(&mut self, msg: Message) -> io::Result<()> {
		let mut connection = self.connection.borrow_mut();
		let mut prefix = Vec::with_capacity(8);
		try!(prefix.write_u64::<BigEndian>(msg.len() as u64));

		try!(connection.try_write(&prefix));

		if msg.get_header().len() > 0 {
			try!(connection.try_write(msg.get_header()));
		}

		if msg.get_body().len() > 0 {
			try!(connection.try_write(msg.get_body()));
		}

		debug!("msg sent !");
		Ok(())
	}*/
}
<|endoftext|>


<commit_before>use std::iter;

pub fn verse(n: int) -> ~str {
    match n {
        0 =>
            ~"No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n",
        1 =>
            ~"1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n",
        2 =>
            ~"2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n",
        n if n > 2 && n <= 99 =>
            format!("{n} bottles of beer on the wall, {n} bottles of beer.\nTake one down and pass it around, {n_minus_1} bottles of beer on the wall.\n", n=n, n_minus_1=n - 1),
        _ =>
            fail!(),
    }
}

pub fn sing(start: int, end: int) -> ~str {
    let mut s = iter::range_inclusive(end, start)
        .invert()
        .map(verse)
        .to_owned_vec()
        .connect("\n");
    s.push_char('\n');
    s
}
<commit_msg>rust - add whitespace to beer-song to ensure logic is in the first 80 cols and strings wrap before 100<commit_after>use std::iter;

pub fn verse(n: int) -> ~str {
    match n {
        0 =>
            ~"No more bottles of beer on the wall, no more bottles of beer.\n\
              Go to the store and buy some more, 99 bottles of beer on the wall.\n",
        1 =>
            ~"1 bottle of beer on the wall, 1 bottle of beer.\n\
              Take it down and pass it around, no more bottles of beer on the wall.\n",
        2 =>
            ~"2 bottles of beer on the wall, 2 bottles of beer.\n\
              Take one down and pass it around, 1 bottle of beer on the wall.\n",
        n if n > 2 && n <= 99 =>
            format!(
                "{n} bottles of beer on the wall, {n} bottles of beer.\n\
                 Take one down and pass it around, {n_minus_1} bottles of beer on the wall.\n",
                n=n,
                n_minus_1=n - 1),
        _ =>
            fail!(),
    }
}

pub fn sing(start: int, end: int) -> ~str {
    let mut s = iter::range_inclusive(end, start)
        .invert()
        .map(verse)
        .to_owned_vec()
        .connect("\n");
    s.push_char('\n');
    s
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;

struct App {
    window: RcWindow,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    virtual_cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0f64;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.virtual_cursor_pos = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs, window: RcWindow) {
        // we need to pass the window into update (and set the size here) because
        // using the update event from the window events is currently broken.
        self.translator.set_size(window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color, square, c.transform, gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.virtual_cursor_pos[0], self.virtual_cursor_pos[1], 5.0);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse([0.0, 1.0, 0.0, 1.0], dot, c.transform, gl));
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, (WINDOW_SIZE.1 as f64) * 0.85],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        virtual_cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in  app.window.clone().events() {
        let app_window = app.window.clone();
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u, app_window); },
            Event::Input(i) => { app.input(&i); },
            _ => { }
        }
    }
}
<commit_msg>Make cursor dot color a const rather than a literal in the function call<commit_after>#![allow(unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;

struct App {
    window: RcWindow,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    virtual_cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0f64;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.virtual_cursor_pos = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs, window: RcWindow) {
        // we need to pass the window into update (and set the size here) because
        // using the update event from the window events is currently broken.
        self.translator.set_size(window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color, square, c.transform, gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.virtual_cursor_pos[0], self.virtual_cursor_pos[1], 5.0);
            const CURSOR_DOT_COLOR: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(CURSOR_DOT_COLOR, dot, c.transform, gl));
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, (WINDOW_SIZE.1 as f64) * 0.85],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        virtual_cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in  app.window.clone().events() {
        let app_window = app.window.clone();
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u, app_window); },
            Event::Input(i) => { app.input(&i); },
            _ => { }
        }
    }
}
<|endoftext|>


<commit_before>// In order to use YAML to define your CLI you must compile clap with the "yaml" feature becasue
// it's **not** included by default.
//
// In order to do this, ensure your Cargo.toml looks like one of the following:
//
// [dependencies.clap]
// features = ["yaml"]
//
// __OR__
//
// [dependencies]
// clap = { features = ["yaml"] }

// Using yaml requires calling a clap macro `load_yaml!()` so we must use the '#[macro_use]'
// directive
#[macro_use]
extern crate clap;

#[cfg(feature = "yaml")]
fn main() {
    use clap::App;

    // To load a yaml file containing our CLI definition such as the example '17_yaml.yml' we can
    // use the convenience macro which loads the file at compile relative to the current file
    // similiar to how modules are found.
    //
    // Then we pass that yaml object to App to build the CLI.
    //
    // Finally we call get_matches() to start the parsing process. We use the matches just as we
    // normally would
    let yml = load_yaml!("17_yaml.yml");
    let m = App::from_yaml(yml).get_matches();

    // Because the example 17_yaml.yml is rather large we'll just look a single arg so you can
    // see that it works...
    if let Some(mode) = m.value_of("mode") {
        match mode {
            "fast" => println!("We're really going now!"),
            "slow" => println!("Awwww, too slow :("),
            _      => unreachable!()
        }
    } else {
        println!("--mode <MODE> wasn't used...");
    }
}

#[cfg(not(feature = "yaml"))]
fn main() {
    // As stated above, if clap is not compiled with the YAML feature, it is disabled.
    println!("YAML feature is disabled.");
    println!("Pass --features yaml to cargo when trying this example.");
}
<commit_msg>fix(yaml-example): inconsistent args<commit_after>// In order to use YAML to define your CLI you must compile clap with the "yaml" feature becasue
// it's **not** included by default.
//
// In order to do this, ensure your Cargo.toml looks like one of the following:
//
// [dependencies.clap]
// features = ["yaml"]
//
// __OR__
//
// [dependencies]
// clap = { features = ["yaml"] }

// Using yaml requires calling a clap macro `load_yaml!()` so we must use the '#[macro_use]'
// directive
#[macro_use]
extern crate clap;

#[cfg(feature = "yaml")]
fn main() {
    use clap::App;

    // To load a yaml file containing our CLI definition such as the example '17_yaml.yml' we can
    // use the convenience macro which loads the file at compile relative to the current file
    // similiar to how modules are found.
    //
    // Then we pass that yaml object to App to build the CLI.
    //
    // Finally we call get_matches() to start the parsing process. We use the matches just as we
    // normally would
    let yml = load_yaml!("17_yaml.yml");
    let m = App::from_yaml(yml).get_matches();

    // Because the example 17_yaml.yml is rather large we'll just look a single arg so you can
    // see that it works...
    if let Some(mode) = m.value_of("mode") {
        match mode {
            "vi" => println!("You are using vi"),
            "emacs" => println!("You are using emacs..."),
            _      => unreachable!()
        }
    } else {
        println!("--mode <MODE> wasn't used...");
    }
}

#[cfg(not(feature = "yaml"))]
fn main() {
    // As stated above, if clap is not compiled with the YAML feature, it is disabled.
    println!("YAML feature is disabled.");
    println!("Pass --features yaml to cargo when trying this example.");
}
<|endoftext|>


<commit_before>extern crate rustyline;

use rustyline::completion::FilenameCompleter;
use rustyline::error::ReadlineError;
use rustyline::Editor;

fn main() {
    let c = FilenameCompleter::new();
    let mut rl = Editor::new();
    rl.set_completer(Some(&c));
    if let Err(_) = rl.load_history("history.txt") {
        println!("No previous history.");
    }
    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                println!("Line: {}", line);
            },
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }
    rl.save_history("history.txt").unwrap();
}
<commit_msg>Update example with an ansi formatted prompt.<commit_after>extern crate rustyline;

use rustyline::completion::FilenameCompleter;
use rustyline::error::ReadlineError;
use rustyline::Editor;

fn main() {
    let c = FilenameCompleter::new();
    let mut rl = Editor::new();
    rl.set_completer(Some(&c));
    if let Err(_) = rl.load_history("history.txt") {
        println!("No previous history.");
    }
    loop {
        let readline = rl.readline("\x1b[1;32m>>\x1b[0m ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                println!("Line: {}", line);
            },
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }
    rl.save_history("history.txt").unwrap();
}
<|endoftext|>