<commit_before>//! Convenient utility methods, mostly for printing `syntect` data structures
//! prettily to the terminal.
use highlighting::{Style, StyleModifier};
use std::fmt::Write;
use std::ops::Range;
#[cfg(feature = "parsing")]
use parsing::ScopeStackOp;

/// Formats the styled fragments using 24-bit colour
/// terminal escape codes. Meant for debugging and testing.
/// It's currently fairly inefficient in its use of escape codes.
///
/// Note that this does not currently ever un-set the colour so that
/// the end of a line will also get highlighted with the background.
/// This means if you might want to use `println!("\x1b[0m");` after
/// to clear the colouring.
///
/// If `bg` is true then the background is also set
pub fn as_24_bit_terminal_escaped(v: &[(Style, &str)], bg: bool) -> String {
    let mut s: String = String::new();
    for &(ref style, text) in v.iter() {
        if bg {
            write!(s,
                   "\x1b[48;2;{};{};{}m",
                   style.background.r,
                   style.background.g,
                   style.background.b)
                .unwrap();
        }
        write!(s,
               "\x1b[38;2;{};{};{}m{}",
               style.foreground.r,
               style.foreground.g,
               style.foreground.b,
               text)
            .unwrap();
    }
    // s.push_str("\x1b[0m");
    s
}

/// Print out the various push and pop operations in a vector
/// with visual alignment to the line. Obviously for debugging.
#[cfg(feature = "parsing")]
pub fn debug_print_ops(line: &str, ops: &[(usize, ScopeStackOp)]) {
    for &(i, ref op) in ops.iter() {
        println!("{}", line.trim_right());
        print!("{: <1$}", "", i);
        match *op {
            ScopeStackOp::Push(s) => {
                println!("^ +{}", s);
            }
            ScopeStackOp::Pop(count) => {
                println!("^ pop {}", count);
            }
            ScopeStackOp::Clear(amount) => {
                println!("^ clear {:?}", amount);
            }
            ScopeStackOp::Restore => println!("^ restore"),
            ScopeStackOp::Noop => println!("noop"),
        }
    }
}

/// An iterator over the lines of a string, including the line endings.
///
/// This is similar to the standard library's `lines` method on `str`, except
/// that the yielded lines include the trailing newline character(s).
///
/// You can use it if you're parsing/highlighting some text that you have as a
/// string. With this, you can use the "newlines" variant of syntax definitions,
/// which is recommended.
///
/// # Examples
///
/// ```
/// use syntect::util::LinesWithEndings;
///
/// let mut lines = LinesWithEndings::from("foo\nbar\nbaz");
///
/// assert_eq!(Some("foo\n"), lines.next());
/// assert_eq!(Some("bar\n"), lines.next());
/// assert_eq!(Some("baz"), lines.next());
///
/// assert_eq!(None, lines.next());
/// ```
pub struct LinesWithEndings<'a> {
    input: &'a str,
}

impl<'a> LinesWithEndings<'a> {
    pub fn from(input: &'a str) -> LinesWithEndings<'a> {
        LinesWithEndings { input }
    }
}

impl<'a> Iterator for LinesWithEndings<'a> {
    type Item = &'a str;

    #[inline]
    fn next(&mut self) -> Option<&'a str> {
        if self.input.is_empty() {
            return None;
        }
        let split = self.input
            .find('\n')
            .map(|i| i + 1)
            .unwrap_or_else(|| self.input.len());
        let (line, rest) = self.input.split_at(split);
        self.input = rest;
        Some(line)
    }
}

/// Split a highlighted line at a byte index in the line into a before and
/// after component. It's just a helper that does the somewhat tricky logic
/// including splitting a span if the index lies on a boundary.
///
/// This can be used to extract a chunk of the line out for special treatment
/// like wrapping it in an HTML tag for extra styling.
///
/// Generic for testing purposes and fancier use cases, but intended for use with
/// the `Vec<(Style, &str)>` returned by `highlight` methods. Look at the source
/// code for `modify_range` for an example usage.
pub fn split_at<'a, A: Clone>(mut v: &[(A, &'a str)], mut split_i: usize) -> (Vec<(A, &'a str)>, Vec<(A, &'a str)>) {
    // Consume all tokens before the split
    let mut before = Vec::new();
    for tok in v {
        if tok.1.len() > split_i {
            break;
        }
        before.push(tok.clone());
        split_i -= tok.1.len();
    }
    v = &v[before.len()..];

    let mut after = Vec::new();
    // If necessary, split the token the split falls inside
    if v.len() > 0 && split_i > 0 {
        let (sa, sb) = v[0].1.split_at(split_i);
        before.push((v[0].0.clone(), sa));
        after.push((v[0].0.clone(), sb));
        v = &v[1..];
    }

    after.extend_from_slice(v);

    return (before, after);
}

/// Modify part of a highlighted line using a style modifier, useful for highlighting sections of a line.
///
/// # Examples
///
/// ```
/// use syntect::util::modify_range;
/// use syntect::highlighting::{Style, StyleModifier, FontStyle};
///
/// let plain = Style::default();
/// let boldmod = StyleModifier { foreground: None, background: None, font_style: Some(FontStyle::BOLD) };
/// let bold = plain.apply(boldmod);
///
/// let l = &[(plain, "abc"), (plain, "def"), (plain, "ghi")];
/// let l2 = modify_range(l, 1..6, boldmod);
/// assert_eq!(l2, &[(plain, "a"), (bold, "bc"), (bold, "def"), (plain, "ghi")]);
/// ```
pub fn modify_range<'a>(v: &[(Style, &'a str)], r: Range<usize>, modifier: StyleModifier) -> Vec<(Style, &'a str)> {
    let (mut result, in_and_after) = split_at(v, r.start);
    let (inside, mut after) = split_at(&in_and_after, r.end - r.start);

    result.extend(inside.iter().map(|(style, s)| { (style.apply(modifier), *s)}));
    result.append(&mut after);
    result
}

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

    #[test]
    fn test_lines_with_endings() {
        fn lines(s: &str) -> Vec<&str> {
            LinesWithEndings::from(s).collect()
        }

        assert!(lines("").is_empty());
        assert_eq!(lines("f"), vec!["f"]);
        assert_eq!(lines("foo"), vec!["foo"]);
        assert_eq!(lines("foo\n"), vec!["foo\n"]);
        assert_eq!(lines("foo\nbar"), vec!["foo\n", "bar"]);
        assert_eq!(lines("foo\nbar\n"), vec!["foo\n", "bar\n"]);
        assert_eq!(lines("foo\r\nbar"), vec!["foo\r\n", "bar"]);
        assert_eq!(lines("foo\r\nbar\r\n"), vec!["foo\r\n", "bar\r\n"]);
        assert_eq!(lines("\nfoo"), vec!["\n", "foo"]);
        assert_eq!(lines("\n\n\n"), vec!["\n", "\n", "\n"]);
    }

    #[test]
    fn test_split_at() {
        let l: &[(u8, &str)] = &[];
        let (before, after) = split_at(l, 0); // empty
        assert_eq!((&before[..], &after[..]), (&[][..],&[][..]));

        let l = &[(0u8, "abc"), (1u8, "def"), (2u8, "ghi")];

        let (before, after) = split_at(l, 0); // at start
        assert_eq!((&before[..], &after[..]), (&[][..],&[(0u8, "abc"), (1u8, "def"), (2u8, "ghi")][..]));

        let (before, after) = split_at(l, 4); // inside token
        assert_eq!((&before[..], &after[..]), (&[(0u8, "abc"), (1u8, "d")][..],&[(1u8, "ef"), (2u8, "ghi")][..]));

        let (before, after) = split_at(l, 3); // between tokens
        assert_eq!((&before[..], &after[..]), (&[(0u8, "abc")][..],&[(1u8, "def"), (2u8, "ghi")][..]));

        let (before, after) = split_at(l, 9); // just after last token
        assert_eq!((&before[..], &after[..]), (&[(0u8, "abc"), (1u8, "def"), (2u8, "ghi")][..], &[][..]));

        let (before, after) = split_at(l, 10); // out of bounds
        assert_eq!((&before[..], &after[..]), (&[(0u8, "abc"), (1u8, "def"), (2u8, "ghi")][..], &[][..]));
    }
}
<commit_msg>Improve variable naming in split_at<commit_after>//! Convenient utility methods, mostly for printing `syntect` data structures
//! prettily to the terminal.
use highlighting::{Style, StyleModifier};
use std::fmt::Write;
use std::ops::Range;
#[cfg(feature = "parsing")]
use parsing::ScopeStackOp;

/// Formats the styled fragments using 24-bit colour
/// terminal escape codes. Meant for debugging and testing.
/// It's currently fairly inefficient in its use of escape codes.
///
/// Note that this does not currently ever un-set the colour so that
/// the end of a line will also get highlighted with the background.
/// This means if you might want to use `println!("\x1b[0m");` after
/// to clear the colouring.
///
/// If `bg` is true then the background is also set
pub fn as_24_bit_terminal_escaped(v: &[(Style, &str)], bg: bool) -> String {
    let mut s: String = String::new();
    for &(ref style, text) in v.iter() {
        if bg {
            write!(s,
                   "\x1b[48;2;{};{};{}m",
                   style.background.r,
                   style.background.g,
                   style.background.b)
                .unwrap();
        }
        write!(s,
               "\x1b[38;2;{};{};{}m{}",
               style.foreground.r,
               style.foreground.g,
               style.foreground.b,
               text)
            .unwrap();
    }
    // s.push_str("\x1b[0m");
    s
}

/// Print out the various push and pop operations in a vector
/// with visual alignment to the line. Obviously for debugging.
#[cfg(feature = "parsing")]
pub fn debug_print_ops(line: &str, ops: &[(usize, ScopeStackOp)]) {
    for &(i, ref op) in ops.iter() {
        println!("{}", line.trim_right());
        print!("{: <1$}", "", i);
        match *op {
            ScopeStackOp::Push(s) => {
                println!("^ +{}", s);
            }
            ScopeStackOp::Pop(count) => {
                println!("^ pop {}", count);
            }
            ScopeStackOp::Clear(amount) => {
                println!("^ clear {:?}", amount);
            }
            ScopeStackOp::Restore => println!("^ restore"),
            ScopeStackOp::Noop => println!("noop"),
        }
    }
}

