<commit_before>use std::cmp;
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use std::io::Write;
use std::fs::{File, rename};
use std::sync::{Mutex, MutexGuard, Arc};

use tempdir::TempDir;

use buffer::{Buffer, Mark};
use input::Input;
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;
use overlay::{Overlay, OverlayType};
use utils;
use textobject::{Anchor, TextObject, Kind, Offset};

/// 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 {
    pub buffer: Arc<Mutex<Buffer>>,
    pub last_buffer: Option<Arc<Mutex<Buffer>>>,
    pub overlay: Overlay,

    /// First character of the top line to be displayed
    top_line: Mark,

    /// Index into the top_line - used for horizontal scrolling
    left_col: usize,

    /// The current View's cursor - a reference into the Buffer
    cursor: Mark,

    /// The UIBuffer to which the View is drawn
    uibuf: UIBuffer,

    /// Number of lines from the top/bottom of the View after which vertical
    /// scrolling begins.
    threshold: usize,
}

impl View {

    pub fn new(buffer: Arc<Mutex<Buffer>>, width: usize, height: usize) -> View {
        let cursor = Mark::Cursor(0);
        let top_line = Mark::DisplayMark(0);

        {
            let mut b = buffer.lock().unwrap();

            b.set_mark(cursor, 0);
            b.set_mark(top_line, 0);
        }

        View {
            buffer: buffer,
            last_buffer: None,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: UIBuffer::new(width, height),
            overlay: Overlay::None,
            threshold: 5,
        }
    }

    pub fn set_buffer(&mut self, buffer: Arc<Mutex<Buffer>>) {
        self.last_buffer = Some(self.buffer.clone());

        {
            let mut b = buffer.lock().unwrap();

            b.set_mark(self.cursor, 0);
            b.set_mark(self.top_line, 0);
        }

        self.buffer = buffer;
    }

    pub fn switch_last_buffer(&mut self) {
        let buffer = self.buffer.clone();
        let last_buffer = match self.last_buffer.clone() {
            Some(buf) => buf,
            None => return
        };

        self.buffer = last_buffer;
        self.last_buffer = Some(buffer);
    }

    /// Get the height of the View.
    ///
    /// This is the height of the UIBuffer minus the status bar height.
    pub fn get_height(&self) -> usize {
        let status_bar_height = 1;
        let uibuf_height = self.uibuf.get_height();

        uibuf_height - status_bar_height
    }

    /// Get the width of the View.
    pub fn get_width(&self) -> usize {
        self.uibuf.get_width()
    }

    /// Resize the view
    ///
    /// This involves simply changing the size of the associated UIBuffer
    pub fn resize(&mut self, width: usize, height: usize) {
        let uibuf = UIBuffer::new(width, height);
        self.uibuf = uibuf;
    }

