<commit_before>#[macro_use]
extern crate lazy_static;

use diffus::{
    edit::{self, string},
    Diffable,
};
use regex::Regex;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::str;

const ADD: &str = "\x1b[32m"; // Green
const REMOVE: &str = "\x1b[31m"; // Red
const HUNK_HEADER: &str = "\x1b[36m"; // Cyan
const NO_EOF_NEWLINE: &str = "\x1b[2m"; // Faint

const INVERSE_VIDEO: &str = "\x1b[7m";
const NOT_INVERSE_VIDEO: &str = "\x1b[27m";

const BOLD: &str = "\x1b[1m";

const NORMAL: &str = "\x1b[0m";

lazy_static! {
    static ref STATIC_HEADERS: Vec<(Regex, &'static str)> = vec![
        (Regex::new("^diff ").unwrap(), BOLD),
        (Regex::new("^index ").unwrap(), BOLD),
        (Regex::new("^--- ").unwrap(), BOLD),
        (Regex::new("^\\+\\+\\+ ").unwrap(), BOLD),
        (Regex::new("^@@ ").unwrap(), HUNK_HEADER),
    ];
}

/// Format add and remove lines in ADD and REMOVE colors.
///
/// No intra-line refinement.
#[must_use]
fn simple_format_adds_and_removes(adds: &[String], removes: &[String]) -> Vec<String> {
    let mut lines: Vec<String> = Vec::new();

    for remove_line in removes {
        lines.push(format!("{}{}{}", REMOVE, remove_line, NORMAL));
    }

    for add_line in adds {
        lines.push(format!("{}{}{}", ADD, add_line, NORMAL))
    }

    return lines;
}

/// Joins multiple lines into a single string.
///
/// The first character of each line is skipped, because it is assumed to be
/// either a `+` or a `-` in a diff.
///
/// Between each joined line a `\n` linefeed character is inserted.
#[must_use]
fn join_skip_first(lines: &[String]) -> String {
    let mut joined = String::new();
    for line in lines {
        if !joined.is_empty() {
            joined.push_str("\n")
        }
        joined.push_str(&line[1..]);
    }

    return joined;
}

#[must_use]
fn format_adds_and_removes(adds: &[String], removes: &[String]) -> Vec<String> {
    if adds.is_empty() {
        return simple_format_adds_and_removes(adds, removes);
    }

    if removes.is_empty() {
        return simple_format_adds_and_removes(adds, removes);
    }

    // Join inputs by linefeeds into strings
    let adds = join_skip_first(adds);
    let removes = join_skip_first(removes);

    // Find diffs between adds and removals
    let mut highlighted_adds = String::new();
    let mut highlighted_removes = String::new();
    let mut adds_is_inverse = false;
    let mut removes_is_inverse = false;
    let diff = removes.diff(&adds);
    match diff {
        edit::Edit::Copy(unchanged) => {
            highlighted_adds.push_str(unchanged);
            highlighted_removes.push_str(unchanged);
        }
        edit::Edit::Change(diff) => {
            diff.into_iter()
                .map(|edit| {
                    match edit {
                        string::Edit::Copy(elem) => {
                            if adds_is_inverse {
                                highlighted_adds.push_str(NOT_INVERSE_VIDEO);
                            }
                            adds_is_inverse = false;

                            if removes_is_inverse {
                                highlighted_removes.push_str(NOT_INVERSE_VIDEO);
                            }
                            removes_is_inverse = false;

                            highlighted_adds.push(elem);
                            highlighted_removes.push(elem);
                        }
                        string::Edit::Insert(elem) => {
                            if !adds_is_inverse {
                                highlighted_adds.push_str(INVERSE_VIDEO);
                            }
                            adds_is_inverse = true;

                            if elem == '\n' {
                                // Make sure the highlighted linefeed is visible
                                highlighted_adds.push('⏎');

                                // This will be reset by the linefeed, so we need to re-inverse on the next line
                                adds_is_inverse = false;
                            }
                            highlighted_adds.push(elem);
                        }
                        string::Edit::Remove(elem) => {
                            if !removes_is_inverse {
                                highlighted_removes.push_str(INVERSE_VIDEO);
                            }
                            removes_is_inverse = true;

                            if elem == '\n' {
                                // Make sure the highlighted linefeed is visible
                                highlighted_removes.push('⏎');

                                // This will be reset by the linefeed, so we need to re-inverse on the next line
                                removes_is_inverse = false;
                            }
                            highlighted_removes.push(elem);
                        }
                    };
                })
                .for_each(drop);
        }
    }

    let mut lines: Vec<String> = Vec::new();
    for highlighted_remove in highlighted_removes.lines() {
        lines.push(format!("{}-{}{}", REMOVE, highlighted_remove, NORMAL));
    }
    for highlighted_add in highlighted_adds.lines() {
        lines.push(format!("{}+{}{}", ADD, highlighted_add, NORMAL));
    }

    return lines;
}

#[must_use]
fn get_fixed_highlight(line: &str) -> &str {
    for static_header in STATIC_HEADERS.iter() {
        let re = &static_header.0;
        if re.is_match(line) {
            return static_header.1;
        }
    }

    return "";
}

fn print(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    stream.write(text.as_bytes()).unwrap();
}

fn println(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    print(stream, &text);
    print(stream, "\n");
}

fn highlight_diff(input: &mut dyn io::Read, output: &mut dyn io::Write) {
    let mut adds: Vec<String> = Vec::new();
    let mut removes: Vec<String> = Vec::new();
    let input = BufReader::new(input);
    let output = &mut BufWriter::new(output);
    for line in input.lines() {
        let line = line.unwrap();

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            // Drain outstanding adds / removes
            for line in format_adds_and_removes(&adds, &removes) {
                println(output, &line);
            }
            adds.clear();
            removes.clear();

            print(output, fixed_highlight);
            print(output, &line);
            println(output, NORMAL);
            continue;
        }

        // Collect adds / removes
        if !line.is_empty() && line.chars().next().unwrap() == '+' {
            adds.push(line);
            continue;
        } else if !line.is_empty() && line.chars().next().unwrap() == '-' {
            removes.push(line);
            continue;
        }

        // Drain outstanding adds / removes
        for line in format_adds_and_removes(&adds, &removes) {
            println(output, &line);
        }
        adds.clear();
        removes.clear();

        // Print current line
        println(output, &line);
    }
    for line in format_adds_and_removes(&adds, &removes) {
        println(output, &line);
    }
}