/// An iterator over the lines of a string, including the line endings.
///
/// This is similar to the standard library's `lines` method on `str`, except
/// that the yielded lines include the trailing newline character(s).
///
/// You can use it if you're parsing/highlighting some text that you have as a
/// string. With this, you can use the "newlines" variant of syntax definitions,
/// which is recommended.
///
/// # Examples
///
/// ```
/// use syntect::util::LinesWithEndings;
///
/// let mut lines = LinesWithEndings::from("foo\nbar\nbaz");
///
/// assert_eq!(Some("foo\n"), lines.next());
/// assert_eq!(Some("bar\n"), lines.next());
/// assert_eq!(Some("baz"), lines.next());
///
/// assert_eq!(None, lines.next());
/// ```
pub struct LinesWithEndings<'a> {
    input: &'a str,
}

impl<'a> LinesWithEndings<'a> {
    pub fn from(input: &'a str) -> LinesWithEndings<'a> {
        LinesWithEndings { input }
    }
}

impl<'a> Iterator for LinesWithEndings<'a> {
    type Item = &'a str;

    #[inline]
    fn next(&mut self) -> Option<&'a str> {
        if self.input.is_empty() {
            return None;
        }
        let split = self.input
            .find('\n')
            .map(|i| i + 1)
            .unwrap_or_else(|| self.input.len());
        let (line, rest) = self.input.split_at(split);
        self.input = rest;
        Some(line)
    }
}

/// Split a highlighted line at a byte index in the line into a before and
/// after component. It's just a helper that does the somewhat tricky logic
/// including splitting a span if the index lies on a boundary.
///
/// This can be used to extract a chunk of the line out for special treatment
/// like wrapping it in an HTML tag for extra styling.
///
/// Generic for testing purposes and fancier use cases, but intended for use with
/// the `Vec<(Style, &str)>` returned by `highlight` methods. Look at the source
/// code for `modify_range` for an example usage.
pub fn split_at<'a, A: Clone>(v: &[(A, &'a str)], split_i: usize) -> (Vec<(A, &'a str)>, Vec<(A, &'a str)>) {
    // This function works by gradually reducing the problem into smaller sub-problems from the front
    let mut rest = v;
    let mut rest_split_i = split_i;

    // Consume all tokens before the split
    let mut before = Vec::new();
    for tok in rest { // Use for instead of a while to avoid bounds checks
        if tok.1.len() > rest_split_i {
            break;
        }
        before.push(tok.clone());
        rest_split_i -= tok.1.len();
    }
    rest = &rest[before.len()..];

    let mut after = Vec::new();
    // If necessary, split the token the split falls inside
    if rest.len() > 0 && rest_split_i > 0 {
        let (sa, sb) = rest[0].1.split_at(rest_split_i);
        before.push((rest[0].0.clone(), sa));
        after.push((rest[0].0.clone(), sb));
        rest = &rest[1..];
    }

    after.extend_from_slice(rest);

    return (before, after);
}

/// Modify part of a highlighted line using a style modifier, useful for highlighting sections of a line.
///
/// # Examples
///
/// ```
/// use syntect::util::modify_range;
/// use syntect::highlighting::{Style, StyleModifier, FontStyle};
///
/// let plain = Style::default();
/// let boldmod = StyleModifier { foreground: None, background: None, font_style: Some(FontStyle::BOLD) };
/// let bold = plain.apply(boldmod);
///
/// let l = &[(plain, "abc"), (plain, "def"), (plain, "ghi")];
/// let l2 = modify_range(l, 1..6, boldmod);
/// assert_eq!(l2, &[(plain, "a"), (bold, "bc"), (bold, "def"), (plain, "ghi")]);
/// ```
pub fn modify_range<'a>(v: &[(Style, &'a str)], r: Range<usize>, modifier: StyleModifier) -> Vec<(Style, &'a str)> {
    let (mut result, in_and_after) = split_at(v, r.start);
    let (inside, mut after) = split_at(&in_and_after, r.end - r.start);

    result.extend(inside.iter().map(|(style, s)| { (style.apply(modifier), *s)}));
    result.append(&mut after);
    result
}

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

    #[test]
    fn test_lines_with_endings() {
        fn lines(s: &str) -> Vec<&str> {
            LinesWithEndings::from(s).collect()
        }

        assert!(lines("").is_empty());
        assert_eq!(lines("f"), vec!["f"]);
        assert_eq!(lines("foo"), vec!["foo"]);
        assert_eq!(lines("foo\n"), vec!["foo\n"]);
        assert_eq!(lines("foo\nbar"), vec!["foo\n", "bar"]);
        assert_eq!(lines("foo\nbar\n"), vec!["foo\n", "bar\n"]);
        assert_eq!(lines("foo\r\nbar"), vec!["foo\r\n", "bar"]);
        assert_eq!(lines("foo\r\nbar\r\n"), vec!["foo\r\n", "bar\r\n"]);
        assert_eq!(lines("\nfoo"), vec!["\n", "foo"]);
        assert_eq!(lines("\n\n\n"), vec!["\n", "\n", "\n"]);
    }

    #[test]
    fn test_split_at() {
        let l: &[(u8, &str)] = &[];
        let (before, after) = split_at(l, 0); // empty
        assert_eq!((&before[..], &after[..]), (&[][..],&[][..]));

        let l = &[(0u8, "abc"), (1u8, "def"), (2u8, "ghi")];

        let (before, after) = split_at(l, 0); // at start
        assert_eq!((&before[..], &after[..]), (&[][..],&[(0u8, "abc"), (1u8, "def"), (2u8, "ghi")][..]));

        let (before, after) = split_at(l, 4); // inside token
        assert_eq!((&before[..], &after[..]), (&[(0u8, "abc"), (1u8, "d")][..],&[(1u8, "ef"), (2u8, "ghi")][..]));

        let (before, after) = split_at(l, 3); // between tokens
        assert_eq!((&before[..], &after[..]), (&[(0u8, "abc")][..],&[(1u8, "def"), (2u8, "ghi")][..]));

        let (before, after) = split_at(l, 9); // just after last token
        assert_eq!((&before[..], &after[..]), (&[(0u8, "abc"), (1u8, "def"), (2u8, "ghi")][..], &[][..]));

        let (before, after) = split_at(l, 10); // out of bounds
        assert_eq!((&before[..], &after[..]), (&[(0u8, "abc"), (1u8, "def"), (2u8, "ghi")][..], &[][..]));
    }
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use types::{gboolean,FALSE};

use std::ascii;

#[inline]
pub fn is_true(v: gboolean) -> bool { v != FALSE }

#[inline]
pub fn is_false(v: gboolean) -> bool { v == FALSE }

pub fn escape_bytestring(s: &[u8]) -> String {
    let mut acc = Vec::with_capacity(s.len());
    for c in s.iter() {
        ascii::escape_default(*c, |esc| {
            acc.push(esc);
        })
    }
    unsafe { String::from_utf8_unchecked(acc) }
}
<commit_msg>util: Make escape_bytestring return Cow<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use types::{gboolean,FALSE};

use std::ascii;
use std::ascii::AsciiExt;
use std::borrow::IntoCow;
use std::str;
use std::string::CowString;

#[inline]
pub fn is_true(v: gboolean) -> bool { v != FALSE }

#[inline]
pub fn is_false(v: gboolean) -> bool { v == FALSE }

pub fn escape_bytestring<'a>(s: &'a [u8]) -> CowString<'a> {
    if s.is_ascii() {
        let s = unsafe { str::from_utf8_unchecked(s) };
        return s.into_cow();
    }
    let mut acc = Vec::with_capacity(s.len());
    for c in s.iter() {
        ascii::escape_default(*c, |esc| {
            acc.push(esc);
        })
    }
    let string = unsafe { String::from_utf8_unchecked(acc) };
    string.into_cow()
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use rustc_serialize::json::ToJson;
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;
use std::env;
use websocket::{client,Client,stream,Message,Sender,Receiver};
use std::thread;
use cbor;
use cbor::ToCbor;

use value::Value;
use server::Event;
use relation::Change;
use server;

// The (increasingly misnamed) login server is responsible for:
// * handling authentication via authrocket
// * serving static files for the editor and clients
// TODO needs review

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
    client: String,
    id: String,
    user_id: String,
    object: String,
    created_at: f64,
    expires_at: f64,
    ip: String,
    user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
    custom: Custom,
    id: String,
    realm_id: String,
    username: String,
    state: String,
    user_type: String,
    reference: Option<String>,
    name: String,
    email: String,
    object: String,
    last_login_at: f64,
    last_login_on: f64,
    created_at: f64,
    first_name: Option<String>,
    last_name: Option<String>,
    credentials: Vec<Credential>,
    membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
    id: String,
    credential_type: String,
    object: String,
}

pub fn run() {
    // TODO high thread-count is a workaround for https://github.com/hyperium/hyper/issues/368
    Server::http("0.0.0.0:8080").unwrap().handle_threads(login, 100).unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    contents
}