    /// 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);
    }

    // FIXME: should probably use draw_line here...
    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        {
            let buffer = self.buffer.lock().unwrap();
            let height = self.get_height() - 2;
            let width = self.get_width();
            let mut line = 0;
            let mut col = 0;

            // FIXME: don't use unwrap here
            //        This will fail if for some reason the buffer doesnt have
            //        the top_line mark
            for c in buffer.chars_from(self.top_line).unwrap() {
                if c == '\n' {
                    // clear everything after the end of the line content
                    for i in col..width {
                        self.uibuf.update_cell_content(i, line, ' ');
                    }

                    if line == height {
                        break;
                    }

                    col = 0;
                    line += 1;
                } else {
                    self.uibuf.update_cell_content(col, line, c);
                    col += 1;
                }
            }

        }
        match self.overlay {
            Overlay::None => self.draw_cursor(frontend),
            _ => {
                self.overlay.draw(frontend, &mut self.uibuf);
                self.overlay.draw_cursor(frontend);
            }
        }
        self.draw_status(frontend);
        self.uibuf.draw_everything(frontend);
    }

    fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer = self.buffer.lock().unwrap();
        let buffer_status = buffer.status_text();
        let mut cursor_status = 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.0, cursor_status.1).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height() - 1;

        for index in 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);
    }

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

    pub fn set_overlay(&mut self, overlay_type: OverlayType) {
        match overlay_type {
            OverlayType::Prompt => {
                self.overlay = Overlay::Prompt {
                    cursor_x: 1,
                    prefix: ":",
                    data: String::new(),
                };
            }

            OverlayType::SelectFile => {
                let prefix = "Enter file path:";

                self.overlay = Overlay::SelectFile {
                    cursor_x: prefix.len(),
                    prefix: prefix,
                    data: String::new(),
                };
            }
            _ => {}
        }
    }

    pub fn move_mark(&mut self, mark: Mark, object: TextObject) {
        self.buffer.lock().unwrap().set_mark_to_object(mark, object);
        self.maybe_move_screen();
    }

    /// Update the top_line mark if necessary to keep the cursor on the screen.
    fn maybe_move_screen(&mut self) {
        let mut buffer = self.buffer.lock().unwrap();
        if let (Some(cursor), Some((_, top_line))) = (buffer.get_mark_coords(self.cursor),
                                                      buffer.get_mark_coords(self.top_line)) {

            let width  = (self.get_width()  - self.threshold) as isize;
            let height = (self.get_height() - self.threshold) as isize;

            //left-right shifting
            self.left_col = match cursor.0 as isize - self.left_col as isize {
                x_offset if x_offset < self.threshold as isize => {
                    cmp::max(0, self.left_col as isize - (self.threshold as isize - x_offset)) as usize
                }
                x_offset if x_offset >= width => {
                    self.left_col + (x_offset - width + 1) as usize
                }
                _ => { self.left_col }
            };

            //up-down shifting
            match cursor.1 as isize - top_line as isize {
                y_offset if y_offset < self.threshold as isize && top_line > 0 => {
                    let amount = (self.threshold as isize - y_offset) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Backward(amount, self.top_line)
                    };
                    buffer.set_mark_to_object(self.top_line, obj);
                }
                y_offset if y_offset >= height => {
                    let amount = (y_offset - height + 1) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Forward(amount, self.top_line)
                    };
                    buffer.set_mark_to_object(self.top_line, obj);
                }
                _ => { }
            }
        }
    }

    // Delete chars from the first index of object to the last index of object
    pub fn delete_object(&mut self, object: TextObject) {
        self.buffer.lock().unwrap().remove_object(object);
    }

    pub fn delete_from_mark_to_object(&mut self, mark: Mark, object: TextObject) {
        let mut buffer = self.buffer.lock().unwrap();
        if let Some((idx, _)) = buffer.get_object_index(object) {
            if let Some(midx) = buffer.get_mark_idx(mark) {
                buffer.remove_from_mark_to_object(mark, object);
                buffer.set_mark(mark, cmp::min(idx, midx));
            }
        }
    }

    /// Insert a chacter into the buffer & update cursor position accordingly.
    pub fn insert_char(&mut self, ch: char) {
        self.buffer.lock().unwrap().insert_char(self.cursor, ch as u8);
        // NOTE: the last param to char_width here may not be correct
        if let Some(ch_width) = utils::char_width(ch, false, 4, 1) {
            let obj = TextObject {
                kind: Kind::Char,
                offset: Offset::Forward(ch_width, Mark::Cursor(0))
            };
            self.move_mark(Mark::Cursor(0), obj)
        }
    }

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

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

    fn save_buffer(&mut self) {
        let buffer = self.buffer.lock().unwrap();
        let path = match buffer.file_path {
            Some(ref p) => Cow::Borrowed(p),
            None => {
                // NOTE: this should never happen, as the file path
                // should have been set inside the try_save_buffer method.
                //
                // If this runs, it probably means save_buffer has been called
                // directly, rather than try_save_buffer.
                //
                // TODO: ask the user to submit a bug report on how they hit this.
                Cow::Owned(PathBuf::new("untitled"))
            },
        };
        let tmpdir = match TempDir::new_in(&Path::new("."), "iota") {
            Ok(d) => d,
            Err(e) => panic!("file error: {}", e)
        };

        let tmppath = tmpdir.path().join(Path::new("tmpfile"));
        let mut file = match File::create(&tmppath) {
            Ok(f) => f,
            Err(e) => {
                panic!("file error: {}", e)
            }
        };

        //TODO (lee): Is iteration still necessary in this format?
        for line in buffer.lines() {
            let result = file.write_all(&*line);

            if result.is_err() {
                // TODO(greg): figure out what to do here.
                panic!("Something went wrong while writing the file");
            }
        }

        if let Err(e) = rename(&tmppath, &*path) {
            panic!("file error: {}", e);
        }
    }

    pub fn try_save_buffer(&mut self) {
        let mut should_save = false;
        {
            let buffer = self.buffer.lock().unwrap();

            match buffer.file_path {
                Some(_) => { should_save = true }
                None => {
                    let prefix = "Enter file name: ";
                    self.overlay = Overlay::SavePrompt {
                        cursor_x: prefix.len(),
                        prefix: prefix,
                        data: String::new(),
                    };
                },
            }
        }

        if should_save { self.save_buffer() }
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: usize, left: usize) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in left..(left + width) {
        if line_idx < line.len() {
            let special_char = line[line_idx] as char;
            match special_char {
                '\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in 0..w {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                '\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 view::View;
    use input::Input;

    fn setup_view(testcase: &'static str) -> View {
        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_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        assert_eq!(view.buffer.lines().next().unwrap(), b"ttest\n");
    }
}
<commit_msg>Fixed failing tests<commit_after>use std::cmp;
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
use std::io::Write;
use std::fs::{File, rename};
use std::sync::{Mutex, MutexGuard, Arc};

use tempdir::TempDir;

use buffer::{Buffer, Mark};
use input::Input;
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;
use overlay::{Overlay, OverlayType};
use utils;
use textobject::{Anchor, TextObject, Kind, Offset};

/// 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 {
    pub buffer: Arc<Mutex<Buffer>>,
    pub last_buffer: Option<Arc<Mutex<Buffer>>>,
    pub overlay: Overlay,

    /// First character of the top line to be displayed
    top_line: Mark,

    /// Index into the top_line - used for horizontal scrolling
    left_col: usize,

    /// The current View's cursor - a reference into the Buffer
    cursor: Mark,

    /// The UIBuffer to which the View is drawn
    uibuf: UIBuffer,

    /// Number of lines from the top/bottom of the View after which vertical
    /// scrolling begins.
    threshold: usize,
}

impl View {

    pub fn new(buffer: Arc<Mutex<Buffer>>, width: usize, height: usize) -> View {
        let cursor = Mark::Cursor(0);
        let top_line = Mark::DisplayMark(0);

        {
            let mut b = buffer.lock().unwrap();

            b.set_mark(cursor, 0);
            b.set_mark(top_line, 0);
        }

        View {
            buffer: buffer,
            last_buffer: None,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: UIBuffer::new(width, height),
            overlay: Overlay::None,
            threshold: 5,
        }
    }

    pub fn set_buffer(&mut self, buffer: Arc<Mutex<Buffer>>) {
        self.last_buffer = Some(self.buffer.clone());

        {
            let mut b = buffer.lock().unwrap();

            b.set_mark(self.cursor, 0);
            b.set_mark(self.top_line, 0);
        }

        self.buffer = buffer;
    }

    pub fn switch_last_buffer(&mut self) {
        let buffer = self.buffer.clone();
        let last_buffer = match self.last_buffer.clone() {
            Some(buf) => buf,
            None => return
        };

        self.buffer = last_buffer;
        self.last_buffer = Some(buffer);
    }

    /// Get the height of the View.
    ///
    /// This is the height of the UIBuffer minus the status bar height.
    pub fn get_height(&self) -> usize {
        let status_bar_height = 1;
        let uibuf_height = self.uibuf.get_height();

        uibuf_height - status_bar_height
    }

    /// Get the width of the View.
    pub fn get_width(&self) -> usize {
        self.uibuf.get_width()
    }

    /// Resize the view
    ///
    /// This involves simply changing the size of the associated UIBuffer
    pub fn resize(&mut self, width: usize, height: usize) {
        let uibuf = UIBuffer::new(width, height);
        self.uibuf = uibuf;
    }

    /// 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);
    }

    // FIXME: should probably use draw_line here...
    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        {
            let buffer = self.buffer.lock().unwrap();
            let height = self.get_height() - 2;
            let width = self.get_width();
            let mut line = 0;
            let mut col = 0;

            // FIXME: don't use unwrap here
            //        This will fail if for some reason the buffer doesnt have
            //        the top_line mark
            for c in buffer.chars_from(self.top_line).unwrap() {
                if c == '\n' {
                    // clear everything after the end of the line content
                    for i in col..width {
                        self.uibuf.update_cell_content(i, line, ' ');
                    }

                    if line == height {
                        break;
                    }

                    col = 0;
                    line += 1;
                } else {
                    self.uibuf.update_cell_content(col, line, c);
                    col += 1;
                }
            }

        }
        match self.overlay {
            Overlay::None => self.draw_cursor(frontend),
            _ => {
                self.overlay.draw(frontend, &mut self.uibuf);
                self.overlay.draw_cursor(frontend);
            }
        }
        self.draw_status(frontend);
        self.uibuf.draw_everything(frontend);
    }

    fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer = self.buffer.lock().unwrap();
        let buffer_status = buffer.status_text();
        let mut cursor_status = 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.0, cursor_status.1).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height() - 1;

        for index in 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);
    }

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

    pub fn set_overlay(&mut self, overlay_type: OverlayType) {
        match overlay_type {
            OverlayType::Prompt => {
                self.overlay = Overlay::Prompt {
                    cursor_x: 1,
                    prefix: ":",
                    data: String::new(),
                };
            }

            OverlayType::SelectFile => {
                let prefix = "Enter file path:";

                self.overlay = Overlay::SelectFile {
                    cursor_x: prefix.len(),
                    prefix: prefix,
                    data: String::new(),
                };
            }
            _ => {}
        }
    }

    pub fn move_mark(&mut self, mark: Mark, object: TextObject) {
        self.buffer.lock().unwrap().set_mark_to_object(mark, object);
        self.maybe_move_screen();
    }

    /// Update the top_line mark if necessary to keep the cursor on the screen.
    fn maybe_move_screen(&mut self) {
        let mut buffer = self.buffer.lock().unwrap();
        if let (Some(cursor), Some((_, top_line))) = (buffer.get_mark_coords(self.cursor),
                                                      buffer.get_mark_coords(self.top_line)) {

            let width  = (self.get_width()  - self.threshold) as isize;
            let height = (self.get_height() - self.threshold) as isize;

            //left-right shifting
            self.left_col = match cursor.0 as isize - self.left_col as isize {
                x_offset if x_offset < self.threshold as isize => {
                    cmp::max(0, self.left_col as isize - (self.threshold as isize - x_offset)) as usize
                }
                x_offset if x_offset >= width => {
                    self.left_col + (x_offset - width + 1) as usize
                }
                _ => { self.left_col }
            };

            //up-down shifting
            match cursor.1 as isize - top_line as isize {
                y_offset if y_offset < self.threshold as isize && top_line > 0 => {
                    let amount = (self.threshold as isize - y_offset) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Backward(amount, self.top_line)
                    };
                    buffer.set_mark_to_object(self.top_line, obj);
                }
                y_offset if y_offset >= height => {
                    let amount = (y_offset - height + 1) as usize;
                    let obj = TextObject {
                        kind: Kind::Line(Anchor::Same),
                        offset: Offset::Forward(amount, self.top_line)
                    };
                    buffer.set_mark_to_object(self.top_line, obj);
                }
                _ => { }
            }
        }
    }

    // Delete chars from the first index of object to the last index of object
    pub fn delete_object(&mut self, object: TextObject) {
        self.buffer.lock().unwrap().remove_object(object);
    }

    pub fn delete_from_mark_to_object(&mut self, mark: Mark, object: TextObject) {
        let mut buffer = self.buffer.lock().unwrap();
        if let Some((idx, _)) = buffer.get_object_index(object) {
            if let Some(midx) = buffer.get_mark_idx(mark) {
                buffer.remove_from_mark_to_object(mark, object);
                buffer.set_mark(mark, cmp::min(idx, midx));
            }
        }
    }

    /// Insert a chacter into the buffer & update cursor position accordingly.
    pub fn insert_char(&mut self, ch: char) {
        self.buffer.lock().unwrap().insert_char(self.cursor, ch as u8);
        // NOTE: the last param to char_width here may not be correct
        if let Some(ch_width) = utils::char_width(ch, false, 4, 1) {
            let obj = TextObject {
                kind: Kind::Char,
                offset: Offset::Forward(ch_width, Mark::Cursor(0))
            };
            self.move_mark(Mark::Cursor(0), obj)
        }
    }

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

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

    fn save_buffer(&mut self) {
        let buffer = self.buffer.lock().unwrap();
        let path = match buffer.file_path {
            Some(ref p) => Cow::Borrowed(p),
            None => {
                // NOTE: this should never happen, as the file path
                // should have been set inside the try_save_buffer method.
                //
                // If this runs, it probably means save_buffer has been called
                // directly, rather than try_save_buffer.
                //
                // TODO: ask the user to submit a bug report on how they hit this.
                Cow::Owned(PathBuf::new("untitled"))
            },
        };
        let tmpdir = match TempDir::new_in(&Path::new("."), "iota") {
            Ok(d) => d,
            Err(e) => panic!("file error: {}", e)
        };

        let tmppath = tmpdir.path().join(Path::new("tmpfile"));
        let mut file = match File::create(&tmppath) {
            Ok(f) => f,
            Err(e) => {
                panic!("file error: {}", e)
            }
        };

        //TODO (lee): Is iteration still necessary in this format?
        for line in buffer.lines() {
            let result = file.write_all(&*line);

            if result.is_err() {
                // TODO(greg): figure out what to do here.
                panic!("Something went wrong while writing the file");
            }
        }

        if let Err(e) = rename(&tmppath, &*path) {
            panic!("file error: {}", e);
        }
    }

    pub fn try_save_buffer(&mut self) {
        let mut should_save = false;
        {
            let buffer = self.buffer.lock().unwrap();

            match buffer.file_path {
                Some(_) => { should_save = true }
                None => {
                    let prefix = "Enter file name: ";
                    self.overlay = Overlay::SavePrompt {
                        cursor_x: prefix.len(),
                        prefix: prefix,
                        data: String::new(),
                    };
                },
            }
        }

        if should_save { self.save_buffer() }
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: usize, left: usize) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in left..(left + width) {
        if line_idx < line.len() {
            let special_char = line[line_idx] as char;
            match special_char {
                '\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in 0..w {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                '\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 std::sync::{Arc, Mutex};

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

    fn setup_view(testcase: &'static str) -> View {
        let mut buffer = Arc::new(Mutex::new(Buffer::new()));
        let mut view = View::new(buffer.clone(), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }

        let mut buffer = buffer.lock().unwrap();
        buffer.set_mark(view.cursor, 0);
        view
    }

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

        {
            let mut buffer = view.buffer.lock().unwrap();
            assert_eq!(buffer.lines().next().unwrap(), b"ttest\n");
        }
    }
}
<|endoftext|>


<commit_before>use std::thread::Thread;
use std::{cmp, iter, mem, raw};

// Proxy struct to send raw pointers across task boundaries
struct RawPtr<T>(*const T);

impl<T> Copy for RawPtr<T> {}

unsafe impl<T> Send for RawPtr<T> where T: Send {}

/// Parallelizes an `operation` over a mutable slice
///
/// The `data` will be divided in chunks of `granularity` size. A new thread will be spawned to
/// "operate" over each chunk.
///
/// `operation` will receive two arguments:
///
/// - The mutable chunk of data, and
/// - The offset of this chunk from the start of `data`
///
/// # Panics
///
/// Panics if any of the underlying threads panics
///
/// # Example
///
/// Parallel map
///
/// ```
/// use std::num::Float;
/// use std::rand::{Rng, XorShiftRng, self};
///
/// let ref mut rng: XorShiftRng = rand::thread_rng().gen();
/// let mut v = range(0, 1_000u).map(|_| rng.gen::<f32>()).collect::<Vec<_>>();
/// # let w = v.iter().map(|x| x.sin()).collect::<Vec<_>>();
/// parallel::divide(v.as_mut_slice(), 100, |data, _| {
///     for x in data.iter_mut() {
///         *x = x.sin();
///     }
/// });
/// # assert_eq!(v, w);
/// ```
pub fn divide<T, F>(data: &mut [T], granularity: usize, operation: F) where
    T: Send,
    F: Fn(&mut [T], usize) + Sync,
{
    assert!(granularity > 0);

    let raw::Slice { data, len } = unsafe { mem::transmute::<_, raw::Slice<T>>(data) };
    let data = RawPtr(data);
    let op = RawPtr(&operation as *const _ as *const ());

    let threads = iter::range_step(0, len, granularity).map(|offset| {
        Thread::scoped(move || {
            // NB Is safe to send the slice/closure because the thread won't outlive this function
            let slice = raw::Slice {
                data: unsafe { data.0.offset(offset as isize) },
                len: cmp::min(granularity, len - offset)
            };
            let data = unsafe { mem::transmute::<_, &mut [T]>(slice) };
            let operation = unsafe { mem::transmute::<_, &F>(op.0) };

            (*operation)(data, offset);
        })
    }).collect::<Vec<_>>();

    for thread in threads.into_iter() {
        if thread.join().is_err() {
            panic!();
        }
    }
}

#[cfg(test)]
mod test {
    use quickcheck::TestResult;
    use std::iter;
    use std::rand::{Rng, XorShiftRng, self};

    #[quickcheck]
    fn clone(size: usize, granularity: usize) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut rng: XorShiftRng = rand::thread_rng().gen();
        let original = range(0, size).map(|_| rng.gen::<f64>()).collect::<Vec<_>>();
        let mut clone = iter::repeat(0f64).take(size).collect::<Vec<_>>();

        let original_slice = &*original;
        super::divide(&mut *clone, granularity, |data, offset| {
            for (i, x) in data.iter_mut().enumerate() {
                *x = original_slice[offset + i]
            }
        });

        TestResult::from_bool(original == clone)
    }

    #[quickcheck]
    fn new(size: usize, granularity: usize) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut v = iter::repeat(None::<f64>).take(size).collect::<Vec<_>>();

        super::divide(&mut *v, granularity, |data, _| {
            let mut rng: XorShiftRng = rand::thread_rng().gen();

            for x in data.iter_mut() {
                *x = Some(rng.gen())
            }
        });

        TestResult::from_bool(v.iter().all(|&x| match x {
            None => false,
            Some(x) => x > 0. && x < 1.
        }))
    }
}
<commit_msg>fix(doctests): allow unstable API in doctest<commit_after>use std::thread::Thread;
use std::{cmp, iter, mem, raw};

