<commit_before>use buffer::{Buffer, Direction, Mark};
use input::Input;
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer,     //Text buffer
    top_line: Mark,         //First character of the top line to be displayed.
    left_col: uint,         //Index into the top line to set the left column to.
    cursor: Mark,           //Cursor displayed by this buffer.
    uibuf: UIBuffer,        //UIBuffer
}

impl<'v> View<'v> {

    //----- CONSTRUCTORS ---------------------------------------------------------------------------

    pub fn new(source: Input, width: uint, height: uint) -> View<'v> {
        let mut buffer = match source {
            Input::Filename(path) => {
                match path {
                    Some(s) => Buffer::new_from_file(Path::new(s)),
                    None    => Buffer::new(),
                }
            },
            Input::Stdin(reader) => {
                Buffer::new_from_reader(reader)
            },
        };

        // NOTE(greg): this may not play well with resizing
        let uibuf = UIBuffer::new(width, height);

        let cursor = Mark::Cursor(0);
        buffer.set_mark(cursor, 0);
        let top_line = Mark::DisplayMark(0);
        buffer.set_mark(top_line, 0);

        View {
            buffer: buffer,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: uibuf,
        }
    }

    pub fn get_height(&self) -> uint {
        // NOTE(greg): when the status bar needs to move up, this value should be changed
        self.uibuf.get_height() -1
    }

    pub fn get_width(&self) -> uint {
        self.uibuf.get_width()
    }

    //----- DRAWING METHODS ------------------------------------------------------------------------
    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear<T: Frontend>(&mut self, frontend: &mut T) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        for (index,line) in self.buffer
                                .lines_from(self.top_line)
                                .unwrap()
                                .take(self.get_height())
                                .enumerate() {
            draw_line(&mut self.uibuf, line, index, self.left_col);
            if index == self.get_height() { break; }
        }
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer_status = self.buffer.status_text();
        let mut cursor_status = self.buffer.get_mark_coords(self.cursor).unwrap_or((0,0));
        cursor_status = (cursor_status.0 + 1, cursor_status.1 + 1);
        let status_text = format!("{} {}", buffer_status, cursor_status).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height();

        for index in range(0, width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, CharColor::Black, CharColor::Blue);
        }

        self.uibuf.draw_range(frontend, height, height+1);
    }

    pub fn draw_cursor<T: Frontend>(&mut self, frontend: &mut T) {
        if let Some(top_line) = self.buffer.get_mark_coords(self.top_line) {
            if let Some((x, y)) = self.buffer.get_mark_coords(self.cursor) {
                frontend.draw_cursor(x as int, y as int - top_line.1 as int);
            }
        }
    }

    pub fn resize<T: Frontend>(&mut self, frontend: &mut T) {
        let width = self.uibuf.get_width();
        self.clear(frontend);
        self.uibuf = UIBuffer::new(width, 15);
    }

    //----- CURSOR METHODS -------------------------------------------------------------------------

    pub fn move_cursor(&mut self, direction: Direction) {
        self.buffer.shift_mark(self.cursor, direction);
        self.move_screen();
    }

    pub fn move_cursor_to_line_end(&mut self) {
        self.buffer.shift_mark(self.cursor, Direction::LineEnd);
        self.move_screen();
    }

    pub fn move_cursor_to_line_start(&mut self) {
        self.buffer.shift_mark(self.cursor, Direction::LineStart);
        self.move_screen();
    }

    //Update the top_line mark if necessary to keep the cursor on the screen.
    fn move_screen(&mut self) {
        if let (Some(cursor), Some(top_line)) = (self.buffer.get_mark_coords(self.cursor),
                                                 self.buffer.get_mark_coords(self.top_line)) {
            // FIXME
            // match cursor.0 as int - self.left_col as int {
            //     x if x < 0 => { self.left_col -= x as uint; }
            //     x if x > self.get_width() as int => { self.left_col += x as uint - self.get_width()}
            //     _ => { }
            // }

            let cursor_linenum = cursor.1 as int;
            let cursor_offset = cursor_linenum - top_line.1 as int;
            let height = self.get_height() as int;

            if cursor_offset >= (height - 5) {
                // moving down
                let times = cursor_offset - (height - 5) + 1;
                self.buffer.shift_mark(self.top_line, Direction::Down(times as uint));
            } else if cursor_offset < 5 {
                // moving up
                self.buffer.shift_mark(self.top_line, Direction::Up(1));
            }
        }
    }

    //----- TEXT EDIT METHODS ----------------------------------------------------------------------

    pub fn delete_char(&mut self, direction: Direction) {
        match direction {
            Direction::Left(1) if self.buffer.get_mark_idx(self.cursor) != Some(0) => {
                self.move_cursor(direction);
                self.buffer.remove_char(self.cursor);
            }
            Direction::Right(1) if self.buffer.get_mark_idx(self.cursor) != Some(self.buffer.len()) => {
                self.buffer.remove_char(self.cursor);
            }
            _ => {}
        }
    }

    pub fn insert_tab(&mut self) {
        // A tab is just 4 spaces
        for _ in range(0i, 4) {
            self.insert_char(' ');
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.buffer.insert_char(self.cursor, ch as u8);
        self.move_cursor(Direction::Right(1))
    }

    pub fn undo(&mut self) {
        let point = if let Some(transaction) = self.buffer.undo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
    }

    pub fn redo(&mut self) {
        let point = if let Some(transaction) = self.buffer.redo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: uint, left: uint) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in range(left, left + width) {
        if line_idx < line.len() {
            match line[line_idx] {
                b'\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in range(0, w) {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                b'\n'   => buf.update_cell_content(line_idx + wide_chars - left, idx, ' '),
                _       => buf.update_cell_content(line_idx + wide_chars - left, idx,
                                                   line[line_idx] as char),
            }
            wide_chars += (line[line_idx] as char).width(false).unwrap_or(1) - 1;
        } else { buf.update_cell_content(line_idx + wide_chars - left, idx, ' '); }
    }
    if line.len() >= width {
        buf.update_cell_content(width + wide_chars, idx, '→');
    }

}

#[cfg(test)]
mod tests {

    use buffer::Direction;
    use view::View;
    use input::Input;

    fn setup_view<'v>(testcase: &'static str) -> View<'v> {
        let mut view = View::new(Input::Filename(None), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }
        view.buffer.set_mark(view.cursor, 0);
        view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap().1, 1);
        assert_eq!(view.buffer.lines_from(view.cursor).unwrap().next().unwrap(), b"second"[]);
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        view.move_cursor(Direction::Up(1));
        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap().1, 0);
        assert_eq!(view.buffer.lines_from(view.cursor).unwrap().next().unwrap(), b"test\n"[]);
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(1));
        view.insert_char('\n');

        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap(), (0, 1))
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        assert_eq!(view.buffer.lines().next().unwrap(), b"ttest\n"[]);
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view("test\nsecond");
        view.delete_char(Direction::Right(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"est\n"[]);
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(1));
        view.delete_char(Direction::Left(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"est\n"[]);
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        view.delete_char(Direction::Left(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"testsecond"[]);
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(4));
        view.delete_char(Direction::Right(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"testsecond"[]);
    }

    #[test]
    fn deleting_backward_at_start_of_first_line_does_nothing() {
        let mut view = setup_view("test\nsecond");
        view.delete_char(Direction::Left(1));

        let lines: Vec<&[u8]> = view.buffer.lines().collect();

        assert_eq!(lines.len(), 2);
        assert_eq!(view.buffer.lines().next().unwrap(), b"test\n");
    }
}
<commit_msg>Move screen when undo & redo occur.<commit_after>use buffer::{Buffer, Direction, Mark};
use input::Input;
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer,     //Text buffer
    top_line: Mark,         //First character of the top line to be displayed.
    left_col: uint,         //Index into the top line to set the left column to.
    cursor: Mark,           //Cursor displayed by this buffer.
    uibuf: UIBuffer,        //UIBuffer
}