fn file_exists(path: &str) -> bool {
    let path_obj = Path::new(path);
    path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
    let mime_types = Types::new().unwrap();
    let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
    let file;
    let file_path: &str;
    if file_exists(&local_path) {
        file = read_file_bytes(&local_path);
        file_path = &local_path;
    } else {
        let content = read_file_bytes(default_file);
        //@HACK, @TODO: absolutize the html file so that it looks in the right place
        //this allows us to use file:/// locally, while still doing the right thing
        //when we're hooked up to the server
        let mut str = String::from_utf8(content).unwrap();
        str = str.replace("href=\"", "href=\"/app/");
        str = str.replace("src=\"", "src=\"/app/");
        str = str.replace("/app/http", "http");
        file = str.as_bytes().to_owned();
        file_path = default_file;
    }
    let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
    res.headers_mut().set(ContentType(mime));
    let mut res = res.start().unwrap();
    res.write_all(&file).unwrap();
    res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

    // Don't use a port if we're running in local mode
    let mut port = ":8000";
    for argument in env::args() {
        match &*argument {
            "local" => {
                port = "";
            },
            _ => continue,
        }
    }

    match (&req.method.clone(), &req.uri.clone()) {
        (&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

            // Form a url from the path
            let absolute_path = "http://localhost".to_string() + relative_path;
            let url = Url::parse(&*absolute_path).unwrap();

            // Get the file name
            let scheme_data = &url.scheme_data;

            let requested_file = match scheme_data {
                &Relative(ref rsd) => rsd.path[0].clone(),
                _ => panic!("Expected relative path"),
            };
            let path_info = match scheme_data {
                &Relative(ref rsd) => rsd,
                _ => panic!("Expected relative path"),
            };

            // Parse the query string
            let query_pairs = &url.query_pairs();

            // Handle login
            match &*requested_file {
                "app.html" | "app" => {
                    serve_local_or_file(res, &path_info.path, "../ui/app.html");
                },
                "editor.html" | "editor" => {
                    serve_local_or_file(res, &path_info.path, "../ui/editor.html");
                },
                "login.html" => {
                    println!("Authenticating User");

                    let referer = format!("{}",req.headers.get::<hyper::header::Referer>().unwrap());
                    let referer_url = Url::parse(&*referer).unwrap();

                    let pairs = query_pairs.clone().unwrap();
                    match &pairs[..] {
                        [(_ , ref page), (ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

                            // We have a login token, now to authenticate
                            let client = hyper::client::Client::new();
                            let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
                            let req = client.request(hyper::method::Method::Get,&*api_call);

                            // Set the appropriate headers for authorocket
                            let mut headers = Headers::new();
                            let json: Mime = "application/json".parse().unwrap();
                            let content_type = ContentType(json);
                            headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
                            headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
                            headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
                            headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
                            headers.set(content_type);

                            // Send the request and receive a response with session data
                            let mut client_res = req.headers(headers).send().unwrap();

                            match client_res.status_raw() {

                                &hyper::http::RawStatus(200,_) => {

                                    let mut body = String::new();
                                    client_res.read_to_string(&mut body).unwrap();
                                    let session_data: Session = json::decode(&body).unwrap();
                                    println!("Welcome to Eve, {:?}!",session_data.user.username);
                                    println!("Login Successful. Redirecting to user area.");

                                    // Connect to the Eve runtime and add the user to the eveusers table
                                    let ws_result = open_websocket("ws://0.0.0.0:2794");
                                    match ws_result {
                                        // If things went okay, redirect to the Eve UI
                                        Ok(mut sender) => {
                                            // Form the response
                                            *res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

                                            // Form the response headers
                                            let mut headers = Headers::new();
                                            let redirect_url = referer_url.scheme.clone() + "://" + referer_url.domain().unwrap().clone() + port + "/" + page;
                                            let location = Location(redirect_url);
                                            let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
                                            let cookies = SetCookie(vec![user_cookie]);
                                            headers.set(location);
                                            headers.set(cookies);
                                            *res.headers_mut() = headers;

                                            // Create eveusers table and insert the new user
                                            let change = ("eveusers".to_owned(),
                                                Change{
                                                    fields: vec!["eveusers: id".to_owned(), "eveusers: username".to_owned()],
                                                    insert: vec![vec![
                                                        Value::String(session_data.user.id.clone()),
                                                        Value::String(session_data.user.username.clone())
                                                    ]],
                                                    remove: vec![],
                                                });
                                            let event = Event{changes: vec![change], session: "".to_owned(), commands: vec![]};
                                            send_event(event, &mut sender);
                                            let _ = sender.send_message(Message::Close(None));
                                        }
                                        // Otherwise, throw an error... maybe redirect to a special page.
                                        Err(e) => {
                                            println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
                                            *res.status_mut() = hyper::status::StatusCode::NotFound;
                                            panic!("Oh no!");
                                            //serve_file("404.html",res);
                                        }
                                    }

                                    println!("Login complete.");
                                }
                                _ => {
                                    println!("ERROR: Could not authenticate user with token {}",token);
                                    *res.status_mut() = hyper::status::StatusCode::Forbidden;
                                    panic!("Oh no!");
                                    //serve_file("404.html",res);
                                }
                            };
                        },
                        _ => panic!("Oh no!"), //serve_file("404.html",res),
                    }
                },
                "logout.html" => {
                    println!("Logging out...");
                    let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                    println!("{:?}",user_id);
                },
                "favicon.ico" => (),
                other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
            };
        }
        _ => panic!("Oh no!"),
    }
}

pub fn open_websocket(url_string: &str) -> Result<client::sender::Sender<stream::WebSocketStream>,String> {

    //let mut context = SslContext::new(SslMethod::Tlsv1).unwrap();
    //let _ = context.set_certificate_file(&(Path::new("server.crt")), X509FileType::PEM);
    //let _ = context.set_private_key_file(&(Path::new("server.key")), X509FileType::PEM);

    let url = Url::parse(url_string).unwrap();
    println!("Connecting to {}", url);

    let request = match Client::connect(url) {
        Ok(t) => t,
        Err(e) => {
            return Err(format!("{}", e).to_string());
        }
    };

    let response = match request.send() {
        Ok(t) => t,
        Err(e) => {
            return Err(format!("{}", e).to_string());
        }
    };

    match response.validate() {
        Ok(_) => println!("Response valid. Start sending/receiving..."),
        Err(e) => {
            return Err(format!("{}", e).to_string());
        }
    };

    let (sender, mut receiver) = response.begin().split();

    thread::spawn(move || {
        for message in receiver.incoming_messages() {
            let message = match message {
                Ok(m) => m,
                Err(_) => return,
            };
            match message {
                Message::Text(_) => {
                    //let json = Json::from_str(&text).unwrap();
                    //let event: Event = FromJson::from_json(&json);
                },
                Message::Close(_) => {
                    println!("Received close message");
                    return;
                }
                _ => println!("Unknown message: {:?}", message)
            }
        }
    });

    Ok(sender)
}

pub fn send_event(event: Event, sender: &mut client::sender::Sender<stream::WebSocketStream>) {
    let mut e = cbor::Encoder::from_memory();
    let json = event.to_json();
    let cbor = json.to_cbor();
    e.encode(vec![cbor]).unwrap();
    sender.send_message(Message::Binary(e.into_bytes())).unwrap();
}<commit_msg>Dont die on closed connections in static server<commit_after>use std::io::{Read, Write};
use std::io;
use std::fs::File;
use std::error::Error;
use hyper;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use rustc_serialize::json::ToJson;
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;
use std::env;
use websocket::{client,Client,stream,Message,Sender,Receiver};
use std::thread;
use cbor;
use cbor::ToCbor;

use value::Value;
use server::Event;
use relation::Change;
use server;

// The (increasingly misnamed) login server is responsible for:
// * handling authentication via authrocket
// * serving static files for the editor and clients
// TODO needs review

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
    client: String,
    id: String,
    user_id: String,
    object: String,
    created_at: f64,
    expires_at: f64,
    ip: String,
    user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
    custom: Custom,
    id: String,
    realm_id: String,
    username: String,
    state: String,
    user_type: String,
    reference: Option<String>,
    name: String,
    email: String,
    object: String,
    last_login_at: f64,
    last_login_on: f64,
    created_at: f64,
    first_name: Option<String>,
    last_name: Option<String>,
    credentials: Vec<Credential>,
    membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
    id: String,
    credential_type: String,
    object: String,
}

pub fn run() {
    // TODO high thread-count is a workaround for https://github.com/hyperium/hyper/issues/368
    Server::http("0.0.0.0:8080").unwrap().handle_threads(login, 100).unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    contents
}

fn file_exists(path: &str) -> bool {
    let path_obj = Path::new(path);
    path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) -> io::Result<()> {
    let mime_types = Types::new().unwrap();
    let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
    let file;
    let file_path: &str;
    if file_exists(&local_path) {
        file = read_file_bytes(&local_path);
        file_path = &local_path;
    } else {
        let content = read_file_bytes(default_file);
        //@HACK, @TODO: absolutize the html file so that it looks in the right place
        //this allows us to use file:/// locally, while still doing the right thing
        //when we're hooked up to the server
        let mut str = String::from_utf8(content).unwrap();
        str = str.replace("href=\"", "href=\"/app/");
        str = str.replace("src=\"", "src=\"/app/");
        str = str.replace("/app/http", "http");
        file = str.as_bytes().to_owned();
        file_path = default_file;
    }
    let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
    res.headers_mut().set(ContentType(mime));
    let mut res = try!(res.start());
    try!(res.write_all(&file));
    try!(res.end());
    Ok(())
}