// Proxy struct to send raw pointers across task boundaries
struct RawPtr<T>(*const T);

impl<T> Copy for RawPtr<T> {}

unsafe impl<T> Send for RawPtr<T> where T: Send {}

/// Parallelizes an `operation` over a mutable slice
///
/// The `data` will be divided in chunks of `granularity` size. A new thread will be spawned to
/// "operate" over each chunk.
///
/// `operation` will receive two arguments:
///
/// - The mutable chunk of data, and
/// - The offset of this chunk from the start of `data`
///
/// # Panics
///
/// Panics if any of the underlying threads panics
///
/// # Example
///
/// Parallel map
///
/// ```
/// # #![allow(unstable)]
/// # extern crate parallel;
/// use std::num::Float;
/// use std::rand::{Rng, XorShiftRng, self};
///
/// # fn main() {
/// let ref mut rng: XorShiftRng = rand::thread_rng().gen();
/// let mut v = (0..1_000).map(|_| rng.gen::<f32>()).collect::<Vec<_>>();
/// # let w = v.iter().map(|x| x.sin()).collect::<Vec<_>>();
/// parallel::divide(v.as_mut_slice(), 100, |data, _| {
///     for x in data.iter_mut() {
///         *x = x.sin();
///     }
/// });
/// # assert_eq!(v, w);
/// # }
/// ```
pub fn divide<T, F>(data: &mut [T], granularity: usize, operation: F) where
    T: Send,
    F: Fn(&mut [T], usize) + Sync,
{
    assert!(granularity > 0);

    let raw::Slice { data, len } = unsafe { mem::transmute::<_, raw::Slice<T>>(data) };
    let data = RawPtr(data);
    let op = RawPtr(&operation as *const _ as *const ());

    let threads = iter::range_step(0, len, granularity).map(|offset| {
        Thread::scoped(move || {
            // NB Is safe to send the slice/closure because the thread won't outlive this function
            let slice = raw::Slice {
                data: unsafe { data.0.offset(offset as isize) },
                len: cmp::min(granularity, len - offset)
            };
            let data = unsafe { mem::transmute::<_, &mut [T]>(slice) };
            let operation = unsafe { mem::transmute::<_, &F>(op.0) };

            (*operation)(data, offset);
        })
    }).collect::<Vec<_>>();

    for thread in threads.into_iter() {
        if thread.join().is_err() {
            panic!();
        }
    }
}

#[cfg(test)]
mod test {
    use quickcheck::TestResult;
    use std::iter;
    use std::rand::{Rng, XorShiftRng, self};

    #[quickcheck]
    fn clone(size: usize, granularity: usize) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut rng: XorShiftRng = rand::thread_rng().gen();
        let original = range(0, size).map(|_| rng.gen::<f64>()).collect::<Vec<_>>();
        let mut clone = iter::repeat(0f64).take(size).collect::<Vec<_>>();

        let original_slice = &*original;
        super::divide(&mut *clone, granularity, |data, offset| {
            for (i, x) in data.iter_mut().enumerate() {
                *x = original_slice[offset + i]
            }
        });

        TestResult::from_bool(original == clone)
    }

    #[quickcheck]
    fn new(size: usize, granularity: usize) -> TestResult {
        if granularity == 0 {
            return TestResult::discard();
        }

        let mut v = iter::repeat(None::<f64>).take(size).collect::<Vec<_>>();

        super::divide(&mut *v, granularity, |data, _| {
            let mut rng: XorShiftRng = rand::thread_rng().gen();

            for x in data.iter_mut() {
                *x = Some(rng.gen())
            }
        });

        TestResult::from_bool(v.iter().all(|&x| match x {
            None => false,
            Some(x) => x > 0. && x < 1.
        }))
    }
}
<|endoftext|>


<commit_before>extern crate cgmath;
extern crate png;

use std::default::Default;
use std::f64;
use time;

use cgmath::{Matrix4, Point, Point3, Vector3};
use noise;
use noise::{Brownian3, Seed};

#[cfg(target_os = "android")]
use egl_context::EglContext;
use gl;
use gl::Texture;
use mesh;
use program::Program;
use vertices::Vertices;
use world::{Block, World};
#[cfg(target_os = "linux")]
use x11::{PollEventsIterator, XWindow};

#[cfg(target_os = "android")]
pub struct EngineImpl {
  pub egl_context: Option<Box<EglContext>>,
  pub program: Option<Program>,
}

#[cfg(target_os = "android")]
impl Default for EngineImpl {
  fn default() -> EngineImpl {
    EngineImpl {
      egl_context: None,
      program: None,
    }
  }
}

#[cfg(target_os = "linux")]
pub struct EngineImpl {
  pub window: XWindow,
  pub program: Program,
}

pub struct Engine {
  engine_impl: EngineImpl,
  animating: bool,
  angle: f32,  // in degrees.
  /// GL projection matrix
  projection_matrix: Matrix4<f32>,
  /// Texture atlas.
  texture: Texture,
  world: World,
  position_indices: Vec<u16>,
}

impl Engine {
  #[cfg(target_os = "android")]
  pub fn new() -> Engine {
    Engine {
      engine_impl: Default::default(),
      animating: false,
      angle: 0.0,
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: generate_chunk_of_perlin(),
      position_indices: Vec::new(),
    }
  }

  #[cfg(target_os = "linux")]
  pub fn new(window: XWindow, program: Program) -> Engine {
    Engine {
      engine_impl: EngineImpl {
        window: window,
        program: program,
      },
      animating: false,
      angle: 0.0,
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: generate_chunk_of_perlin(),
      position_indices: Vec::new(),
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "android")]
  pub fn init(&mut self, egl_context: Box<EglContext>, texture_atlas_bytes: &[u8]) {
    self.engine_impl.egl_context = Some(egl_context);

    self.engine_impl.program = match Program::new() {
      Ok(p) => Some(p),
      Err(e) => panic!("Program failed: {:?}", e),
    };

    self.common_init(texture_atlas_bytes);

    if let Some(ref p) = self.engine_impl.program {
      p.set_texture_unit(0);
    }

    // Silly gymnastics to satisfy the borrow checker.
    let wh = if let Some(ref ec) = self.engine_impl.egl_context {
      Some((ec.width, ec.height))
    } else {
      None
    };
    if let Some((w, h)) = wh {
      self.set_viewport(w, h);
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "linux")]
  pub fn init(&mut self, texture_atlas_bytes: &[u8]) {
    self.common_init(texture_atlas_bytes);
    self.engine_impl.program.set_texture_unit(0);
  }

  fn common_init(&mut self, texture_atlas_bytes: &[u8]) {
    // Set the background clear color to sky blue.
    gl::clear_color(0.5, 0.69, 1.0, 1.0);

    // Enable reverse face culling.
    gl::enable(gl::CULL_FACE);
    // Enable depth test.
    gl::enable(gl::DEPTH_TEST);
    gl::depth_func(gl::LEQUAL);

    // Set up textures.
    self.texture = Engine::load_texture_atlas(texture_atlas_bytes);
    gl::active_texture(gl::TEXTURE0);
    gl::bind_texture_2d(self.texture);

    self.load_mesh();
  }

  #[cfg(target_os = "android")]
  fn load_mesh(&mut self) {
    let vertices = create_mesh_vertices(&self.world);
    if let Some(ref mut p) = self.engine_impl.program {
      p.set_vertices(&vertices);
    }
    self.position_indices = vertices.position_indices();
  }

  #[cfg(target_os = "linux")]
  fn load_mesh(&mut self) {
    let vertices = create_mesh_vertices(&self.world);
    self.engine_impl.program.set_vertices(&vertices);
    self.position_indices = vertices.position_indices();
  }

  pub fn set_viewport(&mut self, w: i32, h: i32) {
    gl::viewport(0, 0, w, h);
    self.projection_matrix = projection_matrix(w, h);
  }