impl<'v> View<'v> {

    //----- CONSTRUCTORS ---------------------------------------------------------------------------

    pub fn new(source: Input, width: uint, height: uint) -> View<'v> {
        let mut buffer = match source {
            Input::Filename(path) => {
                match path {
                    Some(s) => Buffer::new_from_file(Path::new(s)),
                    None    => Buffer::new(),
                }
            },
            Input::Stdin(reader) => {
                Buffer::new_from_reader(reader)
            },
        };

        // NOTE(greg): this may not play well with resizing
        let uibuf = UIBuffer::new(width, height);

        let cursor = Mark::Cursor(0);
        buffer.set_mark(cursor, 0);
        let top_line = Mark::DisplayMark(0);
        buffer.set_mark(top_line, 0);

        View {
            buffer: buffer,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: uibuf,
        }
    }

    pub fn get_height(&self) -> uint {
        // NOTE(greg): when the status bar needs to move up, this value should be changed
        self.uibuf.get_height() -1
    }

    pub fn get_width(&self) -> uint {
        self.uibuf.get_width()
    }

    //----- DRAWING METHODS ------------------------------------------------------------------------
    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear<T: Frontend>(&mut self, frontend: &mut T) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        for (index,line) in self.buffer
                                .lines_from(self.top_line)
                                .unwrap()
                                .take(self.get_height())
                                .enumerate() {
            draw_line(&mut self.uibuf, line, index, self.left_col);
            if index == self.get_height() { break; }
        }
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer_status = self.buffer.status_text();
        let mut cursor_status = self.buffer.get_mark_coords(self.cursor).unwrap_or((0,0));
        cursor_status = (cursor_status.0 + 1, cursor_status.1 + 1);
        let status_text = format!("{} {}", buffer_status, cursor_status).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height();

        for index in range(0, width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, CharColor::Black, CharColor::Blue);
        }

        self.uibuf.draw_range(frontend, height, height+1);
    }

    pub fn draw_cursor<T: Frontend>(&mut self, frontend: &mut T) {
        if let Some(top_line) = self.buffer.get_mark_coords(self.top_line) {
            if let Some((x, y)) = self.buffer.get_mark_coords(self.cursor) {
                frontend.draw_cursor(x as int, y as int - top_line.1 as int);
            }
        }
    }

    pub fn resize<T: Frontend>(&mut self, frontend: &mut T) {
        let width = self.uibuf.get_width();
        self.clear(frontend);
        self.uibuf = UIBuffer::new(width, 15);
    }

    //----- CURSOR METHODS -------------------------------------------------------------------------

    pub fn move_cursor(&mut self, direction: Direction) {
        self.buffer.shift_mark(self.cursor, direction);
        self.move_screen();
    }

    pub fn move_cursor_to_line_end(&mut self) {
        self.buffer.shift_mark(self.cursor, Direction::LineEnd);
        self.move_screen();
    }

    pub fn move_cursor_to_line_start(&mut self) {
        self.buffer.shift_mark(self.cursor, Direction::LineStart);
        self.move_screen();
    }

    //Update the top_line mark if necessary to keep the cursor on the screen.
    fn move_screen(&mut self) {
        if let (Some(cursor), Some(top_line)) = (self.buffer.get_mark_coords(self.cursor),
                                                 self.buffer.get_mark_coords(self.top_line)) {
            // FIXME
            // match cursor.0 as int - self.left_col as int {
            //     x if x < 0 => { self.left_col -= x as uint; }
            //     x if x > self.get_width() as int => { self.left_col += x as uint - self.get_width()}
            //     _ => { }
            // }

            let cursor_linenum = cursor.1 as int;
            let cursor_offset = cursor_linenum - top_line.1 as int;
            let height = self.get_height() as int;

            if cursor_offset >= (height - 5) {
                // moving down
                let times = cursor_offset - (height - 5) + 1;
                self.buffer.shift_mark(self.top_line, Direction::Down(times as uint));
            } else if cursor_offset < 5 {
                // moving up
                self.buffer.shift_mark(self.top_line, Direction::Up(1));
            }
        }
    }

    //----- TEXT EDIT METHODS ----------------------------------------------------------------------

    pub fn delete_char(&mut self, direction: Direction) {
        match direction {
            Direction::Left(1) if self.buffer.get_mark_idx(self.cursor) != Some(0) => {
                self.move_cursor(direction);
                self.buffer.remove_char(self.cursor);
            }
            Direction::Right(1) if self.buffer.get_mark_idx(self.cursor) != Some(self.buffer.len()) => {
                self.buffer.remove_char(self.cursor);
            }
            _ => {}
        }
    }

    pub fn insert_tab(&mut self) {
        // A tab is just 4 spaces
        for _ in range(0i, 4) {
            self.insert_char(' ');
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.buffer.insert_char(self.cursor, ch as u8);
        self.move_cursor(Direction::Right(1))
    }

    pub fn undo(&mut self) {
        let point = if let Some(transaction) = self.buffer.undo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.move_screen();
    }

    pub fn redo(&mut self) {
        let point = if let Some(transaction) = self.buffer.redo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.move_screen();
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: uint, left: uint) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in range(left, left + width) {
        if line_idx < line.len() {
            match line[line_idx] {
                b'\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in range(0, w) {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                b'\n'   => buf.update_cell_content(line_idx + wide_chars - left, idx, ' '),
                _       => buf.update_cell_content(line_idx + wide_chars - left, idx,
                                                   line[line_idx] as char),
            }
            wide_chars += (line[line_idx] as char).width(false).unwrap_or(1) - 1;
        } else { buf.update_cell_content(line_idx + wide_chars - left, idx, ' '); }
    }
    if line.len() >= width {
        buf.update_cell_content(width + wide_chars, idx, '→');
    }

}

#[cfg(test)]
mod tests {

    use buffer::Direction;
    use view::View;
    use input::Input;

    fn setup_view<'v>(testcase: &'static str) -> View<'v> {
        let mut view = View::new(Input::Filename(None), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }
        view.buffer.set_mark(view.cursor, 0);
        view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap().1, 1);
        assert_eq!(view.buffer.lines_from(view.cursor).unwrap().next().unwrap(), b"second"[]);
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        view.move_cursor(Direction::Up(1));
        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap().1, 0);
        assert_eq!(view.buffer.lines_from(view.cursor).unwrap().next().unwrap(), b"test\n"[]);
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(1));
        view.insert_char('\n');

        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap(), (0, 1))
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        assert_eq!(view.buffer.lines().next().unwrap(), b"ttest\n"[]);
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view("test\nsecond");
        view.delete_char(Direction::Right(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"est\n"[]);
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(1));
        view.delete_char(Direction::Left(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"est\n"[]);
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        view.delete_char(Direction::Left(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"testsecond"[]);
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(4));
        view.delete_char(Direction::Right(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"testsecond"[]);
    }

    #[test]
    fn deleting_backward_at_start_of_first_line_does_nothing() {
        let mut view = setup_view("test\nsecond");
        view.delete_char(Direction::Left(1));

        let lines: Vec<&[u8]> = view.buffer.lines().collect();

        assert_eq!(lines.len(), 2);
        assert_eq!(view.buffer.lines().next().unwrap(), b"test\n");
    }
}
<|endoftext|>


<commit_before>extern crate gcc;
extern crate pkg_config;

use std::path::Path;