fn login(req: Request, mut res: Response<Fresh>) {

    // Don't use a port if we're running in local mode
    let mut port = ":8000";
    for argument in env::args() {
        match &*argument {
            "local" => {
                port = "";
            },
            _ => continue,
        }
    }

    match (&req.method.clone(), &req.uri.clone()) {
        (&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

            // Form a url from the path
            let absolute_path = "http://localhost".to_string() + relative_path;
            let url = Url::parse(&*absolute_path).unwrap();

            // Get the file name
            let scheme_data = &url.scheme_data;

            let requested_file = match scheme_data {
                &Relative(ref rsd) => rsd.path[0].clone(),
                _ => panic!("Expected relative path"),
            };
            let path_info = match scheme_data {
                &Relative(ref rsd) => rsd,
                _ => panic!("Expected relative path"),
            };

            // Parse the query string
            let query_pairs = &url.query_pairs();

            // Handle login
            match &*requested_file {
                "app.html" | "app" => {
                    let result = serve_local_or_file(res, &path_info.path, "../ui/app.html");
                    if let Err(error) = result {
                        println!("Warning: serve error {:?}", error);
                    }
                },
                "editor.html" | "editor" => {
                    let result = serve_local_or_file(res, &path_info.path, "../ui/editor.html");
                    if let Err(error) = result {
                        println!("Warning: serve error {:?}", error);
                    }
                },
                "login.html" => {
                    println!("Authenticating User");

                    let referer = format!("{}",req.headers.get::<hyper::header::Referer>().unwrap());
                    let referer_url = Url::parse(&*referer).unwrap();

                    let pairs = query_pairs.clone().unwrap();
                    match &pairs[..] {
                        [(_ , ref page), (ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

                            // We have a login token, now to authenticate
                            let client = hyper::client::Client::new();
                            let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
                            let req = client.request(hyper::method::Method::Get,&*api_call);

                            // Set the appropriate headers for authorocket
                            let mut headers = Headers::new();
                            let json: Mime = "application/json".parse().unwrap();
                            let content_type = ContentType(json);
                            headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
                            headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
                            headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
                            headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
                            headers.set(content_type);

                            // Send the request and receive a response with session data
                            let mut client_res = req.headers(headers).send().unwrap();

                            match client_res.status_raw() {

                                &hyper::http::RawStatus(200,_) => {

                                    let mut body = String::new();
                                    client_res.read_to_string(&mut body).unwrap();
                                    let session_data: Session = json::decode(&body).unwrap();
                                    println!("Welcome to Eve, {:?}!",session_data.user.username);
                                    println!("Login Successful. Redirecting to user area.");

                                    // Connect to the Eve runtime and add the user to the eveusers table
                                    let ws_result = open_websocket("ws://0.0.0.0:2794");
                                    match ws_result {
                                        // If things went okay, redirect to the Eve UI
                                        Ok(mut sender) => {
                                            // Form the response
                                            *res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

                                            // Form the response headers
                                            let mut headers = Headers::new();
                                            let redirect_url = referer_url.scheme.clone() + "://" + referer_url.domain().unwrap().clone() + port + "/" + page;
                                            let location = Location(redirect_url);
                                            let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
                                            let cookies = SetCookie(vec![user_cookie]);
                                            headers.set(location);
                                            headers.set(cookies);
                                            *res.headers_mut() = headers;

                                            // Create eveusers table and insert the new user
                                            let change = ("eveusers".to_owned(),
                                                Change{
                                                    fields: vec!["eveusers: id".to_owned(), "eveusers: username".to_owned()],
                                                    insert: vec![vec![
                                                        Value::String(session_data.user.id.clone()),
                                                        Value::String(session_data.user.username.clone())
                                                    ]],
                                                    remove: vec![],
                                                });
                                            let event = Event{changes: vec![change], session: "".to_owned(), commands: vec![]};
                                            send_event(event, &mut sender);
                                            let _ = sender.send_message(Message::Close(None));
                                        }
                                        // Otherwise, throw an error... maybe redirect to a special page.
                                        Err(e) => {
                                            println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
                                            *res.status_mut() = hyper::status::StatusCode::NotFound;
                                            panic!("Oh no!");
                                            //serve_file("404.html",res);
                                        }
                                    }

                                    println!("Login complete.");
                                }
                                _ => {
                                    println!("ERROR: Could not authenticate user with token {}",token);
                                    *res.status_mut() = hyper::status::StatusCode::Forbidden;
                                    panic!("Oh no!");
                                    //serve_file("404.html",res);
                                }
                            };
                        },
                        _ => panic!("Oh no!"), //serve_file("404.html",res),
                    }
                },
                "logout.html" => {
                    println!("Logging out...");
                    let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                    println!("{:?}",user_id);
                },
                "favicon.ico" => (),
                other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
            };
        }
        _ => panic!("Oh no!"),
    }
}

pub fn open_websocket(url_string: &str) -> Result<client::sender::Sender<stream::WebSocketStream>,String> {

    //let mut context = SslContext::new(SslMethod::Tlsv1).unwrap();
    //let _ = context.set_certificate_file(&(Path::new("server.crt")), X509FileType::PEM);
    //let _ = context.set_private_key_file(&(Path::new("server.key")), X509FileType::PEM);

    let url = Url::parse(url_string).unwrap();
    println!("Connecting to {}", url);

    let request = match Client::connect(url) {
        Ok(t) => t,
        Err(e) => {
            return Err(format!("{}", e).to_string());
        }
    };

    let response = match request.send() {
        Ok(t) => t,
        Err(e) => {
            return Err(format!("{}", e).to_string());
        }
    };

    match response.validate() {
        Ok(_) => println!("Response valid. Start sending/receiving..."),
        Err(e) => {
            return Err(format!("{}", e).to_string());
        }
    };

    let (sender, mut receiver) = response.begin().split();

    thread::spawn(move || {
        for message in receiver.incoming_messages() {
            let message = match message {
                Ok(m) => m,
                Err(_) => return,
            };
            match message {
                Message::Text(_) => {
                    //let json = Json::from_str(&text).unwrap();
                    //let event: Event = FromJson::from_json(&json);
                },
                Message::Close(_) => {
                    println!("Received close message");
                    return;
                }
                _ => println!("Unknown message: {:?}", message)
            }
        }
    });

    Ok(sender)
}

pub fn send_event(event: Event, sender: &mut client::sender::Sender<stream::WebSocketStream>) {
    let mut e = cbor::Encoder::from_memory();
    let json = event.to_json();
    let cbor = json.to_cbor();
    e.encode(vec![cbor]).unwrap();
    sender.send_message(Message::Binary(e.into_bytes())).unwrap();
}<|endoftext|>


<commit_before>use std::error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, BufRead, ErrorKind, Read};
use std::mem;
use std::time::Duration;

use bytes::{Buf, IntoBuf, Reader};
use futures::{Async, Future, Poll, Stream};
use tokio_io::{try_nb, AsyncRead};
use tokio_timer;

use error::{Error, HyperError};

// Synonym of `twitter_stream_message::util::string_enums`
macro_rules! string_enums {
    (
        $(
            $(#[$attr:meta])*
            pub enum $E:ident {
                $(
                    $(#[$v_attr:meta])*
                    $V:ident($by:expr)
                ),*;
                $(#[$u_attr:meta])*
                $U:ident(_),
            }
        )*
    ) => {
        $(
            $(#[$attr])*
            pub enum $E {
                $(
                    $(#[$v_attr])*
                    $V,
                )*
                $(#[$u_attr])*
                $U(String),
            }

            impl std::convert::AsRef<str> for $E {
                fn as_ref(&self) -> &str {
                    match *self {
                        $($E::$V => $by,)*
                        $E::$U(ref s) => s,
                    }
                }
            }

            impl std::fmt::Display for $E {
                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                    AsRef::<str>::as_ref(self).fmt(f)
                }
            }

            impl std::cmp::PartialEq for $E {
                fn eq(&self, other: &$E) -> bool {
                    match *self {
                        $($E::$V => match *other {
                            $E::$V => true,
                            $E::$U(ref s) if $by == s => true,
                            _ => false,
                        },)*
                        $E::$U(ref s) => match *other {
                            $($E::$V => $by == s,)*
                            $E::$U(ref t) => s == t,
                        },
                    }
                }
            }

            impl std::hash::Hash for $E {
                fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
                    match *self {
                        $($E::$V => $by.hash(state),)*
                        $E::$U(ref s) => s.hash(state),
                    }
                }
            }

            impl std::cmp::Eq for $E {}
        )*
    }
}

pub enum Either<A, B> {
    A(A),
    B(B),
}

pub struct Lines<B> {
    read: B,
    line: Vec<u8>,
}

/// Wrapper to map `T::Error` onto `Error`.
pub struct MapErr<T>(T);

pub struct StreamRead<S: Stream>
where
    S::Item: IntoBuf,
{
    body: S,
    buf: Reader<<S::Item as IntoBuf>::Buf>,
    error: Option<S::Error>,
}

/// A `tokio_timer::Timeout`-like type that holds the original `Duration` which can be used to
/// create another `Timeout`.
pub struct Timeout<F> {
    tokio: tokio_timer::Timeout<F>,
    dur: Duration,
}

pub type MaybeTimeout<F> = futures::future::Either<Timeout<F>, MapErr<F>>;

pub type MaybeTimeoutStream<S> = Either<MapErr<tokio_timer::Timeout<S>>, MapErr<S>>;

/// Represents an infallible operation in `default_connector::new`.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum Never {}

pub trait IntoError {
    fn into_error(self) -> Error;
}

impl<A: Read, B: Read> Read for Either<A, B> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            Either::A(ref mut a) => a.read(buf),
            Either::B(ref mut b) => b.read(buf),
        }
    }
}

impl<A: BufRead, B: BufRead> BufRead for Either<A, B> {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        match *self {
            Either::A(ref mut a) => a.fill_buf(),
            Either::B(ref mut b) => b.fill_buf(),
        }
    }

    fn consume(&mut self, amt: usize) {
        match *self {
            Either::A(ref mut a) => a.consume(amt),
            Either::B(ref mut b) => b.consume(amt),
        }
    }
}

impl<A: AsyncRead, B: AsyncRead> AsyncRead for Either<A, B> {}

impl<A, B> Stream for Either<A, B>
where
    A: Stream,
    B: Stream<Item = A::Item, Error = A::Error>,
{
    type Item = A::Item;
    type Error = A::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match *self {
            Either::A(ref mut a) => a.poll(),
            Either::B(ref mut b) => b.poll(),
        }
    }
}

impl<B> Lines<B> {
    pub fn new(read: B) -> Self {
        Lines {
            read,
            line: Vec::new(),
        }
    }

    pub fn get_mut(&mut self) -> &mut B {
        &mut self.read
    }
}

impl<B: BufRead> Stream for Lines<B> {
    type Item = Vec<u8>;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            let n = try_nb!(self.read.read_until(b'\n', &mut self.line));
            if self.line.ends_with(b"\r\n") {
                // TODO: remove CRLF in v0.10
                // let len = self.line.len();
                // self.line.truncate(len - 2);
                break;
            }
            if n == 0 {
                if self.line.is_empty() {
                    return Ok(None.into());
                } else {
                    break;
                }
            }
            // Not EOF nor CRLF, continue reading.
        }

        Ok(Some(mem::replace(&mut self.line, Vec::new())).into())
    }
}

impl<F: Future> Future for MapErr<F>
where
    F::Error: IntoError,
{
    type Item = F::Item;
    type Error = Error;

    fn poll(&mut self) -> Poll<F::Item, Error> {
        self.0.poll().map_err(IntoError::into_error)
    }
}

impl<S: Stream> Stream for MapErr<S>
where
    S::Error: IntoError,
{
    type Item = S::Item;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<S::Item>, Error> {
        self.0.poll().map_err(IntoError::into_error)
    }
}

impl<S: Stream> StreamRead<S>
where
    S::Item: IntoBuf + Default,
{
    pub fn new(body: S) -> Self {
        StreamRead {
            body,
            buf: S::Item::default().into_buf().reader(),
            error: None,
        }
    }

    pub fn take_err(&mut self) -> Option<S::Error> {
        self.error.take()
    }
}

impl<S: Stream> Read for StreamRead<S>
where
    S::Item: IntoBuf,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.fill_buf()?;
        self.buf.read(buf)
    }
}

impl<S: Stream> BufRead for StreamRead<S>
where
    S::Item: IntoBuf,
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        while !self.buf.get_ref().has_remaining() {
            match self.body.poll() {
                Ok(Async::Ready(Some(data))) => self.buf = data.into_buf().reader(),
                Ok(Async::Ready(None)) => break,
                Ok(Async::NotReady) => return Err(ErrorKind::WouldBlock.into()),
                Err(e) => {
                    self.error = Some(e);
                    return Err(ErrorKind::Other.into());
                }
            }
        }

        Ok(self.buf.get_ref().bytes())
    }

    fn consume(&mut self, amt: usize) {
        BufRead::consume(&mut self.buf, amt)
    }
}

impl<S: Stream> AsyncRead for StreamRead<S> where S::Item: IntoBuf {}

impl<F> Timeout<F> {
    pub fn new(fut: F, dur: Duration) -> Self {
        Timeout {
            tokio: tokio_timer::Timeout::new(fut, dur),
            dur,
        }
    }
}

impl<F: Future> Future for Timeout<F>
where
    F::Error: IntoError,
{
    type Item = F::Item;
    type Error = Error;

    fn poll(&mut self) -> Poll<F::Item, Error> {
        MapErr(&mut self.tokio).poll()
    }
}