fn main() {
    highlight_diff(&mut io::stdin().lock(), &mut io::stdout());
}

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_join_skip_first() {
        assert_eq!(
            join_skip_first(&["Xa".to_string(), "Xb".to_string()]),
            "a\nb"
        );
    }

    #[test]
    fn test_simple_format_adds_and_removes() {
        let empty: Vec<String> = Vec::new();
        assert_eq!(simple_format_adds_and_removes(&empty, &empty), empty);

        // Test adds-only
        assert_eq!(
            simple_format_adds_and_removes(&["+a".to_string()], &empty),
            ["".to_string() + ADD + "+a" + NORMAL]
        );
        assert_eq!(
            simple_format_adds_and_removes(&["+a".to_string(), "+b".to_string()], &empty),
            [
                "".to_string() + ADD + "+a" + NORMAL,
                "".to_string() + ADD + "+b" + NORMAL,
            ]
        );

        // Test removes-only
        assert_eq!(
            simple_format_adds_and_removes(&empty, &["-a".to_string()]),
            ["".to_string() + REMOVE + "-a" + NORMAL]
        );
        assert_eq!(
            simple_format_adds_and_removes(&empty, &["-a".to_string(), "-b".to_string()]),
            [
                "".to_string() + REMOVE + "-a" + NORMAL,
                "".to_string() + REMOVE + "-b" + NORMAL,
            ]
        );
    }

    #[test]
    fn test_quote_change() {
        assert_eq!(
            format_adds_and_removes(&["+[quotes]".to_string()], &["-<quotes>".to_string()]),
            [
                format!(
                    "{}-{}<{}quotes{}>{}",
                    REMOVE, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
                format!(
                    "{}+{}[{}quotes{}]{}",
                    ADD, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
            ]
        )
    }

    fn remove(text: &str) -> String {
        return format!("{}{}{}", REMOVE, text, NORMAL);
    }

    fn add(text: &str) -> String {
        return format!("{}{}{}", ADD, text, NORMAL);
    }

    #[test]
    fn test_remove_trailing_newline() {
        let mut input = "-hej\n\
            +hej\n\
            \\ No newline at end of file\n\
            "
        .as_bytes();

        let expected = format!(
            "{}\n{}\n{}\n",
            remove(&format!("-hej{}⏎", INVERSE_VIDEO)),
            add("+hej"),
            format!("{}\\ No newline at end of file{}", NO_EOF_NEWLINE, NORMAL)
        );

        let mut output: Vec<u8> = Vec::new();
        highlight_diff(&mut input, &mut output);
        assert_eq!(std::str::from_utf8(&output).unwrap(), expected);
    }
}
<commit_msg>Highlight multi line strings<commit_after>#[macro_use]
extern crate lazy_static;

use diffus::{
    edit::{self, string},
    Diffable,
};
use regex::Regex;
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::str;

const ADD: &str = "\x1b[32m"; // Green
const REMOVE: &str = "\x1b[31m"; // Red
const HUNK_HEADER: &str = "\x1b[36m"; // Cyan
const NO_EOF_NEWLINE: &str = "\x1b[2m"; // Faint

const INVERSE_VIDEO: &str = "\x1b[7m";
const NOT_INVERSE_VIDEO: &str = "\x1b[27m";

const BOLD: &str = "\x1b[1m";

const NORMAL: &str = "\x1b[0m";

lazy_static! {
    static ref STATIC_HEADERS: Vec<(Regex, &'static str)> = vec![
        (Regex::new("^diff ").unwrap(), BOLD),
        (Regex::new("^index ").unwrap(), BOLD),
        (Regex::new("^--- ").unwrap(), BOLD),
        (Regex::new("^\\+\\+\\+ ").unwrap(), BOLD),
        (Regex::new("^@@ ").unwrap(), HUNK_HEADER),
    ];
}

/// Format add and remove lines in ADD and REMOVE colors.
///
/// No intra-line refinement.
#[must_use]
fn simple_format_adds_and_removes(adds: &String, removes: &String) -> Vec<String> {
    let mut lines: Vec<String> = Vec::new();

    for remove_line in removes.lines() {
        lines.push(format!("{}-{}{}", REMOVE, remove_line, NORMAL));
    }

    for add_line in adds.lines() {
        lines.push(format!("{}+{}{}", ADD, add_line, NORMAL))
    }

    return lines;
}

#[must_use]
fn format_adds_and_removes(adds: &String, removes: &String) -> Vec<String> {
    if adds.is_empty() {
        return simple_format_adds_and_removes(adds, removes);
    }

    if removes.is_empty() {
        return simple_format_adds_and_removes(adds, removes);
    }

    // Find diffs between adds and removals
    let mut highlighted_adds = String::new();
    let mut highlighted_removes = String::new();
    let mut adds_is_inverse = false;
    let mut removes_is_inverse = false;
    let diff = removes.diff(&adds);
    match diff {
        edit::Edit::Copy(unchanged) => {
            highlighted_adds.push_str(unchanged);
            highlighted_removes.push_str(unchanged);
        }
        edit::Edit::Change(diff) => {
            diff.into_iter()
                .map(|edit| {
                    match edit {
                        string::Edit::Copy(elem) => {
                            if adds_is_inverse {
                                highlighted_adds.push_str(NOT_INVERSE_VIDEO);
                            }
                            adds_is_inverse = false;

                            if removes_is_inverse {
                                highlighted_removes.push_str(NOT_INVERSE_VIDEO);
                            }
                            removes_is_inverse = false;

                            highlighted_adds.push(elem);
                            highlighted_removes.push(elem);
                        }
                        string::Edit::Insert(elem) => {
                            if !adds_is_inverse {
                                highlighted_adds.push_str(INVERSE_VIDEO);
                            }
                            adds_is_inverse = true;

                            if elem == '\n' {
                                // Make sure the highlighted linefeed is visible
                                highlighted_adds.push('⏎');

                                // This will be reset by the linefeed, so we need to re-inverse on the next line
                                adds_is_inverse = false;
                            }
                            highlighted_adds.push(elem);
                        }
                        string::Edit::Remove(elem) => {
                            if !removes_is_inverse {
                                highlighted_removes.push_str(INVERSE_VIDEO);
                            }
                            removes_is_inverse = true;

                            if elem == '\n' {
                                // Make sure the highlighted linefeed is visible
                                highlighted_removes.push('⏎');

                                // This will be reset by the linefeed, so we need to re-inverse on the next line
                                removes_is_inverse = false;
                            }
                            highlighted_removes.push(elem);
                        }
                    };
                })
                .for_each(drop);
        }
    }

    let mut lines: Vec<String> = Vec::new();
    for highlighted_remove in highlighted_removes.lines() {
        lines.push(format!("{}-{}{}", REMOVE, highlighted_remove, NORMAL));
    }
    for highlighted_add in highlighted_adds.lines() {
        lines.push(format!("{}+{}{}", ADD, highlighted_add, NORMAL));
    }

    return lines;
}

#[must_use]
fn get_fixed_highlight(line: &str) -> &str {
    for static_header in STATIC_HEADERS.iter() {
        let re = &static_header.0;
        if re.is_match(line) {
            return static_header.1;
        }
    }

    return "";
}

fn print(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    stream.write(text.as_bytes()).unwrap();
}

fn println(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    print(stream, &text);
    print(stream, "\n");
}

fn highlight_diff(input: &mut dyn io::Read, output: &mut dyn io::Write) {
    let mut adds = String::new();
    let mut removes = String::new();
    let input = BufReader::new(input);
    let output = &mut BufWriter::new(output);
    for line in input.lines() {
        let line = line.unwrap();

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            // Drain outstanding adds / removes
            for line in format_adds_and_removes(&adds, &removes) {
                println(output, &line);
            }
            adds.clear();
            removes.clear();

            print(output, fixed_highlight);
            print(output, &line);
            println(output, NORMAL);
            continue;
        }

        // Collect adds / removes
        if !line.is_empty() && line.chars().next().unwrap() == '+' {
            adds.push_str(&line[1..]);
            adds.push('\n');
            continue;
        } else if !line.is_empty() && line.chars().next().unwrap() == '-' {
            removes.push_str(&line[1..]);
            removes.push('\n');
            continue;
        }

        // Drain outstanding adds / removes
        for line in format_adds_and_removes(&adds, &removes) {
            println(output, &line);
        }
        adds.clear();
        removes.clear();

        // Print current line
        println(output, &line);
    }
    for line in format_adds_and_removes(&adds, &removes) {
        println(output, &line);
    }
}