  /// Load texture atlas from assets folder.
  fn load_texture_atlas(texture_atlas_bytes: &[u8]) -> Texture {
    let image = png::load_png_from_memory(texture_atlas_bytes)
      .unwrap_or_else(|s| panic!("load_png_from_memory() failed: {}", s));

    let pixels = match image.pixels {
      png::PixelsByColorType::RGBA8(v) => v,
      _ => {
        let color_type = match image.pixels {
            png::PixelsByColorType::K8(_) => "K8",
            png::PixelsByColorType::KA8(_) => "KA8",
            png::PixelsByColorType::RGB8(_) => "RGB8",
            png::PixelsByColorType::RGBA8(_) => panic!("Should not happen"),
        };
        panic!("Only RGBA8 image format supported, was: {}", color_type);
      }
    };

    let texture = gl::gen_texture();
    gl::bind_texture_2d(texture);
    gl::texture_2d_param(gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
    gl::texture_2d_param(gl::TEXTURE_MAG_FILTER, gl::LINEAR);
    gl::texture_2d_param(gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
    gl::texture_2d_param(gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
    gl::texture_2d_image_rgba(image.width as i32, image.height as i32, &pixels);
    gl::generate_mipmap_2d();
    gl::bind_texture_2d(0);

    texture
  }

  /// Draw a frame.
  #[cfg(target_os = "android")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    match self.engine_impl.egl_context {
      None => return,  // No display.
      Some(ref egl_context) => {
        gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

        match self.engine_impl.program {
          Some(ref p) => {
            // Compute the composite mvp_matrix and send it to program.  Model matrix
            // is always identity so instead of MVP = P * V * M just do MVP = P * V.
            let mvp_matrix = self.projection_matrix * view_matrix(self.angle);
            p.set_mvp_matrix(mvp_matrix);
            // Finally, draw the cube mesh.
            if self.position_indices.len() > 0 {
              // TODO: Switch to VBOs once it works for better performance!!!
              gl::draw_elements_triangles_u16(self.position_indices.len() as i32, &self.position_indices[0..]);
            }
          },
          None => panic!("Missing program, should never happen"),
        }

        egl_context.swap_buffers();
      }
    }
  }

  /// Draw a frame.
  #[cfg(target_os = "linux")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

    let p = &self.engine_impl.program;

    // Compute the composite mvp_matrix and send it to program.  Model matrix
    // is always identity so instead of MVP = P * V * M just do MVP = P * V.
    let mvp_matrix = self.projection_matrix * view_matrix(self.angle);
    p.set_mvp_matrix(mvp_matrix);

    // Finally, draw the cube mesh.
    if self.position_indices.len() > 0 {
      // TODO: Switch to VBOs once it works for better performance!!!
      gl::draw_elements_triangles_u16(self.position_indices.len() as i32, &self.position_indices[0..]);
    }

    self.engine_impl.window.swap_buffers();
    self.engine_impl.window.flush();
  }

  /// Update for time passed and draw a frame.
  pub fn update_draw(&mut self) {
    if self.animating {
      // Done processing events; draw next animation frame.
      // Do a complete rotation every 10 seconds, assuming 60 FPS.
      self.angle += 360.0 / 600.0;
      if self.angle > 360.0 {
        self.angle = 0.0;
      }

      // Drawing is throttled to the screen update rate, so there is no need to do timing here.
      self.draw();
    }
  }

  /// Terminate the engine.
  #[cfg(target_os = "android")]
  pub fn term(&mut self) {
    self.animating = false;
    // Drop the program and the EGL context.
    self.engine_impl = Default::default();
    log!("*** Renderer terminated");
  }

  /// Called when window gains input focus.
  pub fn gained_focus(&mut self) {
    self.animating = true;
  }

  /// Called when window loses input focus.
  pub fn lost_focus(&mut self) {
    self.animating = false;
  }

  #[cfg(target_os = "linux")]
  pub fn is_closed(&self) -> bool {
    self.engine_impl.window.is_closed()
  }

  #[cfg(target_os = "linux")]
  pub fn poll_events(&self) -> PollEventsIterator {
    self.engine_impl.window.poll_events()
  }
}

fn generate_chunk_of_perlin() -> World {
  let start_s = time::precise_time_s();

  let seed = Seed::new(1);
  let noise = Brownian3::new(noise::perlin3, 4).wavelength(16.0);

  let y_min = -8;
  let y_max = 7;
  let y_range = y_max - y_min;

  let mut min = f64::MAX;
  let mut max = f64::MIN;
  let mut world: World = Default::default();

  for y in y_min..(y_max + 1) {
    // Normalize into [0, 1].
    let normalized_y = (y as f64 - y_min as f64) / y_range as f64;
    for x in -8..8 {
      for z in -8..8 {
        let p = [x as f64, y as f64, z as f64];
        let val = noise.apply(&seed, &p);

        if val < min {
          min = val;
        }
        if val > max {
          max = val;
        }

        // Probablility to have a block added linearly increases from 0.0 at y_max to 1.0 at y_min.
        if 0.5 * (val + 1.0) >= normalized_y {
          world.add(Block::new(x, y, z));
        }
      }
    }
  }

  let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
  log!("*** Generating a chunk of perlin: {:.3}ms, {} blocks", spent_ms, world.len());
  log!("***   min = {}, max = {}", min, max);
  log!("***   world = {:?}", world);

  world
}

fn create_mesh_vertices(world: &World) -> Vertices {
  let mut vertices = Vertices::new(world.len());
  for block in world.iter() {
    // Eliminate definitely invisible faces, i.e. those between two neighboring cubes.
    for face in mesh::CUBE_FACES.iter() {
      if !world.contains(&block.add_v(&face.direction)) {
        vertices.add(&translate(&face.position_coords, block), &face.position_indices, &face.texture_coords);
      }
    }
  }
  vertices
}

/// Accepts vertex coordinates as a flat list: x, y, z, x, y, z, ...
/// Translates them along the vector corresponding to the block.
fn translate(coords: &[f32; 12], block: &Block) -> [f32; 12] {
  let x = block.x as f32;
  let y = block.y as f32;
  let z = block.z as f32;

  [
    coords[0] + x, coords[1] + y, coords[2] + z,
    coords[3] + x, coords[4] + y, coords[5] + z,
    coords[6] + x, coords[7] + y, coords[8] + z,
    coords[9] + x, coords[10] + y, coords[11] + z,
  ]
}

/// A view matrix, eye is on a 10.0 radius circle starting at (0.0, 2.1, 10.0),
/// rotating around (0, 1, 0) counter-clockwise and looking at (0, 2.1, 0).
fn view_matrix(angle: f32) -> Matrix4<f32> {
  let r = 13.0;
  let y = 2.1;  // 0.5 for half block under feet + 1.6 up to eye height.
  let (s, c) = angle.to_radians().sin_cos();
  let eye = Point3::new(r * s, y, r * c);
  let center = Point3::new(0.0, y, 0.0);
  let up = Vector3::new(0.0, 1.0, 0.0);
  Matrix4::look_at(&eye, &center, &up)
}

/// Perspective projection matrix as frustum matrix.
fn projection_matrix(width: i32, height: i32) -> Matrix4<f32> {
  let ratio = width as f32 / height as f32;
  let left = -ratio;
  let right = ratio;
  let bottom = -1.0;
  let top = 1.0;
  let near = 1.0;
  let far = 50.0;
  cgmath::frustum(left, right, bottom, top, near, far)
}
<commit_msg>Fix brokenness with many blocks.<commit_after>extern crate cgmath;
extern crate png;

use std::default::Default;
use std::f64;
use time;

use cgmath::{Matrix4, Point, Point3, Vector3};
use noise;
use noise::{Brownian3, Seed};

#[cfg(target_os = "android")]
use egl_context::EglContext;
use gl;
use gl::Texture;
use mesh;
use program::Program;
use vertices::Vertices;
use world::{Block, World};
#[cfg(target_os = "linux")]
use x11::{PollEventsIterator, XWindow};

#[cfg(target_os = "android")]
pub struct EngineImpl {
  pub egl_context: Option<Box<EglContext>>,
  pub program: Option<Program>,
}

#[cfg(target_os = "android")]
impl Default for EngineImpl {
  fn default() -> EngineImpl {
    EngineImpl {
      egl_context: None,
      program: None,
    }
  }
}

#[cfg(target_os = "linux")]
pub struct EngineImpl {
  pub window: XWindow,
  pub program: Program,
}

pub struct Engine {
  engine_impl: EngineImpl,
  animating: bool,
  angle: f32,  // in degrees.
  /// GL projection matrix
  projection_matrix: Matrix4<f32>,
  /// Texture atlas.
  texture: Texture,
  world: World,
  position_indices: Vec<u16>,
  // Important: need to save position and texture coordinates since OpenGL tries to reload them
  // from memory!
  vertices: Vertices,
}

impl Engine {
  #[cfg(target_os = "android")]
  pub fn new() -> Engine {
    Engine {
      engine_impl: Default::default(),
      animating: false,
      angle: 0.0,
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: generate_chunk_of_perlin(),
      position_indices: Vec::new(),
      vertices: Vertices::new(0),
    }
  }

  #[cfg(target_os = "linux")]
  pub fn new(window: XWindow, program: Program) -> Engine {
    Engine {
      engine_impl: EngineImpl {
        window: window,
        program: program,
      },
      animating: false,
      angle: 0.0,
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: generate_chunk_of_perlin(),
      position_indices: Vec::new(),
      vertices: Vertices::new(0),
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "android")]
  pub fn init(&mut self, egl_context: Box<EglContext>, texture_atlas_bytes: &[u8]) {
    self.engine_impl.egl_context = Some(egl_context);

    self.engine_impl.program = match Program::new() {
      Ok(p) => Some(p),
      Err(e) => panic!("Program failed: {:?}", e),
    };

    self.common_init(texture_atlas_bytes);

    if let Some(ref p) = self.engine_impl.program {
      p.set_texture_unit(0);
    }

    // Silly gymnastics to satisfy the borrow checker.
    let wh = if let Some(ref ec) = self.engine_impl.egl_context {
      Some((ec.width, ec.height))
    } else {
      None
    };
    if let Some((w, h)) = wh {
      self.set_viewport(w, h);
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "linux")]
  pub fn init(&mut self, texture_atlas_bytes: &[u8]) {
    self.common_init(texture_atlas_bytes);
    self.engine_impl.program.set_texture_unit(0);
  }