impl error::Error for Never {
    fn description(&self) -> &str {
        match *self {}
    }
}

impl Display for Never {
    fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
        match *self {}
    }
}

impl IntoError for Error {
    fn into_error(self) -> Error {
        self
    }
}

impl IntoError for HyperError {
    fn into_error(self) -> Error {
        Error::Hyper(self)
    }
}

impl<E: IntoError> IntoError for tokio_timer::timeout::Error<E> {
    fn into_error(self) -> Error {
        self.into_inner().map_or(Error::TimedOut, E::into_error)
    }
}

pub fn fmt_join<T: Display>(t: &[T], sep: &str, f: &mut Formatter<'_>) -> fmt::Result {
    let mut iter = t.iter();
    if let Some(t) = iter.next() {
        Display::fmt(t, f)?;
        for t in iter {
            write!(f, "{}{}", sep, t)?;
        }
    }
    Ok(())
}

const COMMA: &str = "%2C";

pub fn fmt_follow(ids: &[u64], f: &mut Formatter<'_>) -> fmt::Result {
    fmt_join(ids, COMMA, f)
}

type Location = ((f64, f64), (f64, f64));

pub fn fmt_locations(locs: &[Location], f: &mut Formatter<'_>) -> fmt::Result {
    use std::mem::size_of;
    use std::slice;

    use static_assertions::const_assert;

    let locs: &[f64] = unsafe {
        let ptr: *const Location = locs.as_ptr();
        const_assert!(size_of::<Location>() % size_of::<f64>() == 0);
        let n = locs.len() * (size_of::<Location>() / size_of::<f64>());
        slice::from_raw_parts(ptr as *const f64, n)
    };

    fmt_join(locs, COMMA, f)
}

#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn not(p: &bool) -> bool {
    !p
}

pub fn timeout<F>(fut: F, dur: Option<Duration>) -> MaybeTimeout<F> {
    use futures::future::Either;

    match dur {
        Some(dur) => Either::A(Timeout::new(fut, dur)),
        None => Either::B(MapErr(fut)),
    }
}

pub fn timeout_to_stream<F, S>(timeout: &MaybeTimeout<F>, s: S) -> MaybeTimeoutStream<S> {
    use futures::future::Either as EitherFut;

    match *timeout {
        EitherFut::A(ref t) => Either::A(MapErr(tokio_timer::Timeout::new(s, t.dur))),
        EitherFut::B(_) => Either::B(MapErr(s)),
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Cursor, Read};

    use bytes::Bytes;
    use futures::stream;

    use super::*;

    const BUF_SIZE: usize = 8 * 1024;

    #[test]
    fn lines() {
        let lines = [
            "abc\r\n",
            "d\r\n",
            "efg\r\n",
            "hijk\r\n",
            "\r\n",
            "lmn\r\n",
            "opq\rrs\r\n",
            "\n\rtuv\r\r\n",
            "wxyz\n",
        ];
        let body = [
            b"abc\r\n" as &[_],
            b"d\r\nefg\r\n" as &[_],
            b"hi" as &[_],
            b"jk" as &[_],
            b"" as &[_],
            b"\r\n" as &[_],
            b"\r\n" as &[_],
            b"lmn\r\nop" as &[_],
            b"q\rrs\r" as &[_],
            b"\n\n\rtuv\r\r\n" as &[_],
            b"wxyz\n" as &[_],
        ];

        let mut iter1 = lines.iter().cloned();
        let mut iter2 = Lines::new(StreamRead::new(stream::iter_ok::<_, ()>(
            body.iter().cloned(),
        )))
        .wait()
        .map(|s| String::from_utf8(s.unwrap().to_vec()).unwrap());

        for _ in 0..(lines.len() + 1) {
            assert_eq!(iter1.next(), iter2.next().as_ref().map(String::as_str));
        }
    }

    #[test]
    fn stream_read() {
        macro_rules! assert_id {
            ($($elm:expr),*) => {{
                let elms = [$(Bytes::from(&$elm[..])),*];
                let mut buf = Vec::new();
                StreamRead {
                    body: stream::iter_ok::<_,()>(
                        elms.iter().cloned().map(Cursor::new)
                    ),
                    buf: Cursor::new(Bytes::new()).reader(),
                    error: None,
                }.read_to_end(&mut buf).unwrap();
                assert_eq!(buf, elms.concat());
            }};
        }
        assert_id!();
        assert_id!([]);
        assert_id!([], [0], [], [], [1, 2]);
        assert_id!([0; BUF_SIZE + 1], [1; BUF_SIZE - 1], [2; BUF_SIZE * 5 / 2]);
    }
}
<commit_msg>Remove unused items<commit_after>use std::fmt::{self, Display, Formatter};
use std::io::{self, BufRead, ErrorKind, Read};
use std::mem;
use std::time::Duration;

use bytes::{Buf, IntoBuf, Reader};
use futures::{Async, Future, Poll, Stream};
use tokio_io::{try_nb, AsyncRead};
use tokio_timer;

use error::{Error, HyperError};

// Synonym of `twitter_stream_message::util::string_enums`
macro_rules! string_enums {
    (
        $(
            $(#[$attr:meta])*
            pub enum $E:ident {
                $(
                    $(#[$v_attr:meta])*
                    $V:ident($by:expr)
                ),*;
                $(#[$u_attr:meta])*
                $U:ident(_),
            }
        )*
    ) => {
        $(
            $(#[$attr])*
            pub enum $E {
                $(
                    $(#[$v_attr])*
                    $V,
                )*
                $(#[$u_attr])*
                $U(String),
            }

            impl std::convert::AsRef<str> for $E {
                fn as_ref(&self) -> &str {
                    match *self {
                        $($E::$V => $by,)*
                        $E::$U(ref s) => s,
                    }
                }
            }

            impl std::fmt::Display for $E {
                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                    AsRef::<str>::as_ref(self).fmt(f)
                }
            }

            impl std::cmp::PartialEq for $E {
                fn eq(&self, other: &$E) -> bool {
                    match *self {
                        $($E::$V => match *other {
                            $E::$V => true,
                            $E::$U(ref s) if $by == s => true,
                            _ => false,
                        },)*
                        $E::$U(ref s) => match *other {
                            $($E::$V => $by == s,)*
                            $E::$U(ref t) => s == t,
                        },
                    }
                }
            }

            impl std::hash::Hash for $E {
                fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
                    match *self {
                        $($E::$V => $by.hash(state),)*
                        $E::$U(ref s) => s.hash(state),
                    }
                }
            }

            impl std::cmp::Eq for $E {}
        )*
    }
}

pub enum Either<A, B> {
    A(A),
    B(B),
}

pub struct Lines<B> {
    read: B,
    line: Vec<u8>,
}

/// Wrapper to map `T::Error` onto `Error`.
pub struct MapErr<T>(T);

pub struct StreamRead<S: Stream>
where
    S::Item: IntoBuf,
{
    body: S,
    buf: Reader<<S::Item as IntoBuf>::Buf>,
    error: Option<S::Error>,
}

/// A `tokio_timer::Timeout`-like type that holds the original `Duration` which can be used to
/// create another `Timeout`.
pub struct Timeout<F> {
    tokio: tokio_timer::Timeout<F>,
    dur: Duration,
}

pub type MaybeTimeout<F> = futures::future::Either<Timeout<F>, MapErr<F>>;

pub type MaybeTimeoutStream<S> = Either<MapErr<tokio_timer::Timeout<S>>, MapErr<S>>;

pub trait IntoError {
    fn into_error(self) -> Error;
}

impl<A: Read, B: Read> Read for Either<A, B> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            Either::A(ref mut a) => a.read(buf),
            Either::B(ref mut b) => b.read(buf),
        }
    }
}

impl<A: BufRead, B: BufRead> BufRead for Either<A, B> {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        match *self {
            Either::A(ref mut a) => a.fill_buf(),
            Either::B(ref mut b) => b.fill_buf(),
        }
    }

    fn consume(&mut self, amt: usize) {
        match *self {
            Either::A(ref mut a) => a.consume(amt),
            Either::B(ref mut b) => b.consume(amt),
        }
    }
}

impl<A: AsyncRead, B: AsyncRead> AsyncRead for Either<A, B> {}

impl<A, B> Stream for Either<A, B>
where
    A: Stream,
    B: Stream<Item = A::Item, Error = A::Error>,
{
    type Item = A::Item;
    type Error = A::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match *self {
            Either::A(ref mut a) => a.poll(),
            Either::B(ref mut b) => b.poll(),
        }
    }
}

impl<B> Lines<B> {
    pub fn new(read: B) -> Self {
        Lines {
            read,
            line: Vec::new(),
        }
    }

    pub fn get_mut(&mut self) -> &mut B {
        &mut self.read
    }
}

impl<B: BufRead> Stream for Lines<B> {
    type Item = Vec<u8>;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            let n = try_nb!(self.read.read_until(b'\n', &mut self.line));
            if self.line.ends_with(b"\r\n") {
                // TODO: remove CRLF in v0.10
                // let len = self.line.len();
                // self.line.truncate(len - 2);
                break;
            }
            if n == 0 {
                if self.line.is_empty() {
                    return Ok(None.into());
                } else {
                    break;
                }
            }
            // Not EOF nor CRLF, continue reading.
        }

        Ok(Some(mem::replace(&mut self.line, Vec::new())).into())
    }
}

impl<F: Future> Future for MapErr<F>
where
    F::Error: IntoError,
{
    type Item = F::Item;
    type Error = Error;

    fn poll(&mut self) -> Poll<F::Item, Error> {
        self.0.poll().map_err(IntoError::into_error)
    }
}

impl<S: Stream> Stream for MapErr<S>
where
    S::Error: IntoError,
{
    type Item = S::Item;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<S::Item>, Error> {
        self.0.poll().map_err(IntoError::into_error)
    }
}

impl<S: Stream> StreamRead<S>
where
    S::Item: IntoBuf + Default,
{
    pub fn new(body: S) -> Self {
        StreamRead {
            body,
            buf: S::Item::default().into_buf().reader(),
            error: None,
        }
    }

    pub fn take_err(&mut self) -> Option<S::Error> {
        self.error.take()
    }
}

impl<S: Stream> Read for StreamRead<S>
where
    S::Item: IntoBuf,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.fill_buf()?;
        self.buf.read(buf)
    }
}