fn main() {
    highlight_diff(&mut io::stdin().lock(), &mut io::stdout());
}

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_simple_format_adds_and_removes() {
        let empty: Vec<String> = Vec::new();
        assert_eq!(
            simple_format_adds_and_removes(&"".to_string(), &"".to_string()),
            empty
        );

        // Test adds-only
        assert_eq!(
            simple_format_adds_and_removes(&"a\n".to_string(), &"".to_string()),
            ["".to_string() + ADD + "+a" + NORMAL]
        );
        assert_eq!(
            simple_format_adds_and_removes(&"a\nb\n".to_string(), &"".to_string()),
            [
                "".to_string() + ADD + "+a" + NORMAL,
                "".to_string() + ADD + "+b" + NORMAL,
            ]
        );

        // Test removes-only
        assert_eq!(
            simple_format_adds_and_removes(&"".to_string(), &"a\n".to_string()),
            ["".to_string() + REMOVE + "-a" + NORMAL]
        );
        assert_eq!(
            simple_format_adds_and_removes(&"".to_string(), &"a\nb\n".to_string()),
            [
                "".to_string() + REMOVE + "-a" + NORMAL,
                "".to_string() + REMOVE + "-b" + NORMAL,
            ]
        );
    }

    #[test]
    fn test_quote_change() {
        assert_eq!(
            format_adds_and_removes(&"[quotes]\n".to_string(), &"<quotes>\n".to_string()),
            [
                format!(
                    "{}-{}<{}quotes{}>{}{}",
                    REMOVE,
                    INVERSE_VIDEO,
                    NOT_INVERSE_VIDEO,
                    INVERSE_VIDEO,
                    NOT_INVERSE_VIDEO,
                    NORMAL
                ),
                format!(
                    "{}+{}[{}quotes{}]{}{}",
                    ADD, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NOT_INVERSE_VIDEO, NORMAL
                ),
            ]
        )
    }

    fn remove(text: &str) -> String {
        return format!("{}{}{}", REMOVE, text, NORMAL);
    }

    fn add(text: &str) -> String {
        return format!("{}{}{}", ADD, text, NORMAL);
    }

    #[test]
    fn test_remove_trailing_newline() {
        let mut input = "-hej\n\
            +hej\n\
            \\ No newline at end of file\n\
            "
        .as_bytes();

        let expected = format!(
            "{}\n{}\n{}\n",
            remove(&format!("-hej{}⏎", INVERSE_VIDEO)),
            add("+hej"),
            format!("{}\\ No newline at end of file{}", NO_EOF_NEWLINE, NORMAL)
        );

        let mut output: Vec<u8> = Vec::new();
        highlight_diff(&mut input, &mut output);
        assert_eq!(std::str::from_utf8(&output).unwrap(), expected);
    }
}
<|endoftext|>


<commit_before>use {Value, Response};
use parser::parse_response;
use error::RequestError;
use utils::escape_xml;

use hyper::client::{Client, Body};
use hyper::header::{ContentType, UserAgent};

use std::io::{self, Write};

/// A request to call a procedure.
pub struct Request<'a> {
    name: &'a str,
    args: Vec<(&'a str, Value)>,
}

impl<'a> Request<'a> {
    /// Creates a new request to call a function named `name`.
    ///
    /// By default, no arguments are passed. Use the `arg` method to append arguments.
    pub fn new(name: &'a str) -> Self {
        Request {
            name: name,
            args: Vec::new(),
        }
    }

    /// Appends an argument to be passed to the current list of arguments.
    pub fn arg<T: Into<Value>>(mut self, name: &'a str, value: T) -> Self {
        self.args.push((name, value.into()));

        Request {
            name: self.name,
            args: self.args,
        }
    }

    /// Calls the method using the given `Client`.
    ///
    /// Returns a `RequestResult` indicating whether the request was sent and processed successfully
    /// (according to the rules of XML-RPC).
    pub fn call(self, client: Client, url: &str) -> RequestResult {
        use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

        // First, build the body XML
        let mut body = Vec::new();
        try!(self.write_as_xml(&mut body));

        // Send XML-RPC request
        let mut response = try!(client.post(url)
            .header(UserAgent("Rust xmlrpc".to_string()))
            .header(ContentType(Mime(TopLevel::Text, SubLevel::Xml, vec![(Attr::Charset, Value::Utf8)])))
            .body(Body::BufBody(&body, body.len()))
            .send());

        // FIXME Check that the response headers are correct

        // Read the response and parse it
        // FIXME `BufRead`?
        Ok(try!(parse_response(&mut response)))
    }