fn main() {
    let root = std::env::var("CARGO_MANIFEST_DIR").unwrap();
    let root = Path::new(&root).join("libvorbis");

    println!(
        "cargo:include={}",
        root.join("include").into_os_string().into_string().unwrap()
    );
    println!(
        "cargo:src={}",
        root.join("lib").into_os_string().into_string().unwrap()
    );

    match pkg_config::find_library("vorbis") {
        Ok(_) => return,
        Err(..) => {}
    };

    let ogg_inc = std::env::var("DEP_OGG_INCLUDE").unwrap();
    let ogg_inc = Path::new(&ogg_inc);

    gcc::Config::new()
        .file("libvorbis/lib/analysis.c")
        .file("libvorbis/lib/bitrate.c")
        .file("libvorbis/lib/block.c")
        .file("libvorbis/lib/codebook.c")
        .file("libvorbis/lib/envelope.c")
        .file("libvorbis/lib/floor0.c")
        .file("libvorbis/lib/floor1.c")
        .file("libvorbis/lib/info.c")
        .file("libvorbis/lib/lookup.c")
        .file("libvorbis/lib/lpc.c")
        .file("libvorbis/lib/lsp.c")
        .file("libvorbis/lib/mapping0.c")
        .file("libvorbis/lib/mdct.c")
        .file("libvorbis/lib/misc.c")
        .file("libvorbis/lib/psy.c")
        .file("libvorbis/lib/registry.c")
        .file("libvorbis/lib/res0.c")
        .file("libvorbis/lib/sharedbook.c")
        .file("libvorbis/lib/smallft.c")
        .file("libvorbis/lib/synthesis.c")
        .file("libvorbis/lib/vorbisenc.c")
        .file("libvorbis/lib/window.c")
        .define("_USRDLL", None)
        .define("LIBVORBIS_EXPORTS", None)
        .include(&root.join("include"))
        .include(&root.join("lib"))
        .include(&ogg_inc)
        .compile("libvorbis.a");
}
<commit_msg>Remove misc.c from sources<commit_after>extern crate gcc;
extern crate pkg_config;

use std::path::Path;

fn main() {
    let root = std::env::var("CARGO_MANIFEST_DIR").unwrap();
    let root = Path::new(&root).join("libvorbis");

    println!(
        "cargo:include={}",
        root.join("include").into_os_string().into_string().unwrap()
    );
    println!(
        "cargo:src={}",
        root.join("lib").into_os_string().into_string().unwrap()
    );

    match pkg_config::find_library("vorbis") {
        Ok(_) => return,
        Err(..) => {}
    };

    let ogg_inc = std::env::var("DEP_OGG_INCLUDE").unwrap();
    let ogg_inc = Path::new(&ogg_inc);

    gcc::Config::new()
        .file("libvorbis/lib/analysis.c")
        .file("libvorbis/lib/bitrate.c")
        .file("libvorbis/lib/block.c")
        .file("libvorbis/lib/codebook.c")
        .file("libvorbis/lib/envelope.c")
        .file("libvorbis/lib/floor0.c")
        .file("libvorbis/lib/floor1.c")
        .file("libvorbis/lib/info.c")
        .file("libvorbis/lib/lookup.c")
        .file("libvorbis/lib/lpc.c")
        .file("libvorbis/lib/lsp.c")
        .file("libvorbis/lib/mapping0.c")
        .file("libvorbis/lib/mdct.c")
        .file("libvorbis/lib/psy.c")
        .file("libvorbis/lib/registry.c")
        .file("libvorbis/lib/res0.c")
        .file("libvorbis/lib/sharedbook.c")
        .file("libvorbis/lib/smallft.c")
        .file("libvorbis/lib/synthesis.c")
        .file("libvorbis/lib/vorbisenc.c")
        .file("libvorbis/lib/window.c")
        .define("_USRDLL", None)
        .define("LIBVORBIS_EXPORTS", None)
        .include(&root.join("include"))
        .include(&root.join("lib"))
        .include(&ogg_inc)
        .compile("libvorbis.a");
}
<|endoftext|>


<commit_before>extern crate parsell;