impl<S: Stream> BufRead for StreamRead<S>
where
    S::Item: IntoBuf,
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        while !self.buf.get_ref().has_remaining() {
            match self.body.poll() {
                Ok(Async::Ready(Some(data))) => self.buf = data.into_buf().reader(),
                Ok(Async::Ready(None)) => break,
                Ok(Async::NotReady) => return Err(ErrorKind::WouldBlock.into()),
                Err(e) => {
                    self.error = Some(e);
                    return Err(ErrorKind::Other.into());
                }
            }
        }

        Ok(self.buf.get_ref().bytes())
    }

    fn consume(&mut self, amt: usize) {
        BufRead::consume(&mut self.buf, amt)
    }
}

impl<S: Stream> AsyncRead for StreamRead<S> where S::Item: IntoBuf {}

impl<F> Timeout<F> {
    pub fn new(fut: F, dur: Duration) -> Self {
        Timeout {
            tokio: tokio_timer::Timeout::new(fut, dur),
            dur,
        }
    }
}

impl<F: Future> Future for Timeout<F>
where
    F::Error: IntoError,
{
    type Item = F::Item;
    type Error = Error;

    fn poll(&mut self) -> Poll<F::Item, Error> {
        MapErr(&mut self.tokio).poll()
    }
}

impl IntoError for Error {
    fn into_error(self) -> Error {
        self
    }
}

impl IntoError for HyperError {
    fn into_error(self) -> Error {
        Error::Hyper(self)
    }
}

impl<E: IntoError> IntoError for tokio_timer::timeout::Error<E> {
    fn into_error(self) -> Error {
        self.into_inner().map_or(Error::TimedOut, E::into_error)
    }
}

pub fn fmt_join<T: Display>(t: &[T], sep: &str, f: &mut Formatter<'_>) -> fmt::Result {
    let mut iter = t.iter();
    if let Some(t) = iter.next() {
        Display::fmt(t, f)?;
        for t in iter {
            write!(f, "{}{}", sep, t)?;
        }
    }
    Ok(())
}

const COMMA: &str = "%2C";

pub fn fmt_follow(ids: &[u64], f: &mut Formatter<'_>) -> fmt::Result {
    fmt_join(ids, COMMA, f)
}

type Location = ((f64, f64), (f64, f64));

pub fn fmt_locations(locs: &[Location], f: &mut Formatter<'_>) -> fmt::Result {
    use std::mem::size_of;
    use std::slice;

    use static_assertions::const_assert;

    let locs: &[f64] = unsafe {
        let ptr: *const Location = locs.as_ptr();
        const_assert!(size_of::<Location>() % size_of::<f64>() == 0);
        let n = locs.len() * (size_of::<Location>() / size_of::<f64>());
        slice::from_raw_parts(ptr as *const f64, n)
    };

    fmt_join(locs, COMMA, f)
}

#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn not(p: &bool) -> bool {
    !p
}

pub fn timeout<F>(fut: F, dur: Option<Duration>) -> MaybeTimeout<F> {
    use futures::future::Either;

    match dur {
        Some(dur) => Either::A(Timeout::new(fut, dur)),
        None => Either::B(MapErr(fut)),
    }
}

pub fn timeout_to_stream<F, S>(timeout: &MaybeTimeout<F>, s: S) -> MaybeTimeoutStream<S> {
    use futures::future::Either as EitherFut;

    match *timeout {
        EitherFut::A(ref t) => Either::A(MapErr(tokio_timer::Timeout::new(s, t.dur))),
        EitherFut::B(_) => Either::B(MapErr(s)),
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Cursor, Read};

    use bytes::Bytes;
    use futures::stream;

    use super::*;

    const BUF_SIZE: usize = 8 * 1024;

    #[test]
    fn lines() {
        let lines = [
            "abc\r\n",
            "d\r\n",
            "efg\r\n",
            "hijk\r\n",
            "\r\n",
            "lmn\r\n",
            "opq\rrs\r\n",
            "\n\rtuv\r\r\n",
            "wxyz\n",
        ];
        let body = [
            b"abc\r\n" as &[_],
            b"d\r\nefg\r\n" as &[_],
            b"hi" as &[_],
            b"jk" as &[_],
            b"" as &[_],
            b"\r\n" as &[_],
            b"\r\n" as &[_],
            b"lmn\r\nop" as &[_],
            b"q\rrs\r" as &[_],
            b"\n\n\rtuv\r\r\n" as &[_],
            b"wxyz\n" as &[_],
        ];

        let mut iter1 = lines.iter().cloned();
        let mut iter2 = Lines::new(StreamRead::new(stream::iter_ok::<_, ()>(
            body.iter().cloned(),
        )))
        .wait()
        .map(|s| String::from_utf8(s.unwrap().to_vec()).unwrap());

        for _ in 0..(lines.len() + 1) {
            assert_eq!(iter1.next(), iter2.next().as_ref().map(String::as_str));
        }
    }

    #[test]
    fn stream_read() {
        macro_rules! assert_id {
            ($($elm:expr),*) => {{
                let elms = [$(Bytes::from(&$elm[..])),*];
                let mut buf = Vec::new();
                StreamRead {
                    body: stream::iter_ok::<_,()>(
                        elms.iter().cloned().map(Cursor::new)
                    ),
                    buf: Cursor::new(Bytes::new()).reader(),
                    error: None,
                }.read_to_end(&mut buf).unwrap();
                assert_eq!(buf, elms.concat());
            }};
        }
        assert_id!();
        assert_id!([]);
        assert_id!([], [0], [], [], [1, 2]);
        assert_id!([0; BUF_SIZE + 1], [1; BUF_SIZE - 1], [2; BUF_SIZE * 5 / 2]);
    }
}
<|endoftext|>


<commit_before>#![feature(collections)] // for str.escape_default()
extern crate zaldinar_core;

use std::fmt;

use zaldinar_core::client::PluginRegister;
use zaldinar_core::events::CommandEvent;

const MAX_ITERATIONS: u32 = 134217728u32;
const MAX_OUTPUT: usize = 256usize;

#[derive(Debug)]
pub enum Error {
    /// A right bracket was found with no unmatched left brackets preceding it.
    UnbalancedRightBracket,
    /// The input ended before right brackets were found to match all left brackets.
    UnbalancedLeftBracket,
    /// `,` is unsupported
    CommaUnsupported,
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Error::UnbalancedRightBracket => {
                write!(formatter, "Expected matching `[` before `]`, found lone `]` first.")
            },
            &Error::UnbalancedLeftBracket => {
                write!(formatter, "Unbalanced `[`. Expected matching `]`, found end of file.")
            },
            &Error::CommaUnsupported => {
                write!(formatter, "Unsupported command: `,`.")
            }
        }
    }
}

#[derive(Debug)]
enum Instruction {
    /// Increment the memory pointer by one
    MoveRight,
    /// Decrement the memory pointer by one
    MoveLeft,
    /// Increment the memory value at the memory pointer by one
    Increment,
    /// Decrement the memory value at the memory pointer by one
    Decrement,
    /// Output the value of the current memory pointer as a char
    Output,
    /// This is the left side of a loop.
    /// If the memory value at the memory pointer is zero, set the next instruction to the
    /// contained value.
    JumpToLeft(usize),
    /// This is the right side of a loop.
    /// If the memory value at the memory pointer is non-zero, set the next instruction to the
    /// contained value.
    JumpToRight(usize),
}

fn parse_instructions(event: &CommandEvent) -> Result<Vec<Instruction>, Error> {
    // Vec of opening jumps waiting for a closing jump to find
    // each u16 is a position in the instructions vec.
    let mut waiting_opening_jumps = Vec::new();
    let mut instructions = Vec::new();

    for arg in &event.args {
        for c in arg.chars() {
            let instruction = match c {
                '>' => Instruction::MoveRight,
                '<' => Instruction::MoveLeft,
                '+' => Instruction::Increment,
                '-' => Instruction::Decrement,
                '.' => Instruction::Output,
                ',' => {
                    return Err(Error::CommaUnsupported);
                },
                '[' => {
                    // instructions.len() is the position where JumpTo is going to end up
                    waiting_opening_jumps.push(instructions.len());
                    // This is a placeholder, this is guaranteed to be replaced when the
                    // corresponding `]` is found.
                    Instruction::JumpToLeft(0usize)
                },
                ']' => {
                    match waiting_opening_jumps.pop() {
                        Some(left_jump) => {
                            // instructions.len() is the position where the right JumpTo
                            instructions[left_jump] = Instruction::JumpToLeft(instructions.len());
                            Instruction::JumpToRight(left_jump)
                        },
                        None => {
                            return Err(Error::UnbalancedRightBracket);
                        }
                    }
                },
                _ => continue, // treat invalid characters as comments
            };
            instructions.push(instruction);
        }
    }

    if !waiting_opening_jumps.is_empty() {
        return Err(Error::UnbalancedLeftBracket);
    }

    return Ok(instructions);
}

fn brainfuck(event: &CommandEvent) {
    let instructions = match parse_instructions(event) {
        Ok(instructions) => instructions,
        Err(e) => {
            event.client.send_message(event.channel(), format!("Error: {}", e));
            return;
        }
    };

    // Program memory, max size is 2^15
    let mut memory = [0u8; 32768];
    // Current position in memory
    let mut memory_position = 0u16;
    // Next instruction to run
    let mut next_instruction = 0usize;
    // Output string buffer
    let mut output = String::new();
    // Whether or not we finished cleanly (if false, output error for maximum iterations reached)
    let mut done = false;

    // u32::MAX as a limit to the number of iterations to run for a single program.
    for _ in 0..MAX_ITERATIONS {
        if next_instruction >= instructions.len() {
            done = true;
            break;
        }
        match instructions[next_instruction] {
            Instruction::MoveRight => {
                memory_position += 1;
                memory_position %= 32768;
            },
            Instruction::MoveLeft => {
                memory_position -= 1;
                memory_position %= 32768;
            },
            Instruction::Increment => memory[memory_position as usize] += 1,
            Instruction::Decrement => memory[memory_position as usize] -= 1,
            Instruction::Output => {
                output.push(memory[memory_position as usize] as char);

                if output.len() > MAX_OUTPUT {
                    event.client.send_message(event.channel(),
                            "Reached maximum output length. (256)");
                    done = true;
                    break;
                }
            },
            Instruction::JumpToLeft(target_position) => {
                if memory[memory_position as usize] == 0 {
                    next_instruction = target_position;
                    continue; // this avoids the automatic incrementing of next_instruction below.
                }
            },
            Instruction::JumpToRight(target_position) => {
                if memory[memory_position as usize] != 0 {
                    next_instruction = target_position;
                    continue; // this avoids the automatic incrementing of next_instruction below.
                }
            },
        }
        next_instruction += 1;
    }

    if !done {
        event.client.send_message(event.channel(), "Reached maximum iterations. (134217728)");
    }

    if output.is_empty() {
        event.client.send_message(event.channel(), "No output produced.");
    } else {
        event.client.send_message(event.channel(), format!("Output: {}", output.escape_default()));
    }
}