  fn common_init(&mut self, texture_atlas_bytes: &[u8]) {
    // Set the background clear color to sky blue.
    gl::clear_color(0.5, 0.69, 1.0, 1.0);

    // Enable reverse face culling.
    gl::enable(gl::CULL_FACE);
    // Enable depth test.
    gl::enable(gl::DEPTH_TEST);
    gl::depth_func(gl::LEQUAL);

    // Set up textures.
    self.texture = Engine::load_texture_atlas(texture_atlas_bytes);
    gl::active_texture(gl::TEXTURE0);
    gl::bind_texture_2d(self.texture);

    self.load_mesh();
  }

  #[cfg(target_os = "android")]
  fn load_mesh(&mut self) {
    let vertices = create_mesh_vertices(&self.world);
    if let Some(ref mut p) = self.engine_impl.program {
      p.set_vertices(&vertices);
    }
    self.position_indices = vertices.position_indices();
    self.vertices = vertices;
  }

  #[cfg(target_os = "linux")]
  fn load_mesh(&mut self) {
    let vertices = create_mesh_vertices(&self.world);
    self.engine_impl.program.set_vertices(&vertices);
    self.position_indices = vertices.position_indices();
    self.vertices = vertices;
  }

  pub fn set_viewport(&mut self, w: i32, h: i32) {
    gl::viewport(0, 0, w, h);
    self.projection_matrix = projection_matrix(w, h);
  }

  /// Load texture atlas from assets folder.
  fn load_texture_atlas(texture_atlas_bytes: &[u8]) -> Texture {
    let image = png::load_png_from_memory(texture_atlas_bytes)
      .unwrap_or_else(|s| panic!("load_png_from_memory() failed: {}", s));

    let pixels = match image.pixels {
      png::PixelsByColorType::RGBA8(v) => v,
      _ => {
        let color_type = match image.pixels {
            png::PixelsByColorType::K8(_) => "K8",
            png::PixelsByColorType::KA8(_) => "KA8",
            png::PixelsByColorType::RGB8(_) => "RGB8",
            png::PixelsByColorType::RGBA8(_) => panic!("Should not happen"),
        };
        panic!("Only RGBA8 image format supported, was: {}", color_type);
      }
    };

    let texture = gl::gen_texture();
    gl::bind_texture_2d(texture);
    gl::texture_2d_param(gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR);
    gl::texture_2d_param(gl::TEXTURE_MAG_FILTER, gl::LINEAR);
    gl::texture_2d_param(gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
    gl::texture_2d_param(gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
    gl::texture_2d_image_rgba(image.width as i32, image.height as i32, &pixels);
    gl::generate_mipmap_2d();
    gl::bind_texture_2d(0);

    texture
  }

  /// Draw a frame.
  #[cfg(target_os = "android")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    match self.engine_impl.egl_context {
      None => return,  // No display.
      Some(ref egl_context) => {
        gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

        match self.engine_impl.program {
          Some(ref p) => {
            // Compute the composite mvp_matrix and send it to program.  Model matrix
            // is always identity so instead of MVP = P * V * M just do MVP = P * V.
            let mvp_matrix = self.projection_matrix * view_matrix(self.angle);
            p.set_mvp_matrix(mvp_matrix);
            // Finally, draw the cube mesh.
            if self.position_indices.len() > 0 {
              // TODO: Switch to VBOs once it works for better performance!!!
              gl::draw_elements_triangles_u16(self.position_indices.len() as i32, &self.position_indices[0..]);
            }
          },
          None => panic!("Missing program, should never happen"),
        }

        egl_context.swap_buffers();
      }
    }
  }

  /// Draw a frame.
  #[cfg(target_os = "linux")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

    let p = &self.engine_impl.program;

    // Compute the composite mvp_matrix and send it to program.  Model matrix
    // is always identity so instead of MVP = P * V * M just do MVP = P * V.
    let mvp_matrix = self.projection_matrix * view_matrix(self.angle);
    p.set_mvp_matrix(mvp_matrix);

    // Finally, draw the cube mesh.
    if self.position_indices.len() > 0 {
      // TODO: Switch to VBOs once it works for better performance!!!
      gl::draw_elements_triangles_u16(self.position_indices.len() as i32, &self.position_indices[0..]);
    }

    self.engine_impl.window.swap_buffers();
    self.engine_impl.window.flush();
  }

  /// Update for time passed and draw a frame.
  pub fn update_draw(&mut self) {
    if self.animating {
      // Done processing events; draw next animation frame.
      // Do a complete rotation every 10 seconds, assuming 60 FPS.
      self.angle += 360.0 / 600.0;
      if self.angle > 360.0 {
        self.angle = 0.0;
      }

      // Drawing is throttled to the screen update rate, so there is no need to do timing here.
      self.draw();
    }
  }

  /// Terminate the engine.
  #[cfg(target_os = "android")]
  pub fn term(&mut self) {
    self.animating = false;
    // Drop the program and the EGL context.
    self.engine_impl = Default::default();
    log!("*** Renderer terminated");
  }

  /// Called when window gains input focus.
  pub fn gained_focus(&mut self) {
    self.animating = true;
  }

  /// Called when window loses input focus.
  pub fn lost_focus(&mut self) {
    self.animating = false;
  }

  #[cfg(target_os = "linux")]
  pub fn is_closed(&self) -> bool {
    self.engine_impl.window.is_closed()
  }

  #[cfg(target_os = "linux")]
  pub fn poll_events(&self) -> PollEventsIterator {
    self.engine_impl.window.poll_events()
  }
}

fn generate_chunk_of_perlin() -> World {
  let start_s = time::precise_time_s();

  let seed = Seed::new(1);
  let noise = Brownian3::new(noise::perlin3, 4).wavelength(16.0);

  let y_min = -8;
  let y_max = 7;
  let y_range = y_max - y_min;

  let mut min = f64::MAX;
  let mut max = f64::MIN;
  let mut world: World = Default::default();

  for y in y_min..(y_max + 1) {
    // Normalize into [0, 1].
    let normalized_y = (y as f64 - y_min as f64) / y_range as f64;
    for x in -8..8 {
      for z in -8..8 {
        let p = [x as f64, y as f64, z as f64];
        let val = noise.apply(&seed, &p);

        if val < min {
          min = val;
        }
        if val > max {
          max = val;
        }

        // Probablility to have a block added linearly increases from 0.0 at y_max to 1.0 at y_min.
        if 0.5 * (val + 1.0) >= normalized_y {
          world.add(Block::new(x, y, z));
        }
      }
    }
  }

  let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
  log!("*** Generating a chunk of perlin: {:.3}ms, {} blocks", spent_ms, world.len());
  log!("***   min = {}, max = {}", min, max);
  log!("***   world = {:?}", world);

  world
}

fn create_mesh_vertices(world: &World) -> Vertices {
  let mut vertices = Vertices::new(world.len());
  for block in world.iter() {
    // Eliminate definitely invisible faces, i.e. those between two neighboring cubes.
    for face in mesh::CUBE_FACES.iter() {
      if !world.contains(&block.add_v(&face.direction)) {
        vertices.add(&translate(&face.position_coords, block), &face.position_indices, &face.texture_coords);
      }
    }
  }
  vertices
}

/// Accepts vertex coordinates as a flat list: x, y, z, x, y, z, ...
/// Translates them along the vector corresponding to the block.
fn translate(coords: &[f32; 12], block: &Block) -> [f32; 12] {
  let x = block.x as f32;
  let y = block.y as f32;
  let z = block.z as f32;

  [
    coords[0] + x, coords[1] + y, coords[2] + z,
    coords[3] + x, coords[4] + y, coords[5] + z,
    coords[6] + x, coords[7] + y, coords[8] + z,
    coords[9] + x, coords[10] + y, coords[11] + z,
  ]
}

/// A view matrix, eye is on a 10.0 radius circle starting at (0.0, 2.1, 10.0),
/// rotating around (0, 1, 0) counter-clockwise and looking at (0, 2.1, 0).
fn view_matrix(angle: f32) -> Matrix4<f32> {
  let r = 13.0;
  let y = 2.1;  // 0.5 for half block under feet + 1.6 up to eye height.
  let (s, c) = angle.to_radians().sin_cos();
  let eye = Point3::new(r * s, y, r * c);
  let center = Point3::new(0.0, y, 0.0);
  let up = Vector3::new(0.0, 1.0, 0.0);
  Matrix4::look_at(&eye, &center, &up)
}

/// Perspective projection matrix as frustum matrix.
fn projection_matrix(width: i32, height: i32) -> Matrix4<f32> {
  let ratio = width as f32 / height as f32;
  let left = -ratio;
  let right = ratio;
  let bottom = -1.0;
  let top = 1.0;
  let near = 1.0;
  let far = 50.0;
  cgmath::frustum(left, right, bottom, top, near, far)
}
<|endoftext|>


<commit_before>//! Define table formatting utilities

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

use encode_unicode::Utf8Char;

use super::utils::NEWLINE;

/// Alignment for cell's content
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum Alignment {
	LEFT,
	CENTER,
	RIGHT
}

/// Position of a line separator in a table
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum LinePosition {
	Top,
	Title,
	Intern,
	Bottom
}

/// Position of a column separator in a row
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum ColumnPosition {
	Left,
	Intern,
	Right
}

/// Contains the character used for printing a line separator
#[derive(Clone, Debug, Copy)]
pub struct LineSeparator {
	/// Line separator
	line: char,
	/// Internal junction separator
	junc: char,
	/// Left junction separator
	ljunc: char,
	/// Right junction separator
	rjunc: char
}

impl LineSeparator {

	/// Create a new line separator instance where `line` is the character used to separate 2 lines
	/// and `junc` is the one used for junctions between columns and lines
	pub fn new(line: char, junc: char, ljunc: char, rjunc: char) -> LineSeparator {
		LineSeparator{line: line, junc: junc, ljunc: ljunc, rjunc: rjunc}
	}