    /// Formats this `Request` as XML.
    pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        try!(write!(fmt, r#"<?xml version="1.1" encoding="utf-8"?>"#));
        try!(write!(fmt, r#"<methodCall>"#));
        try!(write!(fmt, r#"    <methodName>{}</methodName>"#, escape_xml(&self.name)));
        try!(write!(fmt, r#"    <params>"#));
        for &(_, ref value) in &self.args {
            try!(write!(fmt, r#"        <param>"#));
            try!(value.format(fmt));
            try!(write!(fmt, r#"        </param>"#));
        }
        try!(write!(fmt, r#"    </params>"#));
        try!(write!(fmt, r#"</methodCall>"#));
        Ok(())
    }
}

/// The result of executing a request.
///
/// When the request was executed without major errors (like an HTTP error or a malformed response),
/// this is `Ok`. The `Response` can still denote a `Fault` if the server returned a `<fault>`
/// response.
pub type RequestResult = Result<Response, RequestError>;

#[cfg(test)]
mod tests {
    use super::*;
    use std::str;

    #[test]
    fn escapes_method_names() {
        let mut output: Vec<u8> = Vec::new();
        let req = Request::new("x<&x");

        req.write_as_xml(&mut output).unwrap();
        assert!(
            str::from_utf8(&output)
            .unwrap()
            .contains("<methodName>x<&x</methodName>"));
    }
}
<commit_msg>Make Request::call borrow its parameters instead of consuming them<commit_after>use {Value, Response};
use parser::parse_response;
use error::RequestError;
use utils::escape_xml;

use hyper::client::{Client, Body};
use hyper::header::{ContentType, UserAgent};

use std::io::{self, Write};

/// A request to call a procedure.
pub struct Request<'a> {
    name: &'a str,
    args: Vec<(&'a str, Value)>,
}

impl<'a> Request<'a> {
    /// Creates a new request to call a function named `name`.
    ///
    /// By default, no arguments are passed. Use the `arg` method to append arguments.
    pub fn new(name: &'a str) -> Self {
        Request {
            name: name,
            args: Vec::new(),
        }
    }

    /// Appends an argument to be passed to the current list of arguments.
    pub fn arg<T: Into<Value>>(mut self, name: &'a str, value: T) -> Self {
        self.args.push((name, value.into()));

        Request {
            name: self.name,
            args: self.args,
        }
    }

    /// Calls the method using the given `Client`.
    ///
    /// Returns a `RequestResult` indicating whether the request was sent and processed successfully
    /// (according to the rules of XML-RPC).
    pub fn call(&self, client: &Client, url: &str) -> RequestResult {
        use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

        // First, build the body XML
        let mut body = Vec::new();
        try!(self.write_as_xml(&mut body));

        // Send XML-RPC request
        let mut response = try!(client.post(url)
            .header(UserAgent("Rust xmlrpc".to_string()))
            .header(ContentType(Mime(TopLevel::Text, SubLevel::Xml, vec![(Attr::Charset, Value::Utf8)])))
            .body(Body::BufBody(&body, body.len()))
            .send());

        // FIXME Check that the response headers are correct

        // Read the response and parse it
        // FIXME `BufRead`?
        Ok(try!(parse_response(&mut response)))
    }

    /// Formats this `Request` as XML.
    pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        try!(write!(fmt, r#"<?xml version="1.1" encoding="utf-8"?>"#));
        try!(write!(fmt, r#"<methodCall>"#));
        try!(write!(fmt, r#"    <methodName>{}</methodName>"#, escape_xml(&self.name)));
        try!(write!(fmt, r#"    <params>"#));
        for &(_, ref value) in &self.args {
            try!(write!(fmt, r#"        <param>"#));
            try!(value.format(fmt));
            try!(write!(fmt, r#"        </param>"#));
        }
        try!(write!(fmt, r#"    </params>"#));
        try!(write!(fmt, r#"</methodCall>"#));
        Ok(())
    }
}

/// The result of executing a request.
///
/// When the request was executed without major errors (like an HTTP error or a malformed response),
/// this is `Ok`. The `Response` can still denote a `Fault` if the server returned a `<fault>`
/// response.
pub type RequestResult = Result<Response, RequestError>;

#[cfg(test)]
mod tests {
    use super::*;
    use std::str;

    #[test]
    fn escapes_method_names() {
        let mut output: Vec<u8> = Vec::new();
        let req = Request::new("x<&x");

        req.write_as_xml(&mut output).unwrap();
        assert!(
            str::from_utf8(&output)
            .unwrap()
            .contains("<methodName>x<&x</methodName>"));
    }
}
<|endoftext|>


<commit_before>// Mandelbrot set in rust
//
// This code shows how to calculate the set in serial and parallel.
// More parallel versions will be added in the future.
//
// Written by Willi Kappler, grandor@gmx.de
//
// License: MIT
//
//#![feature(plugin)]
//
//#![plugin(clippy)]

// External crates
extern crate time;
extern crate rayon;

// Internal crates
extern crate mandel_util;
extern crate mandel_method;

// External modules
use time::{now};

// Internal modules
use mandel_util::*;
use mandel_method::*;

fn main() {
    // For example run with:
    // cargo run --release -- --re1=-2.0 --re2=1.0 --img1=-1.5 --img2=1.5
    //           --max_iter=2048 --img_size=1024 --num_threads=2
    //
    // Or just using the default values:
    // cargo run --release -- --num_threads=2
    //
    // Note that the image size must be a power of two

    let mandel_config = parse_arguments();

    let version = env!("CARGO_PKG_VERSION");

    println!("mandel-rust version: {}", version);
    println!("Number of repetitive runs: {}", mandel_config.num_of_runs);
    println!("Rustc version: {}", compiler_version);

    // Get current date and time once and pass it to the individual runs for the image filename.
    let tm = now();
    let tm = tm.strftime("%Y_%m_%d__%H_%M_%S").unwrap();
    let time_now = format!("{}", &tm);

    // vec! macro expects usize
    let mut image: Vec<u32> = vec![0; (mandel_config.img_size * mandel_config.img_size) as usize];

    do_run("serial", &serial, &mandel_config, &mut image, &time_now);

    do_run("scoped_thread_pool", &scoped_thread_pool_, &mandel_config, &mut image, &time_now);

    do_run("simple_parallel", &simple_parallel_, &mandel_config, &mut image, &time_now);

    // Make sure this is only called once
    match rayon::initialize(rayon::Configuration::new().set_num_threads(mandel_config.num_threads as usize)) {
        Ok(_) => {
            do_run("rayon_join", &rayon_join, &mandel_config, &mut image, &time_now);

            do_run("rayon_par_iter", &rayon_par_iter, &mandel_config, &mut image, &time_now);
        },
        Err(e) => println!("Rayon error: set number of threads failed: {}", e)
    }

    do_run("rust_scoped_pool", &rust_scoped_pool, &mandel_config, &mut image, &time_now);

    do_run("job_steal", &job_steal, &mandel_config, &mut image, &time_now);

    do_run("job_steal_join", &job_steal_join, &mandel_config, &mut image, &time_now);

    do_run("kirk_crossbeam", &kirk_crossbeam, &mandel_config, &mut image, &time_now);
}
<commit_msg>only import what is needed<commit_after>// Mandelbrot set in rust
//
// This code shows how to calculate the set in serial and parallel.
// More parallel versions will be added in the future.
//
// Written by Willi Kappler, grandor@gmx.de
//
// License: MIT
//
//#![feature(plugin)]
//
//#![plugin(clippy)]

// External crates
extern crate time;
extern crate rayon;

// Internal crates
extern crate mandel_util;
extern crate mandel_method;

// External modules
use time::{now};

// Internal modules
use mandel_util::{parse_arguments, do_run, compiler_version};
use mandel_method::*;

fn main() {
    // For example run with:
    // cargo run --release -- --re1=-2.0 --re2=1.0 --img1=-1.5 --img2=1.5
    //           --max_iter=2048 --img_size=1024 --num_threads=2
    //
    // Or just using the default values:
    // cargo run --release -- --num_threads=2
    //
    // Note that the image size must be a power of two

    let mandel_config = parse_arguments();

    let version = env!("CARGO_PKG_VERSION");

    println!("mandel-rust version: {}", version);
    println!("Number of repetitive runs: {}", mandel_config.num_of_runs);
    println!("Rustc version: {}", compiler_version);

    // Get current date and time once and pass it to the individual runs for the image filename.
    let tm = now();
    let tm = tm.strftime("%Y_%m_%d__%H_%M_%S").unwrap();
    let time_now = format!("{}", &tm);

    // vec! macro expects usize
    let mut image: Vec<u32> = vec![0; (mandel_config.img_size * mandel_config.img_size) as usize];

    do_run("serial", &serial, &mandel_config, &mut image, &time_now);

    do_run("scoped_thread_pool", &scoped_thread_pool_, &mandel_config, &mut image, &time_now);

    do_run("simple_parallel", &simple_parallel_, &mandel_config, &mut image, &time_now);

    // Make sure this is only called once
    match rayon::initialize(rayon::Configuration::new().set_num_threads(mandel_config.num_threads as usize)) {
        Ok(_) => {
            do_run("rayon_join", &rayon_join, &mandel_config, &mut image, &time_now);

            do_run("rayon_par_iter", &rayon_par_iter, &mandel_config, &mut image, &time_now);
        },
        Err(e) => println!("Rayon error: set number of threads failed: {}", e)
    }

    do_run("rust_scoped_pool", &rust_scoped_pool, &mandel_config, &mut image, &time_now);

    do_run("job_steal", &job_steal, &mandel_config, &mut image, &time_now);

    do_run("job_steal_join", &job_steal_join, &mandel_config, &mut image, &time_now);

    do_run("kirk_crossbeam", &kirk_crossbeam, &mandel_config, &mut image, &time_now);
}
<|endoftext|>


<commit_before>use super::*;

pub trait Request {
    type Params;
    type Result;
    const METHOD: &'static str;
}

#[macro_export]
macro_rules! lsp_request {
    ("initialize") => { $crate::request::Initialize };
    ("shutdown") => { $crate::request::Shutdown };

    ("window/showMessageRequest") => { $crate::request::ShowMessageRequest };

    ("client/registerCapability") => { $crate::request::RegisterCapability };
    ("client/unregisterCapability") => { $crate::request::UnregisterCapability };

    ("workspace/symbol") => { $crate::request::WorkspaceSymbol };
    ("workspace/executeCommand") => { $crate::request::ExecuteCommand };

    ("textDocument/willSaveWaitUntil") => { $crate::request::WillSaveWaitUntil };
    ("textDocument/completion") => { $crate::request::Completion };
    ("completionItem/resolve") => { $crate::request::ResolveCompletionItem };
    ("textDocument/hover") => { $crate::request::HoverRequest };
    ("textDocument/signatureHelp") => { $crate::request::SignatureHelpRequest };
    ("textDocument/definition") => { $crate::request::GotoDefinition };
    ("textDocument/references") => { $crate::request::References };
    ("textDocument/documentHighlight") => { $crate::request::DocumentHighlightRequest };
    ("textDocument/documentSymbol") => { $crate::request::DocumentSymbol };
    ("textDocument/codeAction") => { $crate::request::CodeAction };
    ("textDocument/codeLens") => { $crate::request::CodeLensRequest };
    ("codeLens/resolve") => { $crate::request::CodeLensResolve };
    ("textDocument/documentLink") => { $crate::request::DocumentLink };
    ("documentLink/resolve") => { $crate::request::DocumentLinkResolve };
    ("textDocument/applyEdit") => { $crate::request::ApplyEdit };
    ("textDocument/rangeFormatting") => { $crate::request::RangeFormatting };
    ("textDocument/onTypeFormatting") => { $crate::request::OnTypeFormatting };
    ("textDocument/formatting") => { $crate::request::Formatting };
    ("textDocument/rename") => { $crate::request::Rename };
}

/**

 The initialize request is sent as the first request from the client to the server.
 If the server receives request or notification before the `initialize` request it should act as follows:

 * for a request the respond should be errored with `code: -32001`. The message can be picked by the server.
 * notifications should be dropped.

*/
#[derive(Debug)]
pub enum Initialize {}

impl Request for Initialize {
    type Params = InitializeParams;
    type Result = InitializeResult;
    const METHOD: &'static str = "initialize";
}

/**
 * The shutdown request is sent from the client to the server. It asks the server to shut down,
 * but to not exit (otherwise the response might not be delivered correctly to the client).
 * There is a separate exit notification that asks the server to exit.
 */
#[derive(Debug)]
pub enum Shutdown {}

impl Request for Shutdown {
    type Params = ();
    type Result = ();
    const METHOD: &'static str = "shutdown";
}

/**
 * The show message request is sent from a server to a client to ask the client to display a particular message
 * in the user interface. In addition to the show message notification the request allows to pass actions and to
 * wait for an answer from the client.
 */
#[derive(Debug)]
pub enum ShowMessageRequest {}

impl Request for ShowMessageRequest {
    type Params = ShowMessageRequestParams;
    type Result = Option<MessageActionItem>;
    const METHOD: &'static str = "window/showMessageRequest";
}

/**
 * The client/registerCapability request is sent from the server to the client to register for a new capability on the client side. Not all clients need to support dynamic capability registration. A client opts in via the ClientCapabilities.GenericCapability property.
 */
#[derive(Debug)]
pub enum RegisterCapability {}

impl Request for RegisterCapability {
    type Params = RegistrationParams;
    type Result = ();
    const METHOD: &'static str = "client/registerCapability";
}

/// The client/unregisterCapability request is sent from the server to the client to unregister a
/// previously register capability.
#[derive(Debug)]
pub enum UnregisterCapability {}

impl Request for UnregisterCapability {
    type Params = UnregistrationParams;
    type Result = ();
    const METHOD: &'static str = "client/unregisterCapability";
}

/**
 The Completion request is sent from the client to the server to compute completion items at a given cursor position.
 Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive,
 servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve').
 This request is sent when a completion item is selected in the user interface. A typically use case is for example:
 the 'textDocument/completion' request doesn't fill in the documentation property for returned completion items
 since it is expensive to compute. When the item is selected in the user interface then a 'completionItem/resolve'
 request is sent with the selected completion item as a param. The returned completion item should have the
 documentation property filled in.
*/
#[derive(Debug)]
pub enum Completion {}

impl Request for Completion {
    type Params = CompletionParams;
    type Result = CompletionResponse;
    const METHOD: &'static str = "textDocument/completion";
}

/// The request is sent from the client to the server to resolve additional information for a given completion item.
#[derive(Debug)]
pub enum ResolveCompletionItem {}

impl Request for ResolveCompletionItem {
    type Params = CompletionItem;
    type Result = CompletionItem;
    const METHOD: &'static str = "completionItem/resolve";
}

/// The hover request is sent from the client to the server to request hover information at a given text
/// document position.
#[derive(Debug)]
pub enum HoverRequest {}

impl Request for HoverRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<Hover>;
    const METHOD: &'static str = "textDocument/hover";
}

/// The signature help request is sent from the client to the server to request signature information at
/// a given cursor position.
#[derive(Debug)]
pub enum SignatureHelpRequest {}

impl Request for SignatureHelpRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<SignatureHelp>;
    const METHOD: &'static str = "textDocument/signatureHelp";
}

/// The goto definition request is sent from the client to the server to resolve the definition location of
/// a symbol at a given text document position.
#[derive(Debug)]
pub enum GotoDefinition {}

impl Request for GotoDefinition {
    type Params = TextDocumentPositionParams;
    type Result = Option<GotoDefinitionResponse>;
    const METHOD: &'static str = "textDocument/definition";
}

/**
 * GotoDefinition response can be single location or multiple ones.
 */
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GotoDefinitionResponse {
    Scalar(Location),
    Array(Vec<Location>),
}

/// The references request is sent from the client to the server to resolve project-wide references for the
/// symbol denoted by the given text document position.
pub enum References {}

impl Request for References {
    type Params = ReferenceParams;
    type Result = Option<Vec<Location>>;
    const METHOD: &'static str = "textDocument/references";
}

/**
 The document highlight request is sent from the client to the server to resolve a document highlights
 for a given text document position.
 For programming languages this usually highlights all references to the symbol scoped to this file.
 However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since
 the first one is allowed to be more fuzzy.
 Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches
 use Textas the kind.
*/
#[derive(Debug)]
pub enum DocumentHighlightRequest {}

impl Request for DocumentHighlightRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<Vec<DocumentHighlight>>;
    const METHOD: &'static str = "textDocument/documentHighlight";
}

/**
 * The document symbol request is sent from the client to the server to list all symbols found in a given
 * text document.
 */
#[derive(Debug)]
pub enum DocumentSymbol {}

impl Request for DocumentSymbol {
    type Params = DocumentSymbolParams;
    type Result = Option<Vec<SymbolInformation>>;
    const METHOD: &'static str = "textDocument/documentSymbol";
}

/**
 * The workspace symbol request is sent from the client to the server to list project-wide symbols
 * matching the query string.
 */
#[derive(Debug)]
pub enum WorkspaceSymbol {}

impl Request for WorkspaceSymbol {
    type Params = WorkspaceSymbolParams;
    type Result = Option<Vec<SymbolInformation>>;
    const METHOD: &'static str = "workspace/symbol";
}

/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request workspace/applyEdit which is sent from the server to the client.
#[derive(Debug)]
pub enum ExecuteCommand {}

impl Request for ExecuteCommand {
    type Params = ExecuteCommandParams;
    type Result = Option<Value>;
    const METHOD: &'static str = "workspace/executeCommand";
}

/// The workspace/applyEdit request is sent from the server to the client to modify resource on the
/// client side.
#[derive(Debug)]
pub enum ApplyWorkspaceEdit {}

impl Request for ApplyWorkspaceEdit {
    type Params = ApplyWorkspaceEditParams;
    type Result = ApplyWorkspaceEditResponse;
    const METHOD: &'static str = "workspace/applyEdit";
}

/**
 * The code action request is sent from the client to the server to compute commands for a given text document
 * and range. The request is triggered when the user moves the cursor into a problem marker in the editor or
 * presses the lightbulb associated with a marker.
 */
#[derive(Debug)]
pub enum CodeActionRequest {}

impl Request for CodeActionRequest {
    type Params = CodeActionParams;
    type Result = Option<Vec<Command>>;
    const METHOD: &'static str = "textDocument/codeAction";
}

/**
 * The code lens request is sent from the client to the server to compute code lenses for a given text document.
 */
#[derive(Debug)]
pub enum CodeLensRequest {}

impl Request for CodeLensRequest {
    type Params = CodeLensParams;
    type Result = Option<Vec<CodeLens>>;
    const METHOD: &'static str = "textDocument/codeLens";
}

/**
 * The code lens resolve request is sent from the client to the server to resolve the command for a
 * given code lens item.
 */
#[derive(Debug)]
pub enum CodeLensResolve {}

impl Request for CodeLensResolve {
    type Params = CodeLens;
    type Result = CodeLens;
    const METHOD: &'static str = "codeLens/resolve";
}

/// The document links request is sent from the client to the server to request the location of links in a document.
#[derive(Debug)]
pub enum DocumentLinkRequest {}

impl Request for DocumentLinkRequest {
    type Params = DocumentLinkParams;
    type Result = Option<Vec<DocumentLink>>;
    const METHOD: &'static str = "textDocument/documentLink";
}

/**

 The document link resolve request is sent from the client to the server to resolve the target of
 a given document link.

*/
#[derive(Debug)]
pub enum DocumentLinkResolve {}

impl Request for DocumentLinkResolve {
    type Params = DocumentLink;
    type Result = DocumentLink;
    const METHOD: &'static str = "documentLink/resolve";
}

/**
 * The document formatting request is sent from the server to the client to format a whole document.
 */
#[derive(Debug)]
pub enum Formatting {}

impl Request for Formatting {
    type Params = DocumentFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/formatting";
}

/// The document range formatting request is sent from the client to the server to format a given range in a document.
#[derive(Debug)]
pub enum RangeFormatting {}

impl Request for RangeFormatting {
    type Params = DocumentRangeFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/rangeFormatting";
}

/**
 * The document on type formatting request is sent from the client to the server to format parts of
 * the document during typing.
 */
#[derive(Debug)]
pub enum OnTypeFormatting {}

impl Request for OnTypeFormatting {
    type Params = DocumentOnTypeFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/onTypeFormatting";
}

/**
 * The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol.
 */
#[derive(Debug)]
pub enum Rename {}

impl Request for Rename {
    type Params = RenameParams;
    type Result = Option<WorkspaceEdit>;
    const METHOD: &'static str = "textDocument/rename";
}
<commit_msg>CompletionResponse could be null.<commit_after>use super::*;

pub trait Request {
    type Params;
    type Result;
    const METHOD: &'static str;
}

#[macro_export]
macro_rules! lsp_request {
    ("initialize") => { $crate::request::Initialize };
    ("shutdown") => { $crate::request::Shutdown };

    ("window/showMessageRequest") => { $crate::request::ShowMessageRequest };

    ("client/registerCapability") => { $crate::request::RegisterCapability };
    ("client/unregisterCapability") => { $crate::request::UnregisterCapability };

    ("workspace/symbol") => { $crate::request::WorkspaceSymbol };
    ("workspace/executeCommand") => { $crate::request::ExecuteCommand };

    ("textDocument/willSaveWaitUntil") => { $crate::request::WillSaveWaitUntil };
    ("textDocument/completion") => { $crate::request::Completion };
    ("completionItem/resolve") => { $crate::request::ResolveCompletionItem };
    ("textDocument/hover") => { $crate::request::HoverRequest };
    ("textDocument/signatureHelp") => { $crate::request::SignatureHelpRequest };
    ("textDocument/definition") => { $crate::request::GotoDefinition };
    ("textDocument/references") => { $crate::request::References };
    ("textDocument/documentHighlight") => { $crate::request::DocumentHighlightRequest };
    ("textDocument/documentSymbol") => { $crate::request::DocumentSymbol };
    ("textDocument/codeAction") => { $crate::request::CodeAction };
    ("textDocument/codeLens") => { $crate::request::CodeLensRequest };
    ("codeLens/resolve") => { $crate::request::CodeLensResolve };
    ("textDocument/documentLink") => { $crate::request::DocumentLink };
    ("documentLink/resolve") => { $crate::request::DocumentLinkResolve };
    ("textDocument/applyEdit") => { $crate::request::ApplyEdit };
    ("textDocument/rangeFormatting") => { $crate::request::RangeFormatting };
    ("textDocument/onTypeFormatting") => { $crate::request::OnTypeFormatting };
    ("textDocument/formatting") => { $crate::request::Formatting };
    ("textDocument/rename") => { $crate::request::Rename };
}

/**

 The initialize request is sent as the first request from the client to the server.
 If the server receives request or notification before the `initialize` request it should act as follows:

 * for a request the respond should be errored with `code: -32001`. The message can be picked by the server.
 * notifications should be dropped.

*/
#[derive(Debug)]
pub enum Initialize {}

impl Request for Initialize {
    type Params = InitializeParams;
    type Result = InitializeResult;
    const METHOD: &'static str = "initialize";
}

/**
 * The shutdown request is sent from the client to the server. It asks the server to shut down,
 * but to not exit (otherwise the response might not be delivered correctly to the client).
 * There is a separate exit notification that asks the server to exit.
 */
#[derive(Debug)]
pub enum Shutdown {}

impl Request for Shutdown {
    type Params = ();
    type Result = ();
    const METHOD: &'static str = "shutdown";
}

/**
 * The show message request is sent from a server to a client to ask the client to display a particular message
 * in the user interface. In addition to the show message notification the request allows to pass actions and to
 * wait for an answer from the client.
 */
#[derive(Debug)]
pub enum ShowMessageRequest {}

impl Request for ShowMessageRequest {
    type Params = ShowMessageRequestParams;
    type Result = Option<MessageActionItem>;
    const METHOD: &'static str = "window/showMessageRequest";
}

/**
 * The client/registerCapability request is sent from the server to the client to register for a new capability on the client side. Not all clients need to support dynamic capability registration. A client opts in via the ClientCapabilities.GenericCapability property.
 */
#[derive(Debug)]
pub enum RegisterCapability {}

impl Request for RegisterCapability {
    type Params = RegistrationParams;
    type Result = ();
    const METHOD: &'static str = "client/registerCapability";
}

/// The client/unregisterCapability request is sent from the server to the client to unregister a
/// previously register capability.
#[derive(Debug)]
pub enum UnregisterCapability {}

impl Request for UnregisterCapability {
    type Params = UnregistrationParams;
    type Result = ();
    const METHOD: &'static str = "client/unregisterCapability";
}

/**
 The Completion request is sent from the client to the server to compute completion items at a given cursor position.
 Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive,
 servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve').
 This request is sent when a completion item is selected in the user interface. A typically use case is for example:
 the 'textDocument/completion' request doesn't fill in the documentation property for returned completion items
 since it is expensive to compute. When the item is selected in the user interface then a 'completionItem/resolve'
 request is sent with the selected completion item as a param. The returned completion item should have the
 documentation property filled in.
*/
#[derive(Debug)]
pub enum Completion {}

impl Request for Completion {
    type Params = CompletionParams;
    type Result = Option<CompletionResponse>;
    const METHOD: &'static str = "textDocument/completion";
}

/// The request is sent from the client to the server to resolve additional information for a given completion item.
#[derive(Debug)]
pub enum ResolveCompletionItem {}

impl Request for ResolveCompletionItem {
    type Params = CompletionItem;
    type Result = CompletionItem;
    const METHOD: &'static str = "completionItem/resolve";
}

/// The hover request is sent from the client to the server to request hover information at a given text
/// document position.
#[derive(Debug)]
pub enum HoverRequest {}

impl Request for HoverRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<Hover>;
    const METHOD: &'static str = "textDocument/hover";
}

/// The signature help request is sent from the client to the server to request signature information at
/// a given cursor position.
#[derive(Debug)]
pub enum SignatureHelpRequest {}

impl Request for SignatureHelpRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<SignatureHelp>;
    const METHOD: &'static str = "textDocument/signatureHelp";
}

/// The goto definition request is sent from the client to the server to resolve the definition location of
/// a symbol at a given text document position.
#[derive(Debug)]
pub enum GotoDefinition {}

impl Request for GotoDefinition {
    type Params = TextDocumentPositionParams;
    type Result = Option<GotoDefinitionResponse>;
    const METHOD: &'static str = "textDocument/definition";
}

/**
 * GotoDefinition response can be single location or multiple ones.
 */
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GotoDefinitionResponse {
    Scalar(Location),
    Array(Vec<Location>),
}

/// The references request is sent from the client to the server to resolve project-wide references for the
/// symbol denoted by the given text document position.
pub enum References {}

impl Request for References {
    type Params = ReferenceParams;
    type Result = Option<Vec<Location>>;
    const METHOD: &'static str = "textDocument/references";
}

/**
 The document highlight request is sent from the client to the server to resolve a document highlights
 for a given text document position.
 For programming languages this usually highlights all references to the symbol scoped to this file.
 However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since
 the first one is allowed to be more fuzzy.
 Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches
 use Textas the kind.
*/
#[derive(Debug)]
pub enum DocumentHighlightRequest {}

impl Request for DocumentHighlightRequest {
    type Params = TextDocumentPositionParams;
    type Result = Option<Vec<DocumentHighlight>>;
    const METHOD: &'static str = "textDocument/documentHighlight";
}

/**
 * The document symbol request is sent from the client to the server to list all symbols found in a given
 * text document.
 */
#[derive(Debug)]
pub enum DocumentSymbol {}

impl Request for DocumentSymbol {
    type Params = DocumentSymbolParams;
    type Result = Option<Vec<SymbolInformation>>;
    const METHOD: &'static str = "textDocument/documentSymbol";
}

/**
 * The workspace symbol request is sent from the client to the server to list project-wide symbols
 * matching the query string.
 */
#[derive(Debug)]
pub enum WorkspaceSymbol {}

impl Request for WorkspaceSymbol {
    type Params = WorkspaceSymbolParams;
    type Result = Option<Vec<SymbolInformation>>;
    const METHOD: &'static str = "workspace/symbol";
}

/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request workspace/applyEdit which is sent from the server to the client.
#[derive(Debug)]
pub enum ExecuteCommand {}

impl Request for ExecuteCommand {
    type Params = ExecuteCommandParams;
    type Result = Option<Value>;
    const METHOD: &'static str = "workspace/executeCommand";
}

/// The workspace/applyEdit request is sent from the server to the client to modify resource on the
/// client side.
#[derive(Debug)]
pub enum ApplyWorkspaceEdit {}

impl Request for ApplyWorkspaceEdit {
    type Params = ApplyWorkspaceEditParams;
    type Result = ApplyWorkspaceEditResponse;
    const METHOD: &'static str = "workspace/applyEdit";
}

/**
 * The code action request is sent from the client to the server to compute commands for a given text document
 * and range. The request is triggered when the user moves the cursor into a problem marker in the editor or
 * presses the lightbulb associated with a marker.
 */
#[derive(Debug)]
pub enum CodeActionRequest {}

impl Request for CodeActionRequest {
    type Params = CodeActionParams;
    type Result = Option<Vec<Command>>;
    const METHOD: &'static str = "textDocument/codeAction";
}

/**
 * The code lens request is sent from the client to the server to compute code lenses for a given text document.
 */
#[derive(Debug)]
pub enum CodeLensRequest {}

impl Request for CodeLensRequest {
    type Params = CodeLensParams;
    type Result = Option<Vec<CodeLens>>;
    const METHOD: &'static str = "textDocument/codeLens";
}

/**
 * The code lens resolve request is sent from the client to the server to resolve the command for a
 * given code lens item.
 */
#[derive(Debug)]
pub enum CodeLensResolve {}

impl Request for CodeLensResolve {
    type Params = CodeLens;
    type Result = CodeLens;
    const METHOD: &'static str = "codeLens/resolve";
}

/// The document links request is sent from the client to the server to request the location of links in a document.
#[derive(Debug)]
pub enum DocumentLinkRequest {}

impl Request for DocumentLinkRequest {
    type Params = DocumentLinkParams;
    type Result = Option<Vec<DocumentLink>>;
    const METHOD: &'static str = "textDocument/documentLink";
}

/**

 The document link resolve request is sent from the client to the server to resolve the target of
 a given document link.

*/
#[derive(Debug)]
pub enum DocumentLinkResolve {}

impl Request for DocumentLinkResolve {
    type Params = DocumentLink;
    type Result = DocumentLink;
    const METHOD: &'static str = "documentLink/resolve";
}

/**
 * The document formatting request is sent from the server to the client to format a whole document.
 */
#[derive(Debug)]
pub enum Formatting {}

impl Request for Formatting {
    type Params = DocumentFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/formatting";
}

/// The document range formatting request is sent from the client to the server to format a given range in a document.
#[derive(Debug)]
pub enum RangeFormatting {}

impl Request for RangeFormatting {
    type Params = DocumentRangeFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/rangeFormatting";
}

/**
 * The document on type formatting request is sent from the client to the server to format parts of
 * the document during typing.
 */
#[derive(Debug)]
pub enum OnTypeFormatting {}

impl Request for OnTypeFormatting {
    type Params = DocumentOnTypeFormattingParams;
    type Result = Option<Vec<TextEdit>>;
    const METHOD: &'static str = "textDocument/onTypeFormatting";
}

/**
 * The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol.
 */
#[derive(Debug)]
pub enum Rename {}

impl Request for Rename {
    type Params = RenameParams;
    type Result = Option<WorkspaceEdit>;
    const METHOD: &'static str = "textDocument/rename";
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate termios;

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, winsize};
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Stdin, Stdout, Read, Error, ErrorKind, Write};

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct TermReset {
    orig_term: Termios
}

struct EditorConfig {
    _term: TermReset,
    screenrows: u16,
    screencols: u16,
}

struct Editor {
    config: EditorConfig,
    stdin: Stdin,
    stdout: Stdout,
}

impl Drop for TermReset {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn enable_raw_mode() -> io::Result<TermReset> {
    let mut term = Termios::from_fd(STDIN_FILENO)?;
    let mode = TermReset { orig_term: term.clone() };

    term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    term.c_oflag &= !OPOST;
    term.c_cflag |= CS8;
    term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
    Ok(mode)
}

impl EditorConfig {
    fn new() -> EditorConfig {
        let term = enable_raw_mode().unwrap();
        let (rows, cols) = get_window_size().unwrap();
        EditorConfig { _term: term, screenrows: rows, screencols: cols }
    }
}

impl Editor {
    fn new(config: EditorConfig) -> Editor {
        let stdin = io::stdin();
        let stdout = io::stdout();
        Editor { config: config, stdin: stdin, stdout: stdout }
    }
}

impl Drop for Editor {
    fn drop(&mut self) {
        clear_screen(&mut self.stdout).unwrap();
        self.stdout.flush().unwrap();
    }
}

fn editor_read_key(stdin: &mut Stdin) -> u8 {
    let mut buf = [0; 1];
    loop {
        let n = stdin.read(&mut buf)
                 .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
                 .expect("read");
        if n == 1 {
            return buf[0];
        }
    }
}

fn get_window_size() -> io::Result<(u16, u16)> {
    let ws = winsize { ws_col: 0, ws_row: 0, ws_xpixel: 0, ws_ypixel: 0 };
    unsafe {
        if libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0 {
            return Err(Error::new(ErrorKind::Other, "get_window_size: ioctl failed"))
        }
    }
    Ok((ws.ws_row, ws.ws_col))
}

fn clear_screen(stdout: &mut Stdout) -> io::Result<()> {
    stdout.write(b"\x1b[2J")?;
    stdout.write(b"\x1b[H")?;
    Ok(())
}

fn editor_draw_rows(stdout: &mut Stdout, e: &EditorConfig) -> io::Result<()> {
    for _ in 0..(e.screenrows - 1) {
        stdout.write(b"~\r\n")?;
    }
    stdout.write(b"~")?;
    Ok(())
}

fn editor_refresh_screen(stdout: &mut Stdout, e: &EditorConfig) -> io::Result<()> {
    clear_screen(stdout)?;

    editor_draw_rows(stdout, e)?;

    stdout.write(b"\x1b[H")?;
    stdout.flush()
}

fn editor_process_keypress(stdin: &mut Stdin) -> bool {
    let c = editor_read_key(stdin);

    match c {
        k if k == ctrl_key!(b'q') => {
            false
        },
        _ => true
    }
}

fn main() {
    let mut editor = Editor::new(EditorConfig::new());

    editor_refresh_screen(&mut editor.stdout, &editor.config).unwrap();
    while editor_process_keypress(&mut editor.stdin) {
        editor_refresh_screen(&mut editor.stdout, &editor.config).unwrap();
    }
}
<commit_msg>Hide the cursor when repainting<commit_after>extern crate libc;
extern crate termios;

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, winsize};
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Stdin, Stdout, Read, Error, ErrorKind, Write};

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct TermReset {
    orig_term: Termios
}

struct EditorConfig {
    _term: TermReset,
    screenrows: u16,
    screencols: u16,
}

struct Editor {
    config: EditorConfig,
    stdin: Stdin,
    stdout: Stdout,
}

impl Drop for TermReset {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn enable_raw_mode() -> io::Result<TermReset> {
    let mut term = Termios::from_fd(STDIN_FILENO)?;
    let mode = TermReset { orig_term: term.clone() };

    term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    term.c_oflag &= !OPOST;
    term.c_cflag |= CS8;
    term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
    Ok(mode)
}

impl EditorConfig {
    fn new() -> EditorConfig {
        let term = enable_raw_mode().unwrap();
        let (rows, cols) = get_window_size().unwrap();
        EditorConfig { _term: term, screenrows: rows, screencols: cols }
    }
}

impl Editor {
    fn new(config: EditorConfig) -> Editor {
        let stdin = io::stdin();
        let stdout = io::stdout();
        Editor { config: config, stdin: stdin, stdout: stdout }
    }
}

impl Drop for Editor {
    fn drop(&mut self) {
        clear_screen(&mut self.stdout).unwrap();
        self.stdout.flush().unwrap();
    }
}

fn editor_read_key(stdin: &mut Stdin) -> u8 {
    let mut buf = [0; 1];
    loop {
        let n = stdin.read(&mut buf)
                 .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
                 .expect("read");
        if n == 1 {
            return buf[0];
        }
    }
}

fn get_window_size() -> io::Result<(u16, u16)> {
    let ws = winsize { ws_col: 0, ws_row: 0, ws_xpixel: 0, ws_ypixel: 0 };
    unsafe {
        if libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0 {
            return Err(Error::new(ErrorKind::Other, "get_window_size: ioctl failed"))
        }
    }
    Ok((ws.ws_row, ws.ws_col))
}

fn clear_screen(stdout: &mut Stdout) -> io::Result<()> {
    stdout.write(b"\x1b[2J")?;
    stdout.write(b"\x1b[H")?;
    Ok(())
}

fn editor_draw_rows(stdout: &mut Stdout, e: &EditorConfig) -> io::Result<()> {
    for _ in 0..(e.screenrows - 1) {
        stdout.write(b"~\r\n")?;
    }
    stdout.write(b"~")?;
    Ok(())
}

fn editor_refresh_screen(stdout: &mut Stdout, e: &EditorConfig) -> io::Result<()> {
    stdout.write(b"\x1b[?25l")?;
    clear_screen(stdout)?;

    editor_draw_rows(stdout, e)?;

    stdout.write(b"\x1b[H")?;
    stdout.write(b"\x1b[?25h")?;
    stdout.flush()
}

fn editor_process_keypress(stdin: &mut Stdin) -> bool {
    let c = editor_read_key(stdin);

    match c {
        k if k == ctrl_key!(b'q') => {
            false
        },
        _ => true
    }
}

fn main() {
    let mut editor = Editor::new(EditorConfig::new());

    editor_refresh_screen(&mut editor.stdout, &editor.config).unwrap();
    while editor_process_keypress(&mut editor.stdin) {
        editor_refresh_screen(&mut editor.stdout, &editor.config).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate irc;
extern crate rand;

use std::default::Default;
use irc::client::prelude::*;
use rand::{thread_rng, sample};

fn main() {
    let mut rng = thread_rng();
    let choices = ["heads!", "tails!"];
    let config = Config {
        nickname: Some(format!("pdxferris")),
        alt_nicks: Some(vec![format!("pdxrust-bot"), format!("pdx-rust-bot")]),
        server: Some(format!("irc.freenode.net")),
        channels: Some(vec![format!("#pdxbots"),
                            format!("#pdxrust")]),
        .. Default::default()
    };
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // We'll just panic if there's an error.
        if &message.command[..] == "PRIVMSG" {
            if let Some(msg) = message.suffix {
                if msg.starts_with("!flip") {
                    let choice = sample(&mut rng, choices.iter(), 1);
                    server.send_privmsg(&message.args[0],
                                        &*format!("The coin goes whirling through the air... {}",
                                                  choice.get(0).unwrap())).unwrap();
                }
            }
        }
    }
}
<commit_msg>source command<commit_after>extern crate irc;
extern crate rand;

use std::default::Default;
use irc::client::prelude::*;
use rand::{thread_rng, sample};

fn main() {
    let mut rng = thread_rng();
    let choices = ["heads!", "tails!"];
    let config = Config {
        nickname: Some(format!("pdxferris")),
        alt_nicks: Some(vec![format!("pdxrust-bot"), format!("pdx-rust-bot")]),
        server: Some(format!("irc.freenode.net")),
        channels: Some(vec![format!("#pdxbots"),
                            format!("#pdxrust")]),
        .. Default::default()
    };
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // We'll just panic if there's an error.
        if &message.command[..] == "PRIVMSG" {
            if let Some(msg) = message.suffix {
                if msg.starts_with("!flip") {
                    let choice = sample(&mut rng, choices.iter(), 1);
                    server.send_privmsg(&message.args[0],
                                        &*format!("The coin goes whirling through the air... {}",
                                                  choice.get(0).unwrap())).unwrap();
                } else if msg.starts_with("!source") {
                    server.send_privmsg(&message.args[0],
                                        "Find my source here: \
                                         https://github.com/wraithan/pdxrust-bot \
                                         Contribute and teach me new things!").unwrap();
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains Pair enum.

#[derive(Debug)]
#[derive(PartialEq)]
#[allow(non_camel_case_types)]
pub enum Pair {
    BTC_EUR,
    BTC_USD,
    ETC_BTC,
    ETC_EUR,
    ETC_USD,
    ETH_BTC,
    ETH_EUR,
    ETH_USD,
    EUR_USD,
    XRP_BTC,
    XRP_EUR,
    XRP_USD,
}
<commit_msg>Add more pairs<commit_after>//! This module contains Pair enum.

#[derive(Debug)]
#[derive(PartialEq)]
#[allow(non_camel_case_types)]
pub enum Pair {
    BTC_EUR,
    BTC_USD,
    ETC_BTC,
    ETC_ETH,
    ETC_EUR,
    ETC_USD,
    ETH_BTC,
    ETH_EUR,
    ETH_USD,
    EUR_USD,
    ICN_BTC,
    ICN_ETH,
    LTC_BTC,
    LTC_EUR,
    LTC_USD,
    XMR_BTC,
    XMR_EUR,
    XMR_USD,
    XRP_BTC,
    XRP_EUR,
    XRP_USD,
    ZEC_BTC,
    ZEC_EUR,
    ZEC_USD,
}
<|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;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PipeStateIdx {
	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: PipeStateIdx,
	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: PipeStateIdx::Handshake,
			handshake_state: HandshakePipeState::new(id, protocol, conn_ref.clone()),
			connected_state: ConnectedPipeState::new(id, conn_ref.clone())
		}
	}

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

	pub fn is_ready(&self) -> bool {
		self.state == PipeStateIdx::Connected
	}

	pub fn send(&mut self, msg: Message) {
		self.get_state().send(msg);
	}

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

	fn set_state(&mut self, state: PipeStateIdx, 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(PipeStateIdx::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<PipeStateIdx>>;
	/*fn readable(&mut self, event_loop: &mut EventLoop) -> io::Result<Option<PipeStateIdx>>;
	fn writable(&mut self, event_loop: &mut EventLoop) -> io::Result<Option<PipeStateIdx>>;*/

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

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::InvalidData, "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<PipeStateIdx>> {
		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(PipeStateIdx::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 readable(&mut self, event_loop: &mut EventLoop) -> io::Result<Option<PipeStateIdx>> {
		if self.received {
			return Ok(None)
		}

		try!(self.read_handshake());

		if self.sent {
			Ok(Some(PipeStateIdx::Connected))
		} else {
			let interest = mio::EventSet::hup() | mio::EventSet::writable();
			let poll_opt = mio::PollOpt::oneshot();

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

	fn writable(&mut self, event_loop: &mut EventLoop) -> io::Result<Option<PipeStateIdx>> {
		if self.sent {
			return Ok(None)
		}

		try!(self.write_handshake());

		if self.received {
			Ok(Some(PipeStateIdx::Connected))
		} else {
			let interest = mio::EventSet::hup() | mio::EventSet::readable();
			let poll_opt = mio::PollOpt::oneshot();
			try!(self.reregister(event_loop, interest, poll_opt));
			Ok(None)
		}
	}*/

	fn send(&mut self, _: Message) -> io::Result<()> {
		Ok(())
	}

}

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();
		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<PipeStateIdx>> {
		Ok(None)
	}

	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>Some more cleanup<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;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PipeStateIdx {
	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: PipeStateIdx,
	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: PipeStateIdx::Handshake,
			handshake_state: HandshakePipeState::new(id, protocol, conn_ref.clone()),
			connected_state: ConnectedPipeState::new(id, conn_ref.clone())
		}
	}

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

	pub fn is_ready(&self) -> bool {
		self.state == PipeStateIdx::Connected
	}

	pub fn send(&mut self, msg: Message) {
		self.get_state().send(msg);
	}

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

	fn set_state(&mut self, state: PipeStateIdx, 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(PipeStateIdx::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<PipeStateIdx>>;

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

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<PipeStateIdx>> {
		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(PipeStateIdx::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, _: Message) -> io::Result<()> {
		Ok(())
	}

}

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<PipeStateIdx>> {
		Ok(None)
	}

	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|>