pub fn register(register: &mut PluginRegister) {
    register.register_command("brainfuck", brainfuck);
}
<commit_msg>Replace usage of str.escape_default() in brainfuck.rs with a new escape_output() method which does more of what we actually need.<commit_after>extern crate zaldinar_core;

use std::fmt;

use zaldinar_core::client::PluginRegister;
use zaldinar_core::events::CommandEvent;

const MAX_ITERATIONS: u32 = 134217728u32;
const MAX_OUTPUT: usize = 256usize;

#[derive(Debug)]
pub enum Error {
    /// A right bracket was found with no unmatched left brackets preceding it.
    UnbalancedRightBracket,
    /// The input ended before right brackets were found to match all left brackets.
    UnbalancedLeftBracket,
    /// `,` is unsupported
    CommaUnsupported,
}

impl fmt::Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Error::UnbalancedRightBracket => {
                write!(formatter, "Expected matching `[` before `]`, found lone `]` first.")
            },
            &Error::UnbalancedLeftBracket => {
                write!(formatter, "Unbalanced `[`. Expected matching `]`, found end of file.")
            },
            &Error::CommaUnsupported => {
                write!(formatter, "Unsupported command: `,`.")
            }
        }
    }
}

#[derive(Debug)]
enum Instruction {
    /// Increment the memory pointer by one
    MoveRight,
    /// Decrement the memory pointer by one
    MoveLeft,
    /// Increment the memory value at the memory pointer by one
    Increment,
    /// Decrement the memory value at the memory pointer by one
    Decrement,
    /// Output the value of the current memory pointer as a char
    Output,
    /// This is the left side of a loop.
    /// If the memory value at the memory pointer is zero, set the next instruction to the
    /// contained value.
    JumpToLeft(usize),
    /// This is the right side of a loop.
    /// If the memory value at the memory pointer is non-zero, set the next instruction to the
    /// contained value.
    JumpToRight(usize),
}

fn parse_instructions(event: &CommandEvent) -> Result<Vec<Instruction>, Error> {
    // Vec of opening jumps waiting for a closing jump to find
    // each u16 is a position in the instructions vec.
    let mut waiting_opening_jumps = Vec::new();
    let mut instructions = Vec::new();

    for arg in &event.args {
        for c in arg.chars() {
            let instruction = match c {
                '>' => Instruction::MoveRight,
                '<' => Instruction::MoveLeft,
                '+' => Instruction::Increment,
                '-' => Instruction::Decrement,
                '.' => Instruction::Output,
                ',' => {
                    return Err(Error::CommaUnsupported);
                },
                '[' => {
                    // instructions.len() is the position where JumpTo is going to end up
                    waiting_opening_jumps.push(instructions.len());
                    // This is a placeholder, this is guaranteed to be replaced when the
                    // corresponding `]` is found.
                    Instruction::JumpToLeft(0usize)
                },
                ']' => {
                    match waiting_opening_jumps.pop() {
                        Some(left_jump) => {
                            // instructions.len() is the position where the right JumpTo
                            instructions[left_jump] = Instruction::JumpToLeft(instructions.len());
                            Instruction::JumpToRight(left_jump)
                        },
                        None => {
                            return Err(Error::UnbalancedRightBracket);
                        }
                    }
                },
                _ => continue, // treat invalid characters as comments
            };
            instructions.push(instruction);
        }
    }

    if !waiting_opening_jumps.is_empty() {
        return Err(Error::UnbalancedLeftBracket);
    }

    return Ok(instructions);
}

fn brainfuck(event: &CommandEvent) {
    let instructions = match parse_instructions(event) {
        Ok(instructions) => instructions,
        Err(e) => {
            event.client.send_message(event.channel(), format!("Error: {}", e));
            return;
        }
    };

    // Program memory, max size is 2^15
    let mut memory = [0u8; 32768];
    // Current position in memory
    let mut memory_position = 0u16;
    // Next instruction to run
    let mut next_instruction = 0usize;
    // Output string buffer
    let mut output = String::new();
    // Whether or not we finished cleanly (if false, output error for maximum iterations reached)
    let mut done = false;

    // u32::MAX as a limit to the number of iterations to run for a single program.
    for _ in 0..MAX_ITERATIONS {
        if next_instruction >= instructions.len() {
            done = true;
            break;
        }
        match instructions[next_instruction] {
            Instruction::MoveRight => {
                memory_position += 1;
                memory_position %= 32768;
            },
            Instruction::MoveLeft => {
                memory_position -= 1;
                memory_position %= 32768;
            },
            Instruction::Increment => memory[memory_position as usize] += 1,
            Instruction::Decrement => memory[memory_position as usize] -= 1,
            Instruction::Output => {
                output.push(memory[memory_position as usize] as char);

                if output.len() > MAX_OUTPUT {
                    event.client.send_message(event.channel(),
                            "Reached maximum output length. (256)");
                    done = true;
                    break;
                }
            },
            Instruction::JumpToLeft(target_position) => {
                if memory[memory_position as usize] == 0 {
                    next_instruction = target_position;
                    continue; // this avoids the automatic incrementing of next_instruction below.
                }
            },
            Instruction::JumpToRight(target_position) => {
                if memory[memory_position as usize] != 0 {
                    next_instruction = target_position;
                    continue; // this avoids the automatic incrementing of next_instruction below.
                }
            },
        }
        next_instruction += 1;
    }

    if !done {
        event.client.send_message(event.channel(), "Reached maximum iterations. (134217728)");
    }

    if output.is_empty() {
        event.client.send_message(event.channel(), "No output produced.");
    } else {
        event.client.send_message(event.channel(), format!("Output: {}", escape_output(&output)));
    }
}

pub fn register(register: &mut PluginRegister) {
    register.register_command("brainfuck", brainfuck);
}

fn escape_output(input: &str) -> String {
    let mut result = String::with_capacity(input.len());

    for c in input.chars() {
        match c {
           '\t' => result.push_str("\\t"),
            '\r' => result.push_str("\\r"),
            '\n' => result.push_str("\\n"),
            '\\' => result.push_str("\\\\"),
            v @ '\x20' ... '\x7e' => result.push(v),
            v @ _ => result.extend(v.escape_unicode()),
        }
    }

    return result;
}
<|endoftext|>


<commit_before>//! A module providing an enum for a message prefix.
use std::string;
use std::str::FromStr;
use std::fmt;

/// The Prefix indicates "the true origin of the message", according to the server.
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Prefix {
    /// servername, e.g. collins.mozilla.org
    ServerName(String),
    /// nickname [ ["!" username] "@" hostname ]
    /// i.e. Nickname(nickname, username, hostname)
    /// Any of the strings may be ""
    Nickname(String, String, String),
}

impl Prefix {
    /// Creates a prefix by parsing a string.
    ///
    /// # Example
    /// ```
    /// # extern crate irc;
    /// # use irc::client::prelude::*;
    /// # fn main() {
    /// Prefix::new_from_str("nickname!username@hostname");
    /// Prefix::new_from_str("example.com");
    /// # }
    /// ```
    pub fn new_from_str(s: &str) -> Prefix {
        #[derive(Copy, Clone, Eq, PartialEq)]
        enum Active {
            Name,
            User,
            Host,
        }

        let mut name = String::new();
        let mut user = String::new();
        let mut host = String::new();
        let mut active = Active::Name;
        let mut is_server = false;

        for c in s.chars() {
            if c == '.' {
                // We won't return Nickname("nick", "", "") but if @ or ! are
                // encountered, then we set this back to false
                is_server = true;
            }

            match c {
                '!' if active == Active::Name => {
                    is_server = false;
                    active = Active::User;
                },

                '@' if active != Active::Host => {
                    is_server = false;
                    active = Active::Host;
                },

                _ => {
                    // Push onto the active buffer
                    match active {
                        Active::Name => &mut name,
                        Active::User => &mut user,
                        Active::Host => &mut host,
                    }.push(c)
                }
            }
        }

        if is_server {
            Prefix::ServerName(name)
        } else {
            Prefix::Nickname(name, user, host)
        }
    }
}

/// This implementation never returns an error and is isomorphic with `Display`.
impl FromStr for Prefix {
    type Err = string::ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Prefix::new_from_str(s))
    }
}

/// This is isomorphic with `FromStr`
impl fmt::Display for Prefix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Prefix::ServerName(name) => write!(f, "{}", name),
            Prefix::Nickname(name, user, host) => match (&name[..], &user[..], &host[..]) {
                ("", "", "") => write!(f, ""),
                (name, "", "") => write!(f, "{}", name),
                (name, user, "") => write!(f, "{}!{}", name, user),
                (name, "", host) => write!(f, "{}@{}", name, host),
                (name, user, host) => write!(f, "{}!{}@{}", name, user, host),
            },
        }
    }
}

impl<'a> From<&'a str> for Prefix {
    fn from(s: &str) -> Self {
        Prefix::new_from_str(s)
    }
}

#[cfg(test)]
mod test {
    use super::Prefix::{self, ServerName, Nickname};

    // Checks that str -> parsed -> Display doesn't lose data
    fn test_parse(s: &str) -> Prefix {
        let prefix = Prefix::new_from_str(s);
        let s2 = format!("{}", prefix);
        assert_eq!(s, &s2);
        prefix
    }

    #[test]
    fn print() {
        let s = format!("{}", Nickname("nick".into(), "".into(), "".into()));
        assert_eq!(&s, "nick");
        let s = format!("{}", Nickname("nick".into(), "user".into(), "".into()));
        assert_eq!(&s, "nick!user");
        let s = format!("{}", Nickname("nick".into(), "user".into(), "host".into()));
        assert_eq!(&s, "nick!user@host");
    }

    #[test]
    fn parse_word() {
        assert_eq!(
            test_parse("only_nick"),
            Nickname("only_nick".into(), String::new(), String::new())
        )
    }

    #[test]
    fn parse_host() {
        assert_eq!(
            test_parse("host.tld"),
            ServerName("host.tld".into())
        )
    }

    #[test]
    fn parse_nick_user() {
        assert_eq!(
            test_parse("test!nick"),
            Nickname("test".into(), "nick".into(), String::new())
        )
    }

    #[test]
    fn parse_nick_user_host() {
        assert_eq!(
            test_parse("test!nick@host"),
            Nickname("test".into(), "nick".into(), "host".into())
        )
    }