	/// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
	pub fn print<T: Write+?Sized>(&self, out: &mut T, col_width: &[usize], colsep: bool, lborder: bool, rborder: bool) -> Result<(), Error> {
		if lborder {
			try!(out.write_all(Utf8Char::from(self.ljunc).as_bytes()));
		}
		let mut iter = col_width.into_iter().peekable();
		while let Some(width) = iter.next() {
			for _ in 0..width+2 {
				try!(out.write_all(Utf8Char::from(self.line).as_bytes()));
			}
			if colsep && iter.peek().is_some() {
				try!(out.write_all(Utf8Char::from(self.junc).as_bytes()));
			}
		}
		if rborder {
			try!(out.write_all(Utf8Char::from(self.rjunc).as_bytes()));
		}
		out.write_all(NEWLINE)
	}
}

impl Default for LineSeparator {
	fn default() -> Self {
		LineSeparator::new('-', '+', '+', '+')
	}
}

/// Contains the table formatting rules
#[derive(Clone, Debug, Copy)]
pub struct TableFormat {
	/// Optional column separator character
	csep: Option<char>,
	/// Optional left border character
	lborder: Option<char>,
	/// Optional right border character
	rborder: Option<char>,
	/// Optional internal line separator
	lsep: Option<LineSeparator>,
	/// Optional title line separator
	tsep: Option<LineSeparator>,
	/// Optional top line separator
	top_sep: Option<LineSeparator>,
	/// Optional bottom line separator
	bottom_sep: Option<LineSeparator>,
	/// Left padding
	pad_left: usize,
	/// Right padding
	pad_right: usize
}

impl TableFormat {

	/// Create a new empty TableFormat.
	pub fn new() -> TableFormat {
		 TableFormat{
			 csep: None,
			 lborder: None,
			 rborder: None,
			 lsep: None,
			 tsep: None,
			 top_sep: None,
			 bottom_sep: None,
			 pad_left: 0,
			 pad_right: 0
		 }
	}

	/// Return a tuple with left and right padding
	pub fn get_padding(&self) -> (usize, usize) {
		(self.pad_left, self.pad_right)
	}

	/// Set left and right padding
	pub fn padding(&mut self, left: usize, right: usize) {
		self.pad_left = left;
		self.pad_right = right;
	}

	/// Set the character used for internal column separation
	pub fn column_separator(&mut self, separator: char) {
		self.csep = Some(separator);
	}

	/// Set the character used for table borders
	pub fn borders(&mut self, border: char) {
		self.lborder = Some(border);
		self.rborder = Some(border);
	}

	/// Set a line separator
	pub fn separator(&mut self, what: LinePosition, separator: LineSeparator) {
		*match what {
			LinePosition::Top => &mut self.top_sep,
			LinePosition::Bottom => &mut self.bottom_sep,
			LinePosition::Title => &mut self.tsep,
			LinePosition::Intern => &mut self.lsep
		} = Some(separator);
	}

	/// Set format for multiple kind of line separator
	pub fn separators(&mut self, what: &[LinePosition], separator: LineSeparator) {
		for pos in what {
			self.separator(*pos, separator);
		}
	}

	fn get_sep_for_line(&self, pos: LinePosition) -> &Option<LineSeparator> {
		match pos {
			LinePosition::Intern => return &self.lsep,
			LinePosition::Top => return &self.top_sep,
			LinePosition::Bottom => return &self.bottom_sep,
			LinePosition::Title => match &self.tsep {
				s @ &Some(_) => s,
				&None => &self.lsep
			}
		}
	}

	/// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
	pub fn print_line_separator<T: Write+?Sized>(&self, out: &mut T, col_width: &[usize], pos: LinePosition) -> Result<(), Error> {
		match *self.get_sep_for_line(pos) {
			Some(ref l) => l.print(out, col_width, self.csep.is_some(), self.lborder.is_some(), self.rborder.is_some()),
			None => Ok(())
		}
	}

	pub fn get_column_separator(&self, pos: ColumnPosition) -> Option<char> {
		match pos {
			ColumnPosition::Left => self.lborder,
			ColumnPosition::Intern => self.csep,
			ColumnPosition::Right => self.rborder
		}
	}

	/// Print a column separator or a table border
	pub fn print_column_separator<T: Write+?Sized>(&self, out: &mut T, pos: ColumnPosition) -> Result<(), Error> {
		match self.get_column_separator(pos) {
			Some(s) => out.write_all(Utf8Char::from(s).as_bytes()),
			None => Ok(())
		}
	}
}

impl Default for TableFormat {
	fn default() -> Self {
		TableFormat::new()
	}
}

/// A builder to create a `TableFormat`
pub struct FormatBuilder {
	format: Box<TableFormat>
}

impl FormatBuilder {
	pub fn new() -> FormatBuilder {
		FormatBuilder {
			format: Box::new(TableFormat::new())
		}
	}

	/// Set left and right padding
	pub fn padding(mut self, left: usize, right: usize) -> Self {
		self.format.padding(left, right);
		self
	}

	/// Set the character used for internal column separation
	pub fn column_separator(mut self, separator: char) -> Self {
		self.format.column_separator(separator);
		self
	}

	/// Set the character used for table borders
	pub fn borders(mut self, border: char) -> Self {
		self.format.borders(border);
		self
	}

	/// Set a line separator format
	pub fn separator(mut self, what: LinePosition, separator: LineSeparator) -> Self {
		self.format.separator(what, separator);
		self
	}

	/// Set separator format for multiple kind of line separators
	pub fn separators(mut self, what: &[LinePosition], separator: LineSeparator) -> Self {
		self.format.separators(what, separator);
		self
	}

	/// Consume this builder and return the generated `TableFormat`
	pub fn build(self) -> TableFormat {
		*self.format
	}
}

/// Predifined formats. Those constants are lazily evaluated when
/// the corresponding struct is dereferenced
pub mod consts {
	use super::{TableFormat, LineSeparator, FormatBuilder, LinePosition};

	lazy_static! {
		/// A line separator made of `-` and `+`
		static ref MINUS_PLUS_SEP: LineSeparator = LineSeparator::new('-', '+', '+', '+');
		/// A line separator made of `=` and `+`
		static ref EQU_PLUS_SEP: LineSeparator = LineSeparator::new('=', '+', '+', '+');

		/// Default table format
		///
		/// # Example
		/// ```text
		/// +----+----+
		/// | T1 | T2 |
		/// +====+====+
		/// | a  | b  |
		/// +----+----+
		/// | d  | c  |
		/// +----+----+
		/// ```
		pub static ref FORMAT_DEFAULT: TableFormat = FormatBuilder::new()
																	.column_separator('|')
																	.borders('|')
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// Similar to `FORMAT_DEFAULT` but without special separator after title line
		///
		/// # Example
		/// ```text
		/// +----+----+
		/// | T1 | T2 |
		/// +----+----+
		/// | a  | b  |
		/// +----+----+
		/// | c  | d  |
		/// +----+----+
		/// ```
		pub static ref FORMAT_NO_TITLE: TableFormat = FormatBuilder::new()
																	.column_separator('|')
																	.borders('|')
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// With no line separator, but with title separator
		///
		/// # Example
		/// ```text
		/// +----+----+
		/// | T1 | T2 |
		/// +====+====+
		/// | a  | b  |
		/// | c  | d  |
		/// +----+----+
		/// ```
		pub static ref FORMAT_NO_LINESEP_WITH_TITLE: TableFormat = FormatBuilder::new()
																	.column_separator('|')
																	.borders('|')
																	.separator(LinePosition::Title, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// With no line or title separator
		///
		/// # Example
		/// ```text
		/// +----+----+
		/// | T1 | T2 |
		/// | a  | b  |
		/// | c  | d  |
		/// +----+----+
		/// ```
		pub static ref FORMAT_NO_LINESEP: TableFormat = FormatBuilder::new()
																	.column_separator('|')
																	.borders('|')
																	.padding(1, 1)
																	.build();

		/// No column separator
		///
		/// # Example
		/// ```text
		/// --------
		///  T1  T2
		/// ========
		///  a   b
		/// --------
		///  d   c
		/// --------
		/// ```
		pub static ref FORMAT_NO_COLSEP: TableFormat = FormatBuilder::new()
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// Format for printing a table without any separators (only alignment)
		///
		/// # Example
		/// ```text
		///  T1  T2
		///  a   b
		///  d   c
		/// ```
		pub static ref FORMAT_CLEAN: TableFormat = FormatBuilder::new()
																	.padding(1, 1)
																	.build();

		/// Format for a table with only external borders and title separator
		///
		/// # Example
		/// ```text
		/// +--------+
		/// | T1  T2 |
		/// +========+
		/// | a   b  |
		/// | c   d  |
		/// +--------+
		/// ```
		pub static ref FORMAT_BORDERS_ONLY: TableFormat = FormatBuilder::new()
																	.padding(1, 1)
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.borders('|')
																	.build();

		/// A table with no external border
		///
		/// # Example
		/// ```text
		///  T1 | T2
		/// ====+====
		///  a  | b
		/// ----+----
		///  c  | d
		/// ```
		pub static ref FORMAT_NO_BORDER: TableFormat = FormatBuilder::new()
																	.padding(1, 1)
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.column_separator('|')
																	.build();

		/// A table with no external border and no line separation
		///
		/// # Example
		/// ```text
		///  T1 | T2
		/// ----+----
		///  a  | b
		///  c  | d
		/// ```
		pub static ref FORMAT_NO_BORDER_LINE_SEPARATOR: TableFormat = FormatBuilder::new()
																	.padding(1, 1)
																	.separator(LinePosition::Title, *MINUS_PLUS_SEP)
																	.column_separator('|')
																	.build();
	}
}
<commit_msg>Fix predefined formats to match their descriptions<commit_after>//! Define table formatting utilities

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

use encode_unicode::Utf8Char;

use super::utils::NEWLINE;

/// Alignment for cell's content
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum Alignment {
	LEFT,
	CENTER,
	RIGHT
}

/// Position of a line separator in a table
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum LinePosition {
	Top,
	Title,
	Intern,
	Bottom
}

/// Position of a column separator in a row
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum ColumnPosition {
	Left,
	Intern,
	Right
}

/// Contains the character used for printing a line separator
#[derive(Clone, Debug, Copy)]
pub struct LineSeparator {
	/// Line separator
	line: char,
	/// Internal junction separator
	junc: char,
	/// Left junction separator
	ljunc: char,
	/// Right junction separator
	rjunc: char
}

impl LineSeparator {