use parsell::{StaticMarker};

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum BinOp {
    Add,
    And,
    DivS,
    DivU,
    Eq,
    GeS,
    GeU,
    GtS,
    GtU,
    LeS,
    LeU,
    LtS,
    LtU,
    Mul,
    Ne,
    Or,
    RemS,
    RemU,
    Shl,
    ShrS,
    ShrU,
    Sub,
    Xor,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Export {
    pub name: String,
    pub func: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Expr {
    ConstExpr(Typ, usize),
    GetLocalExpr(String),
    BinOpExpr(Typ, BinOp, Box<Expr>, Box<Expr>),
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Function {
    pub name: String,
    pub params: Vec<Var>,
    pub result: Option<Typ>,
    pub locals: Vec<Var>,
    pub body: Vec<Expr>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Import {
    pub func: String,
    pub module: String,
    pub name: String,
    pub params: Vec<Var>,
    pub result: Option<Typ>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Memory {
    pub init: usize,
    pub max: Option<usize>,
    pub segments: Vec<Segment>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Module {
    pub memory: Option<Memory>,
    pub imports: Vec<Import>,
    pub exports: Vec<Export>,
    pub functions: Vec<Function>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Segment {
    pub addr: usize,
    pub data: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Typ {
    I32,
    I64,
    F32,
    F64,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Var {
    pub name: String,
    pub typ: Typ,
}

impl StaticMarker for BinOp {}
impl StaticMarker for Expr {}
impl StaticMarker for Export {}
impl StaticMarker for Function {}
impl StaticMarker for Import {}
impl StaticMarker for Segment {}
impl StaticMarker for Memory {}
impl StaticMarker for Module {}
impl StaticMarker for Typ {}
<commit_msg>Added rot_l and rot_r to BinOp.<commit_after>extern crate parsell;

use parsell::{StaticMarker};

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum BinOp {
    Add,
    And,
    DivS,
    DivU,
    Eq,
    GeS,
    GeU,
    GtS,
    GtU,
    LeS,
    LeU,
    LtS,
    LtU,
    Mul,
    Ne,
    Or,
    RemS,
    RemU,
    RotL,
    RotR,
    Shl,
    ShrS,
    ShrU,
    Sub,
    Xor,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Export {
    pub name: String,
    pub func: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Expr {
    ConstExpr(Typ, usize),
    GetLocalExpr(String),
    BinOpExpr(Typ, BinOp, Box<Expr>, Box<Expr>),
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Function {
    pub name: String,
    pub params: Vec<Var>,
    pub result: Option<Typ>,
    pub locals: Vec<Var>,
    pub body: Vec<Expr>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Import {
    pub func: String,
    pub module: String,
    pub name: String,
    pub params: Vec<Var>,
    pub result: Option<Typ>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Memory {
    pub init: usize,
    pub max: Option<usize>,
    pub segments: Vec<Segment>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Module {
    pub memory: Option<Memory>,
    pub imports: Vec<Import>,
    pub exports: Vec<Export>,
    pub functions: Vec<Function>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Segment {
    pub addr: usize,
    pub data: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Typ {
    I32,
    I64,
    F32,
    F64,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Var {
    pub name: String,
    pub typ: Typ,
}

impl StaticMarker for BinOp {}
impl StaticMarker for Expr {}
impl StaticMarker for Export {}
impl StaticMarker for Function {}
impl StaticMarker for Import {}
impl StaticMarker for Segment {}
impl StaticMarker for Memory {}
impl StaticMarker for Module {}
impl StaticMarker for Typ {}
<|endoftext|>


<commit_before>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use docopt::Docopt;
use rand::{thread_rng, Rng};
use serde::Deserialize;

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
    global_allocator
)]
#[cfg(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
";

#[derive(Deserialize, Clone)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_key_len: usize,
    flag_val_len: usize,
    flag_get_prop: usize,
    flag_set_prop: usize,
    flag_del_prop: usize,
    flag_cas_prop: usize,
    flag_scan_prop: usize,
    flag_merge_prop: usize,
    flag_entries: usize,
    flag_sequential: bool,
    flag_total_ops: Option<usize>,
}

// defaults will be applied later based on USAGE above
static mut ARGS: Args = Args {
    flag_threads: 0,
    flag_burn_in: false,
    flag_duration: 0,
    flag_key_len: 0,
    flag_val_len: 0,
    flag_get_prop: 0,
    flag_set_prop: 0,
    flag_del_prop: 0,
    flag_cas_prop: 0,
    flag_scan_prop: 0,
    flag_merge_prop: 0,
    flag_entries: 0,
    flag_sequential: false,
    flag_total_ops: None,
};

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let args = unsafe { ARGS.clone() };

    let get_max = args.flag_get_prop;
    let set_max = get_max + args.flag_set_prop;
    let del_max = set_max + args.flag_del_prop;
    let cas_max = del_max + args.flag_cas_prop;
    let merge_max = cas_max + args.flag_merge_prop;
    let scan_max = merge_max + args.flag_scan_prop;

    let bytes = |len| -> sled::IVec {
        let i = if args.flag_sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.flag_entries;

        let i_bytes = i.to_be_bytes();

        i_bytes
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };
    let mut rng = thread_rng();

    let value = sled::IVec::from(vec![0; args.flag_val_len]);

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.flag_key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, value.clone()).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old =
                    if rng.gen::<bool>() { Some(value.clone()) } else { None };

                let new =
                    if rng.gen::<bool>() { Some(value.clone()) } else { None };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                tree.merge(&key, value.clone()).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = unsafe {
        ARGS = Docopt::new(USAGE)
            .and_then(|d| d.argv(std::env::args()).deserialize())
            .unwrap_or_else(|e| e.exit());
        ARGS.clone()
    };

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(200))
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;

    for i in 0..=n_threads {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            thread::spawn(move || run(tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.flag_total_ops {
        assert!(!args.flag_burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.flag_burn_in {
        thread::sleep(std::time::Duration::from_secs(unsafe {
            ARGS.flag_duration
        }));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<commit_msg>Add flusher frequency to stress2 configurables<commit_after>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use docopt::Docopt;
use rand::{thread_rng, Rng};
use serde::Deserialize;

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
    global_allocator
)]
#[cfg(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        feature = "jemalloc",
    ),
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>] \
    [--flush-every=<ms>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
    --flush-every=<m>  Flush and sync the database every ms [default: 200].
";

#[derive(Deserialize, Clone)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_key_len: usize,
    flag_val_len: usize,
    flag_get_prop: usize,
    flag_set_prop: usize,
    flag_del_prop: usize,
    flag_cas_prop: usize,
    flag_scan_prop: usize,
    flag_merge_prop: usize,
    flag_entries: usize,
    flag_sequential: bool,
    flag_total_ops: Option<usize>,
    flag_flush_every: u64,
}

// defaults will be applied later based on USAGE above
static mut ARGS: Args = Args {
    flag_threads: 0,
    flag_burn_in: false,
    flag_duration: 0,
    flag_key_len: 0,
    flag_val_len: 0,
    flag_get_prop: 0,
    flag_set_prop: 0,
    flag_del_prop: 0,
    flag_cas_prop: 0,
    flag_scan_prop: 0,
    flag_merge_prop: 0,
    flag_entries: 0,
    flag_sequential: false,
    flag_total_ops: None,
    flag_flush_every: 200,
};

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops, {}mb RSS", total - last, rss() / (1024 * 1024));

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let args = unsafe { ARGS.clone() };

    let get_max = args.flag_get_prop;
    let set_max = get_max + args.flag_set_prop;
    let del_max = set_max + args.flag_del_prop;
    let cas_max = del_max + args.flag_cas_prop;
    let merge_max = cas_max + args.flag_merge_prop;
    let scan_max = merge_max + args.flag_scan_prop;

    let bytes = |len| -> sled::IVec {
        let i = if args.flag_sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.flag_entries;

        let i_bytes = i.to_be_bytes();

        i_bytes
            .iter()
            .skip_while(|v| **v == 0)
            .cycle()
            .take(len)
            .copied()
            .collect()
    };
    let mut rng = thread_rng();

    let value = sled::IVec::from(vec![0; args.flag_val_len]);

    while !shutdown.load(Ordering::Relaxed) {
        let op = TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.flag_key_len);
        let choice = rng.gen_range(0, scan_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, value.clone()).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old =
                    if rng.gen::<bool>() { Some(value.clone()) } else { None };

                let new =
                    if rng.gen::<bool>() { Some(value.clone()) } else { None };

                if let Err(e) = tree.compare_and_swap(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= merge_max => {
                tree.merge(&key, value.clone()).unwrap();
            }
            _ => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if op % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
        }
    }
}

fn rss() -> usize {
    #[cfg(target_os = "linux")]
    {
        use std::io::prelude::*;
        use std::io::BufReader;

        let mut buf = String::new();
        let mut f =
            BufReader::new(std::fs::File::open("/proc/self/statm").unwrap());
        f.read_line(&mut buf).unwrap();
        let mut parts = buf.split_whitespace();
        let rss_pages = parts.nth(1).unwrap().parse::<usize>().unwrap();
        rss_pages * 4096
    }
    #[cfg(not(target_os = "linux"))]
    {
        0
    }
}

fn main() {
    #[cfg(feature = "logging")]
    setup_logger();

    let args = unsafe {
        ARGS = Docopt::new(USAGE)
            .and_then(|d| d.argv(std::env::args()).deserialize())
            .unwrap_or_else(|e| e.exit());
        ARGS.clone()
    };

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::Config::new()
        .cache_capacity(256 * 1024 * 1024)
        .flush_every_ms(Some(args.flag_flush_every))
        .print_profile_on_drop(true);

    let tree = Arc::new(config.open().unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;

    for i in 0..=n_threads {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            thread::spawn(move || run(tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.flag_total_ops {
        assert!(!args.flag_burn_in, "don't set both --burn-in and --total-ops");
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.flag_burn_in {
        thread::sleep(std::time::Duration::from_secs(unsafe {
            ARGS.flag_duration
        }));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

#[cfg(feature = "logging")]
pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current().name().unwrap_or("unknown").to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate conrod;
extern crate rustc_serialize;
extern crate time;
extern crate piston_window;

mod arena;
mod db;
mod graphic;
mod player;

use player::Player;
use player::PlayerType;
use arena::Arena;
use db::enums;

fn main() {
    println!("");
    println!("Hello and Welcome to the Pokemon Battle Arena");
    println!("");
    testing();
}

// This function is for testing. Pls uncommend before commiting!
fn testing() {

    println!("Testing:");
    for entry in db::movedex::Movedex::new().get_entries() {
        if entry.get_category() == enums::MoveCategory::WholeFieldEffect {
            println!("{:?}", entry.get_name());
        }
    }
    // test_players();
    // test_arena();
    graphic::gui::draw_window();
}

fn test_players() {

    println!("The Player Section");
    let mut human = Player::new_by_id(&[5, 3, 17], PlayerType::Human);

    println!("Creating a player and testing count and getting the name");
    println!("Count: {}", human.get_pokemon_count());
    println!("Place 1: {}", human.get_pokemon_list()[0].get_name());
    println!("Place 2: {}", human.get_pokemon_list()[1].get_name());
    println!("Place 3: {}", human.get_pokemon_list()[2].get_name());

    println!("Alive list:");
    println!("Number: {}", human.get_alive_count());
    println!("List: {:#?}", human.get_alive_list());

    println!("Current:");
    println!("Default: {}", human.get_current());
    human.set_current(2);
    println!("Custom: {}", human.get_current());
}

fn test_arena() {
    // Arena erstellen
    let mut p1 = Player::new_by_id(&[5], PlayerType::Human);
    let mut p2 = Player::new_by_id(&[8], PlayerType::Human);
    let mut arena = Arena::new(&mut p1,
                               &mut p2,
                               db::enums::Types::Normal,
                               db::enums::Weather::ClearSky);
    // println!("Player One: {:#?}", arena.get_player_one());
    // println!("Player Two: {:#?}", arena.get_player_two());
    // Attacke erstellen und "Kampf"
    let movedex = db::movedex::Movedex::new();
    let attack = movedex.move_by_id(1).unwrap();
    let attack_haze = movedex.move_by_id(114).unwrap();
    let attack_hail = movedex.move_by_id(258).unwrap();
    let attack_sandstorm = movedex.move_by_id(201).unwrap();
    let attack_mudsport = movedex.move_by_id(300).unwrap();
    let attack_fairylock = movedex.move_by_id(587).unwrap();
    println!("Attack: {}", attack_hail.get_name());
    println!("HP1 vorher: {}",
             arena.get_player_one().get_pokemon_list()[0]
                 .get_current()
                 .get_stat(&db::enums::Stats::Hp));
    println!("HP2 vorher: {}",
             arena.get_player_two().get_pokemon_list()[0]
                 .get_current()
                 .get_stat(&db::enums::Stats::Hp));
    attack.resolve(&mut arena, enums::Player::Two);
    attack_hail.resolve(&mut arena, enums::Player::Two);
    attack_haze.resolve(&mut arena, enums::Player::Two);
    attack_sandstorm.resolve(&mut arena, enums::Player::Two);
    attack_mudsport.resolve(&mut arena, enums::Player::Two);
    attack_fairylock.resolve(&mut arena, enums::Player::Two);
    attack.resolve(&mut arena, enums::Player::Two);

    println!("HP1 nachher: {}",
             arena.get_player_one().get_pokemon_list()[0]
                 .get_current()
                 .get_stat(&db::enums::Stats::Hp));
    println!("HP2 nachher: {}",
             arena.get_player_two().get_pokemon_list()[0]
                 .get_current()
                 .get_stat(&db::enums::Stats::Hp));
    println!("Hash vorher: {:?}", arena.get_field_effects());
    println!("Weather vorher: {:?}", arena.get_current_weather());
    arena.validate_effects_and_weather();
    arena.validate_effects_and_weather();
    println!("Hash nach 2 Runden: {:?}", arena.get_field_effects());
    println!("Weather nach 2 Runden: {:?}", arena.get_current_weather());
    arena.validate_effects_and_weather();
    arena.validate_effects_and_weather();
    arena.validate_effects_and_weather();
    println!("Hash nach 5 Runden: {:?}", arena.get_field_effects());
    println!("Weather nach 5 Runden: {:?}", arena.get_current_weather());
    arena.validate_effects_and_weather();
    arena.validate_effects_and_weather();
    println!("Hash nach 7 Runden: {:?}", arena.get_field_effects());
    println!("Weather nach 7 Runden: {:?}", arena.get_current_weather());
    // println!("Player One: {:#?}", arena.get_player_one());
}
<commit_msg>edit main.rs<commit_after>#![allow(dead_code)]
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate conrod;
extern crate rustc_serialize;
extern crate time;
extern crate piston_window;

mod arena;
mod db;
mod graphic;
mod player;

use player::Player;
use player::PlayerType;
use arena::Arena;
use db::enums;

fn main() {
    println!("");
    println!("Hello and Welcome to the Pokemon Battle Arena");
    println!("");
    testing();
}

// This function is for testing. Pls uncommend before commiting!
fn testing() {

    println!("Testing:");
    for entry in db::movedex::Movedex::new().get_entries() {
        if entry.get_category() == enums::MoveCategory::WholeFieldEffect {
            println!("{:?}", entry.get_name());
        }
    }
    // test_players();
    // test_arena();
    let mut window = graphic::gui::App::new();
    window.draw_window();
}

fn test_players() {

    println!("The Player Section");
    let mut human = Player::new_by_id(&[5, 3, 17], PlayerType::Human);

    println!("Creating a player and testing count and getting the name");
    println!("Count: {}", human.get_pokemon_count());
    println!("Place 1: {}", human.get_pokemon_list()[0].get_name());
    println!("Place 2: {}", human.get_pokemon_list()[1].get_name());
    println!("Place 3: {}", human.get_pokemon_list()[2].get_name());

    println!("Alive list:");
    println!("Number: {}", human.get_alive_count());
    println!("List: {:#?}", human.get_alive_list());

    println!("Current:");
    println!("Default: {}", human.get_current());
    human.set_current(2);
    println!("Custom: {}", human.get_current());
}

fn test_arena() {
    // Arena erstellen
    let mut p1 = Player::new_by_id(&[5], PlayerType::Human);
    let mut p2 = Player::new_by_id(&[8], PlayerType::Human);
    let mut arena = Arena::new(&mut p1,
                               &mut p2,
                               db::enums::Types::Normal,
                               db::enums::Weather::ClearSky);
    // println!("Player One: {:#?}", arena.get_player_one());
    // println!("Player Two: {:#?}", arena.get_player_two());
    // Attacke erstellen und "Kampf"
    let movedex = db::movedex::Movedex::new();
    let attack = movedex.move_by_id(1).unwrap();
    let attack_haze = movedex.move_by_id(114).unwrap();
    let attack_hail = movedex.move_by_id(258).unwrap();
    let attack_sandstorm = movedex.move_by_id(201).unwrap();
    let attack_mudsport = movedex.move_by_id(300).unwrap();
    let attack_fairylock = movedex.move_by_id(587).unwrap();
    println!("Attack: {}", attack_hail.get_name());
    println!("HP1 vorher: {}",
             arena.get_player_one().get_pokemon_list()[0]
                 .get_current()
                 .get_stat(&db::enums::Stats::Hp));
    println!("HP2 vorher: {}",
             arena.get_player_two().get_pokemon_list()[0]
                 .get_current()
                 .get_stat(&db::enums::Stats::Hp));
    attack.resolve(&mut arena, enums::Player::Two);
    attack_hail.resolve(&mut arena, enums::Player::Two);
    attack_haze.resolve(&mut arena, enums::Player::Two);
    attack_sandstorm.resolve(&mut arena, enums::Player::Two);
    attack_mudsport.resolve(&mut arena, enums::Player::Two);
    attack_fairylock.resolve(&mut arena, enums::Player::Two);
    attack.resolve(&mut arena, enums::Player::Two);

    println!("HP1 nachher: {}",
             arena.get_player_one().get_pokemon_list()[0]
                 .get_current()
                 .get_stat(&db::enums::Stats::Hp));
    println!("HP2 nachher: {}",
             arena.get_player_two().get_pokemon_list()[0]
                 .get_current()
                 .get_stat(&db::enums::Stats::Hp));
    println!("Hash vorher: {:?}", arena.get_field_effects());
    println!("Weather vorher: {:?}", arena.get_current_weather());
    arena.validate_effects_and_weather();
    arena.validate_effects_and_weather();
    println!("Hash nach 2 Runden: {:?}", arena.get_field_effects());
    println!("Weather nach 2 Runden: {:?}", arena.get_current_weather());
    arena.validate_effects_and_weather();
    arena.validate_effects_and_weather();
    arena.validate_effects_and_weather();
    println!("Hash nach 5 Runden: {:?}", arena.get_field_effects());
    println!("Weather nach 5 Runden: {:?}", arena.get_current_weather());
    arena.validate_effects_and_weather();
    arena.validate_effects_and_weather();
    println!("Hash nach 7 Runden: {:?}", arena.get_field_effects());
    println!("Weather nach 7 Runden: {:?}", arena.get_current_weather());
    // println!("Player One: {:#?}", arena.get_player_one());
}
<|endoftext|>


<commit_before>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream };

use core::semantic::*;
use core::position::*;

// type ParseFn<'a, I, T> = fn (&LanguageEnv<'a, I>, State<I>)
//                             -> ParseResult<T, I>;

pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });

    env.white_space()
       .parse(code);

    unimplemented!()
}
<commit_msg>Parser stuff<commit_after>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream };

use core::semantic::*;
use core::semantic::annotations::UnscopedState;
use core::position::*;

type ParseFn<'a, I, T> = fn (&LanguageEnv<'a, I>, State<I>)
                            -> ParseResult<T, I>;

#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b LanguageEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

fn def<'a, I>(env: &LanguageEnv<'a, I>,
              input: State<I>) -> ParseResult<ast::Form<'a, UnscopedState>, I>
where I: Stream<Item=char> {

    unimplemented!()
}

fn expr<'a, I>(env: &LanguageEnv<'a, I>, input: State<I>)
              -> ParseResult<ast::Expr<'a, UnscopedState>, I>
where I: Stream<Item=char> {
    // env.parens( choice([ form(
    //                     ])
    //           )
    //    .parse_state(input)
    unimplemented!()

}

pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });

    env.white_space()
       .parse(code);

    unimplemented!()
}
<|endoftext|>


<commit_before>pub mod space;
pub mod seq;
pub mod set;
pub mod choice;
pub mod int;
pub mod spec;

use nom::{space, is_alphanumeric, alpha, digit};
use parse::space::{skip_other};
use parse::seq::asn1_seq;
use parse::set::asn1_set;
use parse::choice::asn1_choice;
use parse::int::asn1_integer;
use data::{Asn1Type, Asn1Class, Asn1Tag, Asn1Def, Asn1Field, Asn1Optional};

named!(pub asn1_type_name <String>, chain!(
  s: take_while!(is_alphanumeric),
  || String::from_utf8(Vec::from(s)).unwrap()
));

named!(pub asn1_class_tag <Asn1Tag>, do_parse!(
  opt!(space) >>
  class: opt!(alpha) >>
  opt!(space) >>
  tag_num: digit >>
  opt!(space) >>
  ( {
      let class = class.and_then(|i|
        String::from_utf8(Vec::from(i)).ok()
      );
      Asn1Class::parse(class).expect("Couldn't parse tag class")
    },
    String::from_utf8(Vec::from(tag_num)).unwrap().parse().expect("Couldn't parse tag number")
  )
));

named!(pub asn1_tag <Asn1Tag>, do_parse!(
  opt!(space) >>
  tag: delimited!(
    tag!("["),
    asn1_class_tag,
    tag!("]")
  ) >>
  (tag)
));

named!(pub asn1_type_def <Asn1Def>, do_parse!(
  name: asn1_type_name >>
  opt!(space) >>
  tag!("::=") >>
  tag: opt!(asn1_tag) >>
  opt!(space) >>
  asn1_type: asn1_type >>
  (Asn1Def {
    name: name,
    tag: tag,
    assign: asn1_type,
  })
));

named!(pub asn1_type <Asn1Type>, alt!(
  chain!(s: asn1_seq, || Asn1Type::Seq(s)) |
  chain!(s: asn1_set, || Asn1Type::Set(s)) |
  chain!(c: asn1_choice, || Asn1Type::Choice(c)) |
  chain!(i: asn1_integer, || Asn1Type::Integer(i)) |
  chain!(t: asn1_assignment, || Asn1Type::Type(t))
));

named!(pub asn1_assignment <String>, chain!(
  t: asn1_type_name,
  || t
));

named!(pub asn1_field <Asn1Field>, do_parse!(
  opt!(skip_other) >>
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  opt!(skip_other) >>
  optional: opt!(alt!(asn1_field_optional | asn1_field_default)) >>
  (Asn1Field {
    name: name,
    tag: tag,
    asn1_type: asn1_type,
    optional: optional,
  })
));

named!(pub asn1_field_optional <Asn1Optional>, do_parse!(
  tag!("OPTIONAL") >>
  (Asn1Optional::Optional)
));

named!(pub asn1_field_default <Asn1Optional>, do_parse!(
  tag!("DEFAULT") >>
  opt!(skip_other) >>
  default: take_while!(is_alphanumeric) >>
  (Asn1Optional::Default(
    String::from_utf8(Vec::from(default)).unwrap()
  ))
));
#[test]
fn test_asn1_tag() {
  let tag: Asn1Tag = (Asn1Class::ContextSpecific, 32);
  assert_eq!(asn1_tag("[32]".as_bytes()).unwrap().1, tag);
  assert_eq!(asn1_tag("[ 32 ]".as_bytes()).unwrap().1, tag);
  assert_eq!(
    asn1_tag("[APPLICATION 12]".as_bytes()).unwrap().1,
    (Asn1Class::Application, 12)
  );
  assert_eq!(
    asn1_tag("[PRIVATE 24]".as_bytes()).unwrap().1,
    (Asn1Class::Private, 24)
  );
}

#[test]
fn test_asn1_field() {
  let field1 = ::Asn1Field {
    name: "foo".into(),
    tag: None,
    asn1_type: ::Asn1Type::Type("Bar".into()),
    optional: None,
  };
  let field2 = ::Asn1Field {
    name: "asdf".into(),
    tag: Some((Asn1Class::Application, 9)),
    asn1_type: ::Asn1Type::Integer(::Asn1Integer),
    optional: Some(Asn1Optional::Optional),
  };
  let field3 = ::Asn1Field {
    name: "sample".into(),
    tag: None,
    asn1_type: ::Asn1Type::Integer(::Asn1Integer),
    optional: Some(Asn1Optional::Default("TRUE".into())),
  };
  assert_eq!(
    field1,
    asn1_field("foo Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field2,
    asn1_field("asdf [APPLICATION 9] INTEGER OPTIONAL,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field1,
    asn1_field("foo--test\n Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field3,
    asn1_field("sample INTEGER DEFAULT TRUE,".as_bytes()).unwrap().1
  );
}
<commit_msg>Update some more parsers from chain! to do_parse!<commit_after>pub mod space;
pub mod seq;
pub mod set;
pub mod choice;
pub mod int;
pub mod spec;

use nom::{space, is_alphanumeric, alpha, digit};
use parse::space::{skip_other};
use parse::seq::asn1_seq;
use parse::set::asn1_set;
use parse::choice::asn1_choice;
use parse::int::asn1_integer;
use data::{Asn1Type, Asn1Class, Asn1Tag, Asn1Def, Asn1Field, Asn1Optional};

named!(pub asn1_type_name <String>, do_parse!(
  s: take_while!(is_alphanumeric) >>
  (String::from_utf8(Vec::from(s)).unwrap())
));

named!(pub asn1_class_tag <Asn1Tag>, do_parse!(
  opt!(space) >>
  class: opt!(alpha) >>
  opt!(space) >>
  tag_num: digit >>
  opt!(space) >>
  ( {
      let class = class.and_then(|i|
        String::from_utf8(Vec::from(i)).ok()
      );
      Asn1Class::parse(class).expect("Couldn't parse tag class")
    },
    String::from_utf8(Vec::from(tag_num)).unwrap().parse().expect("Couldn't parse tag number")
  )
));

named!(pub asn1_tag <Asn1Tag>, do_parse!(
  opt!(space) >>
  tag: delimited!(
    tag!("["),
    asn1_class_tag,
    tag!("]")
  ) >>
  (tag)
));

named!(pub asn1_type_def <Asn1Def>, do_parse!(
  name: asn1_type_name >>
  opt!(space) >>
  tag!("::=") >>
  tag: opt!(asn1_tag) >>
  opt!(space) >>
  asn1_type: asn1_type >>
  (Asn1Def {
    name: name,
    tag: tag,
    assign: asn1_type,
  })
));

named!(pub asn1_type <Asn1Type>, alt!(
  do_parse!(s: asn1_seq >> (Asn1Type::Seq(s))) |
  do_parse!(s: asn1_set >> (Asn1Type::Set(s))) |
  do_parse!(c: asn1_choice >> (Asn1Type::Choice(c))) |
  do_parse!(i: asn1_integer >> (Asn1Type::Integer(i))) |
  do_parse!(t: asn1_assignment >> (Asn1Type::Type(t)))
));

named!(pub asn1_assignment <String>, chain!(
  t: asn1_type_name,
  || t
));

named!(pub asn1_field <Asn1Field>, do_parse!(
  opt!(skip_other) >>
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  opt!(skip_other) >>
  optional: opt!(alt!(asn1_field_optional | asn1_field_default)) >>
  (Asn1Field {
    name: name,
    tag: tag,
    asn1_type: asn1_type,
    optional: optional,
  })
));

named!(pub asn1_field_optional <Asn1Optional>, do_parse!(
  tag!("OPTIONAL") >>
  (Asn1Optional::Optional)
));

named!(pub asn1_field_default <Asn1Optional>, do_parse!(
  tag!("DEFAULT") >>
  opt!(skip_other) >>
  default: take_while!(is_alphanumeric) >>
  (Asn1Optional::Default(
    String::from_utf8(Vec::from(default)).unwrap()
  ))
));

#[test]
fn test_asn1_tag() {
  let tag: Asn1Tag = (Asn1Class::ContextSpecific, 32);
  assert_eq!(asn1_tag("[32]".as_bytes()).unwrap().1, tag);
  assert_eq!(asn1_tag("[ 32 ]".as_bytes()).unwrap().1, tag);
  assert_eq!(
    asn1_tag("[APPLICATION 12]".as_bytes()).unwrap().1,
    (Asn1Class::Application, 12)
  );
  assert_eq!(
    asn1_tag("[PRIVATE 24]".as_bytes()).unwrap().1,
    (Asn1Class::Private, 24)
  );
}

#[test]
fn test_asn1_field() {
  let field1 = ::Asn1Field {
    name: "foo".into(),
    tag: None,
    asn1_type: ::Asn1Type::Type("Bar".into()),
    optional: None,
  };
  let field2 = ::Asn1Field {
    name: "asdf".into(),
    tag: Some((Asn1Class::Application, 9)),
    asn1_type: ::Asn1Type::Integer(::Asn1Integer),
    optional: Some(Asn1Optional::Optional),
  };
  let field3 = ::Asn1Field {
    name: "sample".into(),
    tag: None,
    asn1_type: ::Asn1Type::Integer(::Asn1Integer),
    optional: Some(Asn1Optional::Default("TRUE".into())),
  };
  assert_eq!(
    field1,
    asn1_field("foo Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field2,
    asn1_field("asdf [APPLICATION 9] INTEGER OPTIONAL,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field1,
    asn1_field("foo--test\n Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field3,
    asn1_field("sample INTEGER DEFAULT TRUE,".as_bytes()).unwrap().1
  );
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::HashMap;

use futures::{Async, Future, Poll};

use crate::common::*;
use crate::error::Error::BadUrl;
use crate::{auth, error, links};

use super::PlaceQuery;
use super::*;

/// Load the place with the given ID.
///
/// ## Examples
///
/// ```rust,no_run
/// # use egg_mode::Token;
/// use tokio::runtime::current_thread::block_on_all;
/// # fn main() {
/// # let token: Token = unimplemented!();
/// let result = block_on_all(egg_mode::place::show("18810aa5b43e76c7", &token)).unwrap();
///
/// assert!(result.full_name == "Dallas, TX");
/// # }
/// ```
pub fn show(id: &str, token: &auth::Token) -> FutureResponse<Place> {
    let url = format!("{}/{}.json", links::place::SHOW_STEM, id);

    let req = auth::get(&url, token, None);

    make_parsed_future(req)
}

/// Begins building a reverse-geocode search with the given coordinate.
///
/// ## Examples
///
/// ```rust,no_run
/// # use egg_mode::Token;
/// use tokio::runtime::current_thread::block_on_all;
/// # fn main() {
/// # let token: Token = unimplemented!();
/// use egg_mode::place::{self, PlaceType};
/// let result = block_on_all(place::reverse_geocode(51.507222, -0.1275)
///                                 .granularity(PlaceType::City)
///                                 .call(&token))
///                  .unwrap();
///
/// assert!(result.results.iter().any(|pl| pl.full_name == "London, England"));
/// # }
/// ```
pub fn reverse_geocode(latitude: f64, longitude: f64) -> GeocodeBuilder {
    GeocodeBuilder::new(latitude, longitude)
}

fn parse_url<'a>(base: &'static str, full: &'a str) -> Result<ParamList<'a>, error::Error> {
    let mut iter = full.split('?');

    if let Some(base_part) = iter.next() {
        if base_part != base {
            return Err(BadUrl);
        }
    } else {
        return Err(BadUrl);
    }

    if let Some(list) = iter.next() {
        let mut p = HashMap::new();

        for item in list.split('&') {
            let mut kv_iter = item.split('=');

            let k = kv_iter.next().ok_or(BadUrl)?;
            let v = kv_iter.next().ok_or(BadUrl)?;

            add_param(&mut p, k, v);
        }

        Ok(p)
    } else {
        Err(BadUrl)
    }
}

///From a URL given with the result of `reverse_geocode`, perform the same reverse-geocode search.
///
///## Errors
///
///In addition to errors that might occur generally, this function will return a `BadUrl` error if
///the given URL is not a valid `reverse_geocode` query URL.
pub fn reverse_geocode_url<'a>(url: &'a str, token: &auth::Token) -> CachedSearchFuture<'a> {
    let params = parse_url(links::place::REVERSE_GEOCODE, url);
    CachedSearchFuture::new(links::place::REVERSE_GEOCODE, token, params)
}

/// Begins building a location search via latitude/longitude.
///
/// ## Example
///
/// ```rust,no_run
/// # use egg_mode::Token;
/// use tokio::runtime::current_thread::block_on_all;
/// # fn main() {
/// # let token: Token = unimplemented!();
/// use egg_mode::place::{self, PlaceType};
/// let result = block_on_all(place::search_point(51.507222, -0.1275)
///                                 .granularity(PlaceType::City)
///                                 .call(&token))
///                  .unwrap();
///
/// assert!(result.results.iter().any(|pl| pl.full_name == "London, England"));
/// # }
/// ```
pub fn search_point(latitude: f64, longitude: f64) -> SearchBuilder<'static> {
    SearchBuilder::new(PlaceQuery::LatLon(latitude, longitude))
}

/// Begins building a location search via a text query.
///
/// ## Example
///
/// ```rust,no_run
/// # use egg_mode::Token;
/// use tokio::runtime::current_thread::block_on_all;
/// # fn main() {
/// # let token: Token = unimplemented!();
/// use egg_mode::place::{self, PlaceType};
/// let result = block_on_all(place::search_query("columbia")
///                                 .granularity(PlaceType::Admin)
///                                 .call(&token))
///                  .unwrap();
///
/// assert!(result.results.iter().any(|pl| pl.full_name == "British Columbia, Canada"));
/// # }
/// ```
pub fn search_query<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder::new(PlaceQuery::Query(query))
}

///Begins building a location search via an IP address.
pub fn search_ip<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder::new(PlaceQuery::IPAddress(query))
}

///From a URL given with the result of any `search_*` function, perform the same location search.
///
///## Errors
///
///In addition to errors that might occur generally, this function will return a `BadUrl` error if
///the given URL is not a valid `search` query URL.
pub fn search_url<'a>(url: &'a str, token: &auth::Token) -> CachedSearchFuture<'a> {
    let params = parse_url(links::place::SEARCH, url);
    CachedSearchFuture::new(links::place::SEARCH, token, params)
}

/// A `TwitterFuture` that needs to parse a provided URL before making a request.
///
/// This is a special case of [`TwitterFuture`] returned by [`reverse_geocode_url`] and
/// [`search_url`] so it can parse the cached search URL and return an error before making a web
/// request. See the docs for `TwitterFuture` for details.
///
/// [`TwitterFuture`]: ../struct.TwitterFuture.html
/// [`reverse_geocode_url`]: fn.reverse_geocode_url.html
/// [`search_url`]: fn search_url.html
pub struct CachedSearchFuture<'a> {
    stem: &'static str,
    params: Option<Result<ParamList<'a>, error::Error>>,
    token: auth::Token,
    future: Option<FutureResponse<SearchResult>>,
}

impl<'a> CachedSearchFuture<'a> {
    fn new(
        stem: &'static str,
        token: &auth::Token,
        params: Result<ParamList<'a>, error::Error>,
    ) -> CachedSearchFuture<'a> {
        CachedSearchFuture {
            stem: stem,
            params: Some(params),
            token: token.clone(),
            future: None,
        }
    }
}

impl<'a> Future for CachedSearchFuture<'a> {
    type Item = Response<SearchResult>;
    type Error = error::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.params.take() {
            Some(Ok(params)) => {
                let req = auth::get(self.stem, &self.token, Some(&params));

                self.future = Some(make_parsed_future(req));
            }
            Some(Err(e)) => {
                return Err(e);
            }
            None => {}
        }

        if let Some(mut fut) = self.future.take() {
            match fut.poll() {
                Ok(Async::NotReady) => {
                    self.future = Some(fut);
                    Ok(Async::NotReady)
                }
                Ok(Async::Ready(res)) => Ok(Async::Ready(res)),
                Err(e) => Err(e),
            }
        } else {
            Err(error::Error::FutureAlreadyCompleted)
        }
    }
}
<commit_msg>remove CachedSearchFuture<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::HashMap;

use futures::{Future, IntoFuture};

use crate::common::*;
use crate::error::Error::BadUrl;
use crate::{auth, error, links};

use super::PlaceQuery;
use super::*;

/// Load the place with the given ID.
///
/// ## Examples
///
/// ```rust,no_run
/// # use egg_mode::Token;
/// use tokio::runtime::current_thread::block_on_all;
/// # fn main() {
/// # let token: Token = unimplemented!();
/// let result = block_on_all(egg_mode::place::show("18810aa5b43e76c7", &token)).unwrap();
///
/// assert!(result.full_name == "Dallas, TX");
/// # }
/// ```
pub fn show(id: &str, token: &auth::Token) -> FutureResponse<Place> {
    let url = format!("{}/{}.json", links::place::SHOW_STEM, id);

    let req = auth::get(&url, token, None);

    make_parsed_future(req)
}

/// Begins building a reverse-geocode search with the given coordinate.
///
/// ## Examples
///
/// ```rust,no_run
/// # use egg_mode::Token;
/// use tokio::runtime::current_thread::block_on_all;
/// # fn main() {
/// # let token: Token = unimplemented!();
/// use egg_mode::place::{self, PlaceType};
/// let result = block_on_all(place::reverse_geocode(51.507222, -0.1275)
///                                 .granularity(PlaceType::City)
///                                 .call(&token))
///                  .unwrap();
///
/// assert!(result.results.iter().any(|pl| pl.full_name == "London, England"));
/// # }
/// ```
pub fn reverse_geocode(latitude: f64, longitude: f64) -> GeocodeBuilder {
    GeocodeBuilder::new(latitude, longitude)
}

fn parse_url<'a>(base: &'static str, full: &'a str) -> Result<ParamList<'a>, error::Error> {
    let mut iter = full.split('?');

    if let Some(base_part) = iter.next() {
        if base_part != base {
            return Err(BadUrl);
        }
    } else {
        return Err(BadUrl);
    }

    if let Some(list) = iter.next() {
        let mut p = HashMap::new();

        for item in list.split('&') {
            let mut kv_iter = item.split('=');

            let k = kv_iter.next().ok_or(BadUrl)?;
            let v = kv_iter.next().ok_or(BadUrl)?;

            add_param(&mut p, k, v);
        }

        Ok(p)
    } else {
        Err(BadUrl)
    }
}

///From a URL given with the result of `reverse_geocode`, perform the same reverse-geocode search.
///
///## Errors
///
///In addition to errors that might occur generally, this function will return a `BadUrl` error if
///the given URL is not a valid `reverse_geocode` query URL.
pub fn reverse_geocode_url<'a>(
    url: &'a str,
    token: &'a auth::Token,
) -> impl Future<Item = Response<SearchResult>, Error = error::Error> + 'a {
    let params = parse_url(links::place::REVERSE_GEOCODE, url);
    params.into_future().and_then(move |params| {
        let req = auth::get(links::place::REVERSE_GEOCODE, &token, Some(&params));
        make_parsed_future(req)
    })
}

/// Begins building a location search via latitude/longitude.
///
/// ## Example
///
/// ```rust,no_run
/// # use egg_mode::Token;
/// use tokio::runtime::current_thread::block_on_all;
/// # fn main() {
/// # let token: Token = unimplemented!();
/// use egg_mode::place::{self, PlaceType};
/// let result = block_on_all(place::search_point(51.507222, -0.1275)
///                                 .granularity(PlaceType::City)
///                                 .call(&token))
///                  .unwrap();
///
/// assert!(result.results.iter().any(|pl| pl.full_name == "London, England"));
/// # }
/// ```
pub fn search_point(latitude: f64, longitude: f64) -> SearchBuilder<'static> {
    SearchBuilder::new(PlaceQuery::LatLon(latitude, longitude))
}

/// Begins building a location search via a text query.
///
/// ## Example
///
/// ```rust,no_run
/// # use egg_mode::Token;
/// use tokio::runtime::current_thread::block_on_all;
/// # fn main() {
/// # let token: Token = unimplemented!();
/// use egg_mode::place::{self, PlaceType};
/// let result = block_on_all(place::search_query("columbia")
///                                 .granularity(PlaceType::Admin)
///                                 .call(&token))
///                  .unwrap();
///
/// assert!(result.results.iter().any(|pl| pl.full_name == "British Columbia, Canada"));
/// # }
/// ```
pub fn search_query<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder::new(PlaceQuery::Query(query))
}

///Begins building a location search via an IP address.
pub fn search_ip<'a>(query: &'a str) -> SearchBuilder<'a> {
    SearchBuilder::new(PlaceQuery::IPAddress(query))
}

///From a URL given with the result of any `search_*` function, perform the same location search.
///
///## Errors
///
///In addition to errors that might occur generally, this function will return a `BadUrl` error if
///the given URL is not a valid `search` query URL.
pub fn search_url<'a>(
    url: &'a str,
    token: &'a auth::Token,
) -> impl Future<Item = Response<SearchResult>, Error = error::Error> + 'a {
    let params = parse_url(links::place::SEARCH, url);
    params.into_future().and_then(move |params| {
        let req = auth::get(links::place::REVERSE_GEOCODE, &token, Some(&params));
        make_parsed_future(req)
    })
}
<|endoftext|>