    #[test]
    fn parse_dot_and_symbols() {
        assert_eq!(
            test_parse("test.net@something"),
            ServerName("test.net@something".into())
        )
    }

    #[test]
    fn parse_danger_cases() {
        assert_eq!(
            test_parse("name@name!user"),
            Nickname("name@name".into(), "user".into(), String::new())
        );
        assert_eq!(
            test_parse("name!@"),
            Nickname("name".into(), "".into(), "".into())
        );
        assert_eq!(
            test_parse("name!@hostname"),
            Nickname("name".into(), "".into(), "hostname".into())
        );
        assert_eq!(
            test_parse("name!.user"),
            Nickname("name".into(), ".user".into(), String::new())
        );
        assert_eq!(
            test_parse("name!user.user"),
            Nickname("name".into(), "user.user".into(), String::new())
        );
        assert_eq!(
            test_parse("name!user@host.host"),
            Nickname("name".into(), "user".into(), "host.host".into())
        );
        assert_eq!(
            test_parse("!user"),
            Nickname("".into(), "user".into(), String::new())
        );
        assert_eq!(
            test_parse("!@host.host"),
            Nickname("".into(), "".into(), "host.host".into())
        );
    }
}
<commit_msg>fixes issues from review<commit_after>//! A module providing an enum for a message prefix.
use std::string;
use std::str::FromStr;
use std::fmt;

/// The Prefix indicates "the true origin of the message", according to the server.
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Prefix {
    /// servername, e.g. collins.mozilla.org
    ServerName(String),
    /// nickname [ ["!" username] "@" hostname ]
    /// i.e. Nickname(nickname, username, hostname)
    /// Any of the strings may be ""
    Nickname(String, String, String),
}

impl Prefix {
    /// Creates a prefix by parsing a string.
    ///
    /// # Example
    /// ```
    /// # extern crate irc_proto;
    /// # use irc_proto::Prefix;
    /// # fn main() {
    /// Prefix::new_from_str("nickname!username@hostname");
    /// Prefix::new_from_str("example.com");
    /// # }
    /// ```
    pub fn new_from_str(s: &str) -> Prefix {
        #[derive(Copy, Clone, Eq, PartialEq)]
        enum Active {
            Name,
            User,
            Host,
        }

        let mut name = String::new();
        let mut user = String::new();
        let mut host = String::new();
        let mut active = Active::Name;
        let mut is_server = false;

        for c in s.chars() {
            if c == '.' && active == Active::Name {
                // We won't return Nickname("nick", "", "") but if @ or ! are
                // encountered, then we set this back to false
                is_server = true;
            }

            match c {
                '!' if active == Active::Name => {
                    is_server = false;
                    active = Active::User;
                },

                '@' if active != Active::Host => {
                    is_server = false;
                    active = Active::Host;
                },

                _ => {
                    // Push onto the active buffer
                    match active {
                        Active::Name => &mut name,
                        Active::User => &mut user,
                        Active::Host => &mut host,
                    }.push(c)
                }
            }
        }

        if is_server {
            Prefix::ServerName(name)
        } else {
            Prefix::Nickname(name, user, host)
        }
    }
}

/// This implementation never returns an error and is isomorphic with `Display`.
impl FromStr for Prefix {
    type Err = string::ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Prefix::new_from_str(s))
    }
}

/// This is isomorphic with `FromStr`
impl fmt::Display for Prefix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Prefix::ServerName(name) => write!(f, "{}", name),
            Prefix::Nickname(name, user, host) => match (&name[..], &user[..], &host[..]) {
                ("", "", "") => write!(f, ""),
                (name, "", "") => write!(f, "{}", name),
                (name, user, "") => write!(f, "{}!{}", name, user),
                (name, "", host) => write!(f, "{}@{}", name, host),
                (name, user, host) => write!(f, "{}!{}@{}", name, user, host),
            },
        }
    }
}

impl<'a> From<&'a str> for Prefix {
    fn from(s: &str) -> Self {
        Prefix::new_from_str(s)
    }
}

#[cfg(test)]
mod test {
    use super::Prefix::{self, ServerName, Nickname};

    // Checks that str -> parsed -> Display doesn't lose data
    fn test_parse(s: &str) -> Prefix {
        let prefix = Prefix::new_from_str(s);
        let s2 = format!("{}", prefix);
        assert_eq!(s, &s2);
        prefix
    }

    #[test]
    fn print() {
        let s = format!("{}", Nickname("nick".into(), "".into(), "".into()));
        assert_eq!(&s, "nick");
        let s = format!("{}", Nickname("nick".into(), "user".into(), "".into()));
        assert_eq!(&s, "nick!user");
        let s = format!("{}", Nickname("nick".into(), "user".into(), "host".into()));
        assert_eq!(&s, "nick!user@host");
    }

    #[test]
    fn parse_word() {
        assert_eq!(
            test_parse("only_nick"),
            Nickname("only_nick".into(), String::new(), String::new())
        )
    }

    #[test]
    fn parse_host() {
        assert_eq!(
            test_parse("host.tld"),
            ServerName("host.tld".into())
        )
    }

    #[test]
    fn parse_nick_user() {
        assert_eq!(
            test_parse("test!nick"),
            Nickname("test".into(), "nick".into(), String::new())
        )
    }

    #[test]
    fn parse_nick_user_host() {
        assert_eq!(
            test_parse("test!nick@host"),
            Nickname("test".into(), "nick".into(), "host".into())
        )
    }

    #[test]
    fn parse_dot_and_symbols() {
        assert_eq!(
            test_parse("test.net@something"),
            Nickname("test.net".into(), "".into(), "something".into())
        )
    }

    #[test]
    fn parse_danger_cases() {
        assert_eq!(
            test_parse("name@name!user"),
            Nickname("name".into(), "".into(), "name!user".into())
        );
        assert_eq!(
            // can't reverse the parse
            "name!@".parse::<Prefix>().unwrap(),
            Nickname("name".into(), "".into(), "".into())
        );
        assert_eq!(
            // can't reverse the parse
            "name!@hostname".parse::<Prefix>().unwrap(),
            Nickname("name".into(), "".into(), "hostname".into())
        );
        assert_eq!(
            test_parse("name!.user"),
            Nickname("name".into(), ".user".into(), "".into())
        );
        assert_eq!(
            test_parse("name!user.user"),
            Nickname("name".into(), "user.user".into(), "".into())
        );
        assert_eq!(
            test_parse("name!user@host.host"),
            Nickname("name".into(), "user".into(), "host.host".into())
        );
        assert_eq!(
            test_parse("!user"),
            Nickname("".into(), "user".into(), "".into())
        );
        assert_eq!(
            "!@host.host".parse::<Prefix>().unwrap(),
            Nickname("".into(), "".into(), "host.host".into())
        );
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use collections::vec::Vec;

use common::memory;

use disk::Disk;

use drivers::pciconfig::PciConfig;

use schemes::Result;

use self::hba::{HbaMem, HbaPort, HbaPortType};

pub mod fis;
pub mod hba;

pub struct Ahci;

impl Ahci {
    pub fn disks(mut pci: PciConfig) -> Vec<Box<Disk>> {
        let mut ret: Vec<Box<Disk>> = Vec::new();

        let base = unsafe { (pci.read(0x24) & 0xFFFFFFF0) as usize };
        let irq = unsafe { (pci.read(0x3C) & 0xF) as u8 };

        debugln!("AHCI on: {:X} IRQ: {:X}", base as usize, irq);

        let pi = unsafe { &mut * (base as *mut HbaMem) }.pi.read();

        for i in 0..32 {
            if pi & 1 << i == 1 << i {
                let mut disk = box AhciDisk {
                    port: &mut unsafe { &mut * (base as *mut HbaMem) }.ports[i]
                };

                let port_type = disk.port.probe();
                debugln!("Port {}: {:?}", i, port_type);
                match port_type {
                    HbaPortType::SATA => {
                        disk.port.init();
                        ret.push(disk);
                    },
                    _ => ()
                }
            }
        }

        ret
    }
}

pub struct AhciDisk {
    port: &'static mut HbaPort
}

impl Disk for AhciDisk {
    fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
        self.port.ata_dma(block, buffer.len()/512, buffer.as_ptr() as usize, false)
    }

    fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
        self.port.ata_dma(block, buffer.len()/512, buffer.as_ptr() as usize, true)
    }
}
<commit_msg>Add private constructor for `AhciDisk`<commit_after>use alloc::boxed::Box;

use collections::vec::Vec;

use common::memory;

use disk::Disk;

use drivers::pciconfig::PciConfig;

use schemes::Result;

use self::hba::{HbaMem, HbaPort, HbaPortType};

pub mod fis;
pub mod hba;

pub struct Ahci;

impl Ahci {
    pub fn disks(mut pci: PciConfig) -> Vec<Box<Disk>> {
        let mut ret: Vec<Box<Disk>> = Vec::new();

        let base = unsafe { (pci.read(0x24) & 0xFFFFFFF0) as usize };
        let irq = unsafe { (pci.read(0x3C) & 0xF) as u8 };

        debugln!("AHCI on: {:X} IRQ: {:X}", base as usize, irq);

        let pi = unsafe { &mut * (base as *mut HbaMem) }.pi.read();

        for i in 0..32 {
            if pi & 1 << i == 1 << i {
                let mut disk = box AhciDisk::new(base, i);
                let port_type = disk.port.probe();
                debugln!("Port {}: {:?}", i, port_type);
                match port_type {
                    HbaPortType::SATA => {
                        disk.port.init();
                        ret.push(disk);
                    },
                    _ => ()
                }
            }
        }

        ret
    }
}

pub struct AhciDisk {
    port: &'static mut HbaPort
}

impl AhciDisk {
    fn new(base: usize, port_index: usize) -> Self {
        AhciDisk {
            port: &mut unsafe { &mut * (base as *mut HbaMem) }.ports[port_index]
        }
    }
}

impl Disk for AhciDisk {
    fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
        self.port.ata_dma(block, buffer.len()/512, buffer.as_ptr() as usize, false)
    }

    fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
        self.port.ata_dma(block, buffer.len()/512, buffer.as_ptr() as usize, true)
    }
}
<|endoftext|>


<commit_before>#![feature(never_type)]
use std::mem::transmute;

fn main() { unsafe {
    let _x: &! = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type !
} }
<commit_msg>change one of the ref-to-uninhbaited tests to Box<commit_after>#![feature(never_type)]
use std::mem::{transmute, forget};

fn main() { unsafe {
    let x: Box<!> = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type !
    forget(x);
} }
<|endoftext|>