	/// Create a new line separator instance where `line` is the character used to separate 2 lines
	/// and `junc` is the one used for junctions between columns and lines
	pub fn new(line: char, junc: char, ljunc: char, rjunc: char) -> LineSeparator {
		LineSeparator{line: line, junc: junc, ljunc: ljunc, rjunc: rjunc}
	}

	/// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
	pub fn print<T: Write+?Sized>(&self, out: &mut T, col_width: &[usize], colsep: bool, lborder: bool, rborder: bool) -> Result<(), Error> {
		if lborder {
			try!(out.write_all(Utf8Char::from(self.ljunc).as_bytes()));
		}
		let mut iter = col_width.into_iter().peekable();
		while let Some(width) = iter.next() {
			for _ in 0..width+2 {
				try!(out.write_all(Utf8Char::from(self.line).as_bytes()));
			}
			if colsep && iter.peek().is_some() {
				try!(out.write_all(Utf8Char::from(self.junc).as_bytes()));
			}
		}
		if rborder {
			try!(out.write_all(Utf8Char::from(self.rjunc).as_bytes()));
		}
		out.write_all(NEWLINE)
	}
}

impl Default for LineSeparator {
	fn default() -> Self {
		LineSeparator::new('-', '+', '+', '+')
	}
}

/// Contains the table formatting rules
#[derive(Clone, Debug, Copy)]
pub struct TableFormat {
	/// Optional column separator character
	csep: Option<char>,
	/// Optional left border character
	lborder: Option<char>,
	/// Optional right border character
	rborder: Option<char>,
	/// Optional internal line separator
	lsep: Option<LineSeparator>,
	/// Optional title line separator
	tsep: Option<LineSeparator>,
	/// Optional top line separator
	top_sep: Option<LineSeparator>,
	/// Optional bottom line separator
	bottom_sep: Option<LineSeparator>,
	/// Left padding
	pad_left: usize,
	/// Right padding
	pad_right: usize
}

impl TableFormat {

	/// Create a new empty TableFormat.
	pub fn new() -> TableFormat {
		 TableFormat{
			 csep: None,
			 lborder: None,
			 rborder: None,
			 lsep: None,
			 tsep: None,
			 top_sep: None,
			 bottom_sep: None,
			 pad_left: 0,
			 pad_right: 0
		 }
	}

	/// Return a tuple with left and right padding
	pub fn get_padding(&self) -> (usize, usize) {
		(self.pad_left, self.pad_right)
	}

	/// Set left and right padding
	pub fn padding(&mut self, left: usize, right: usize) {
		self.pad_left = left;
		self.pad_right = right;
	}

	/// Set the character used for internal column separation
	pub fn column_separator(&mut self, separator: char) {
		self.csep = Some(separator);
	}

	/// Set the character used for table borders
	pub fn borders(&mut self, border: char) {
		self.lborder = Some(border);
		self.rborder = Some(border);
	}

	/// Set a line separator
	pub fn separator(&mut self, what: LinePosition, separator: LineSeparator) {
		*match what {
			LinePosition::Top => &mut self.top_sep,
			LinePosition::Bottom => &mut self.bottom_sep,
			LinePosition::Title => &mut self.tsep,
			LinePosition::Intern => &mut self.lsep
		} = Some(separator);
	}

	/// Set format for multiple kind of line separator
	pub fn separators(&mut self, what: &[LinePosition], separator: LineSeparator) {
		for pos in what {
			self.separator(*pos, separator);
		}
	}

	fn get_sep_for_line(&self, pos: LinePosition) -> &Option<LineSeparator> {
		match pos {
			LinePosition::Intern => return &self.lsep,
			LinePosition::Top => return &self.top_sep,
			LinePosition::Bottom => return &self.bottom_sep,
			LinePosition::Title => match &self.tsep {
				s @ &Some(_) => s,
				&None => &self.lsep
			}
		}
	}

	/// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
	pub fn print_line_separator<T: Write+?Sized>(&self, out: &mut T, col_width: &[usize], pos: LinePosition) -> Result<(), Error> {
		match *self.get_sep_for_line(pos) {
			Some(ref l) => l.print(out, col_width, self.csep.is_some(), self.lborder.is_some(), self.rborder.is_some()),
			None => Ok(())
		}
	}

	pub fn get_column_separator(&self, pos: ColumnPosition) -> Option<char> {
		match pos {
			ColumnPosition::Left => self.lborder,
			ColumnPosition::Intern => self.csep,
			ColumnPosition::Right => self.rborder
		}
	}

	/// Print a column separator or a table border
	pub fn print_column_separator<T: Write+?Sized>(&self, out: &mut T, pos: ColumnPosition) -> Result<(), Error> {
		match self.get_column_separator(pos) {
			Some(s) => out.write_all(Utf8Char::from(s).as_bytes()),
			None => Ok(())
		}
	}
}

impl Default for TableFormat {
	fn default() -> Self {
		TableFormat::new()
	}
}

/// A builder to create a `TableFormat`
pub struct FormatBuilder {
	format: Box<TableFormat>
}

impl FormatBuilder {
	pub fn new() -> FormatBuilder {
		FormatBuilder {
			format: Box::new(TableFormat::new())
		}
	}

	/// Set left and right padding
	pub fn padding(mut self, left: usize, right: usize) -> Self {
		self.format.padding(left, right);
		self
	}

	/// Set the character used for internal column separation
	pub fn column_separator(mut self, separator: char) -> Self {
		self.format.column_separator(separator);
		self
	}

	/// Set the character used for table borders
	pub fn borders(mut self, border: char) -> Self {
		self.format.borders(border);
		self
	}

	/// Set a line separator format
	pub fn separator(mut self, what: LinePosition, separator: LineSeparator) -> Self {
		self.format.separator(what, separator);
		self
	}

	/// Set separator format for multiple kind of line separators
	pub fn separators(mut self, what: &[LinePosition], separator: LineSeparator) -> Self {
		self.format.separators(what, separator);
		self
	}

	/// Consume this builder and return the generated `TableFormat`
	pub fn build(self) -> TableFormat {
		*self.format
	}
}

/// Predifined formats. Those constants are lazily evaluated when
/// the corresponding struct is dereferenced
pub mod consts {
	use super::{TableFormat, LineSeparator, FormatBuilder, LinePosition};

	lazy_static! {
		/// A line separator made of `-` and `+`
		static ref MINUS_PLUS_SEP: LineSeparator = LineSeparator::new('-', '+', '+', '+');
		/// A line separator made of `=` and `+`
		static ref EQU_PLUS_SEP: LineSeparator = LineSeparator::new('=', '+', '+', '+');

		/// Default table format
		///
		/// # Example
		/// ```text
		/// +----+----+
		/// | T1 | T2 |
		/// +====+====+
		/// | a  | b  |
		/// +----+----+
		/// | d  | c  |
		/// +----+----+
		/// ```
		pub static ref FORMAT_DEFAULT: TableFormat = FormatBuilder::new()
																	.column_separator('|')
																	.borders('|')
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// Similar to `FORMAT_DEFAULT` but without special separator after title line
		///
		/// # Example
		/// ```text
		/// +----+----+
		/// | T1 | T2 |
		/// +----+----+
		/// | a  | b  |
		/// +----+----+
		/// | c  | d  |
		/// +----+----+
		/// ```
		pub static ref FORMAT_NO_TITLE: TableFormat = FormatBuilder::new()
																	.column_separator('|')
																	.borders('|')
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// With no line separator, but with title separator
		///
		/// # Example
		/// ```text
		/// +----+----+
		/// | T1 | T2 |
		/// +====+====+
		/// | a  | b  |
		/// | c  | d  |
		/// +----+----+
		/// ```
		pub static ref FORMAT_NO_LINESEP_WITH_TITLE: TableFormat = FormatBuilder::new()
																	.column_separator('|')
																	.borders('|')
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// With no line or title separator
		///
		/// # Example
		/// ```text
		/// +----+----+
		/// | T1 | T2 |
		/// | a  | b  |
		/// | c  | d  |
		/// +----+----+
		/// ```
		pub static ref FORMAT_NO_LINESEP: TableFormat = FormatBuilder::new()
																	.column_separator('|')
																	.borders('|')
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// No column separator
		///
		/// # Example
		/// ```text
		/// --------
		///  T1  T2
		/// ========
		///  a   b
		/// --------
		///  d   c
		/// --------
		/// ```
		pub static ref FORMAT_NO_COLSEP: TableFormat = FormatBuilder::new()
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.padding(1, 1)
																	.build();

		/// Format for printing a table without any separators (only alignment)
		///
		/// # Example
		/// ```text
		///  T1  T2
		///  a   b
		///  d   c
		/// ```
		pub static ref FORMAT_CLEAN: TableFormat = FormatBuilder::new()
																	.padding(1, 1)
																	.build();

		/// Format for a table with only external borders and title separator
		///
		/// # Example
		/// ```text
		/// +--------+
		/// | T1  T2 |
		/// +========+
		/// | a   b  |
		/// | c   d  |
		/// +--------+
		/// ```
		pub static ref FORMAT_BORDERS_ONLY: TableFormat = FormatBuilder::new()
																	.padding(1, 1)
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Top, *MINUS_PLUS_SEP)
																	.borders('|')
																	.build();

		/// A table with no external border
		///
		/// # Example
		/// ```text
		///  T1 | T2
		/// ====+====
		///  a  | b
		/// ----+----
		///  c  | d
		/// ```
		pub static ref FORMAT_NO_BORDER: TableFormat = FormatBuilder::new()
																	.padding(1, 1)
																	.separator(LinePosition::Intern, *MINUS_PLUS_SEP)
																	.separator(LinePosition::Title, *EQU_PLUS_SEP)
																	.column_separator('|')
																	.build();

		/// A table with no external border and no line separation
		///
		/// # Example
		/// ```text
		///  T1 | T2
		/// ----+----
		///  a  | b
		///  c  | d
		/// ```
		pub static ref FORMAT_NO_BORDER_LINE_SEPARATOR: TableFormat = FormatBuilder::new()
																	.padding(1, 1)
																	.separator(LinePosition::Title, *MINUS_PLUS_SEP)
																	.column_separator('|')
																	.build();
	}
}
<|endoftext|>


<commit_before>use crate::parse_from_bytes;
use crate::reflect::MessageDescriptor;
use crate::well_known_types::Any;
use crate::Message;
use crate::ProtobufResult;

impl Any {
    fn get_type_url(type_url_prefix: &str, descriptor: &MessageDescriptor) -> String {
        format!("{}/{}", type_url_prefix, descriptor.full_name())
    }

    fn get_type_name_from_type_url(type_url: &str) -> Option<&str> {
        match type_url.rfind('/') {
            Some(i) => Some(&type_url[i + 1..]),
            None => None,
        }
    }

    /// Pack any message into `well_known_types::Any` value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use protobuf::Message;
    /// # use protobuf::ProtobufResult;
    /// use protobuf::well_known_types::Any;
    ///
    /// # fn the_test<MyMessage: Message>(message: &MyMessage) -> ProtobufResult<()> {
    /// let message: &MyMessage = message;
    /// let any = Any::pack(message)?;
    /// assert!(any.is::<MyMessage>());
    /// #   Ok(())
    /// # }
    /// ```
    pub fn pack<M: Message>(message: &M) -> ProtobufResult<Any> {
        Any::pack_dyn(message)
    }

    /// Pack any message into `well_known_types::Any` value.
    ///
    /// # Examples
    ///
    /// ```
    /// use protobuf::Message;
    /// # use protobuf::ProtobufResult;
    /// use protobuf::well_known_types::Any;
    ///
    /// # fn the_test(message: &dyn Message) -> ProtobufResult<()> {
    /// let message: &dyn Message = message;
    /// let any = Any::pack_dyn(message)?;
    /// assert!(any.is_dyn(message.descriptor()));
    /// #   Ok(())
    /// # }
    /// ```
    pub fn pack_dyn(message: &dyn Message) -> ProtobufResult<Any> {
        Any::pack_with_type_url_prefix(message, "type.googleapis.com")
    }

    fn pack_with_type_url_prefix(
        message: &dyn Message,
        type_url_prefix: &str,
    ) -> ProtobufResult<Any> {
        Ok(Any {
            type_url: Any::get_type_url(type_url_prefix, message.descriptor()),
            value: message.write_to_bytes()?,
            ..Default::default()
        })
    }

    /// Check if `Any` contains a message of given type.
    pub fn is<M: Message>(&self) -> bool {
        self.is_dyn(M::descriptor_static())
    }

    /// Check if `Any` contains a message of given type.
    pub fn is_dyn(&self, descriptor: &MessageDescriptor) -> bool {
        match Any::get_type_name_from_type_url(&self.type_url) {
            Some(type_name) => type_name == descriptor.full_name(),
            None => false,
        }
    }

    /// Extract a message from this `Any`.
    ///
    /// # Returns
    ///
    /// * `Ok(None)` when message type mismatch
    /// * `Err` when parse failed
    pub fn unpack<M: Message>(&self) -> ProtobufResult<Option<M>> {
        if !self.is::<M>() {
            return Ok(None);
        }
        Ok(Some(parse_from_bytes(&self.value)?))
    }

    /// Extract a message from this `Any`.
    ///
    /// # Returns
    ///
    /// * `Ok(None)` when message type mismatch
    /// * `Err` when parse failed
    pub fn unpack_dyn(
        &self,
        descriptor: &MessageDescriptor,
    ) -> ProtobufResult<Option<Box<dyn Message>>> {
        if !self.is_dyn(descriptor) {
            return Ok(None);
        }
        let mut message = descriptor.new_instance();
        message.merge_from_bytes(&self.value)?;
        message.check_initialized()?;
        Ok(Some(message))
    }
}
<commit_msg>Sync code from stable branch<commit_after>use crate::parse_from_bytes;
use crate::reflect::MessageDescriptor;
use crate::well_known_types::Any;
use crate::Message;
use crate::ProtobufResult;

impl Any {
    fn type_url(type_url_prefix: &str, descriptor: &MessageDescriptor) -> String {
        format!("{}/{}", type_url_prefix, descriptor.full_name())
    }

    fn get_type_name_from_type_url(type_url: &str) -> Option<&str> {
        match type_url.rfind('/') {
            Some(i) => Some(&type_url[i + 1..]),
            None => None,
        }
    }

    /// Pack any message into `well_known_types::Any` value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use protobuf::Message;
    /// # use protobuf::ProtobufResult;
    /// use protobuf::well_known_types::Any;
    ///
    /// # fn the_test<MyMessage: Message>(message: &MyMessage) -> ProtobufResult<()> {
    /// let message: &MyMessage = message;
    /// let any = Any::pack(message)?;
    /// assert!(any.is::<MyMessage>());
    /// #   Ok(())
    /// # }
    /// ```
    pub fn pack<M: Message>(message: &M) -> ProtobufResult<Any> {
        Any::pack_dyn(message)
    }

    /// Pack any message into `well_known_types::Any` value.
    ///
    /// # Examples
    ///
    /// ```
    /// use protobuf::Message;
    /// # use protobuf::ProtobufResult;
    /// use protobuf::well_known_types::Any;
    ///
    /// # fn the_test(message: &dyn Message) -> ProtobufResult<()> {
    /// let message: &dyn Message = message;
    /// let any = Any::pack_dyn(message)?;
    /// assert!(any.is_dyn(message.descriptor()));
    /// #   Ok(())
    /// # }
    /// ```
    pub fn pack_dyn(message: &dyn Message) -> ProtobufResult<Any> {
        Any::pack_with_type_url_prefix(message, "type.googleapis.com")
    }

    fn pack_with_type_url_prefix(
        message: &dyn Message,
        type_url_prefix: &str,
    ) -> ProtobufResult<Any> {
        Ok(Any {
            type_url: Any::type_url(type_url_prefix, message.descriptor()),
            value: message.write_to_bytes()?,
            ..Default::default()
        })
    }

    /// Check if `Any` contains a message of given type.
    pub fn is<M: Message>(&self) -> bool {
        self.is_dyn(M::descriptor_static())
    }

    /// Check if `Any` contains a message of given type.
    pub fn is_dyn(&self, descriptor: &MessageDescriptor) -> bool {
        match Any::get_type_name_from_type_url(&self.type_url) {
            Some(type_name) => type_name == descriptor.full_name(),
            None => false,
        }
    }

    /// Extract a message from this `Any`.
    ///
    /// # Returns
    ///
    /// * `Ok(None)` when message type mismatch
    /// * `Err` when parse failed
    pub fn unpack<M: Message>(&self) -> ProtobufResult<Option<M>> {
        if !self.is::<M>() {
            return Ok(None);
        }
        Ok(Some(parse_from_bytes(&self.value)?))
    }

    /// Extract a message from this `Any`.
    ///
    /// # Returns
    ///
    /// * `Ok(None)` when message type mismatch
    /// * `Err` when parse failed
    pub fn unpack_dyn(
        &self,
        descriptor: &MessageDescriptor,
    ) -> ProtobufResult<Option<Box<dyn Message>>> {
        if !self.is_dyn(descriptor) {
            return Ok(None);
        }
        let mut message = descriptor.new_instance();
        message.merge_from_bytes(&self.value)?;
        message.check_initialized()?;
        Ok(Some(message))
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;
extern crate tokio_process;

use std::env;
use std::sync::mpsc::channel;
use std::sync::{Once, ONCE_INIT};
use std::thread;

use tokio_core::{Loop, LoopHandle};
use tokio_process::Command;

static INIT: Once = ONCE_INIT;

fn init() {
    INIT.call_once(|| {
        let (tx, rx) = channel();
        thread::spawn(move || {
            let mut lp = Loop::new().unwrap();
            let cmd = exit(&lp.handle());
            let mut child = lp.run(cmd.spawn()).unwrap();
            drop(child.kill());
            lp.run(child).unwrap();
            tx.send(()).unwrap();
            drop(lp.run(futures::empty::<(), ()>()));
        });
        rx.recv().unwrap();
    });
}

fn exit(handle: &LoopHandle) -> Command {
    let mut me = env::current_exe().unwrap();
    me.pop();
    me.push("exit");
    Command::new(me, handle)
}

#[test]
fn simple() {
    init();

    let mut lp = Loop::new().unwrap();
    let mut cmd = exit(&lp.handle());
    cmd.arg("2");
    let mut child = lp.run(cmd.spawn()).unwrap();
    let id = child.id();
    assert!(id > 0);
    let status = lp.run(&mut child).unwrap();
    assert_eq!(status.code(), Some(2));
    assert_eq!(child.id(), id);
    assert!(child.kill().is_ok());
}
<commit_msg>process: Fix a test on Windows<commit_after>extern crate futures;
extern crate tokio_core;
extern crate tokio_process;

use std::env;
use std::sync::mpsc::channel;
use std::sync::{Once, ONCE_INIT};
use std::thread;

use tokio_core::{Loop, LoopHandle};
use tokio_process::Command;

static INIT: Once = ONCE_INIT;

fn init() {
    INIT.call_once(|| {
        let (tx, rx) = channel();
        thread::spawn(move || {
            let mut lp = Loop::new().unwrap();
            let cmd = exit(&lp.handle());
            let mut child = lp.run(cmd.spawn()).unwrap();
            drop(child.kill());
            lp.run(child).unwrap();
            tx.send(()).unwrap();
            drop(lp.run(futures::empty::<(), ()>()));
        });
        rx.recv().unwrap();
    });
}

fn exit(handle: &LoopHandle) -> Command {
    let mut me = env::current_exe().unwrap();
    me.pop();
    me.push("exit");
    Command::new(me, handle)
}

#[test]
fn simple() {
    init();

    let mut lp = Loop::new().unwrap();
    let mut cmd = exit(&lp.handle());
    cmd.arg("2");
    let mut child = lp.run(cmd.spawn()).unwrap();
    let id = child.id();
    assert!(id > 0);
    let status = lp.run(&mut child).unwrap();
    assert_eq!(status.code(), Some(2));
    assert_eq!(child.id(), id);
    drop(child.kill());
}
<|endoftext|>