<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, Arc};

use tempdir::TempDir;

use buffer::{Buffer, Mark};
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::from("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");
        }
    }
}
<commit_msg>fixed backspace not working when editing the last line of a buffer in standard mode<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, Arc};

use tempdir::TempDir;

use buffer::{Buffer, Mark};
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);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        {
            let buffer = self.buffer.lock().unwrap();
            let height = self.get_height() - 1;

            // FIXME: don't use unwrap here
            //        This will fail if for some reason the buffer doesnt have
            //        the top_line mark
            let lines = buffer.lines_from(self.top_line).unwrap().take(height);
            for (y_position, line) in lines.enumerate() {
                draw_line(&mut self.uibuf, line.as_slice(), y_position, self.left_col);
            }

        }
        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::from("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>//#![feature(trace_macros)]
#![allow(dead_code)]
#![cfg_attr(feature = "cargo-clippy", allow(redundant_closure))]

use nom::{error::ErrorKind, Err, IResult, Needed};

#[allow(dead_code)]
struct Range {
  start: char,
  end: char,
}

pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
  if !input.is_empty() {
    Ok((&input[1..], input[0] as char))
  } else {
    Err(Err::Incomplete(Needed::new(1)))
  }
}

#[cfg(feature = "std")]
mod parse_int {
  use nom::HexDisplay;
  use nom::{
    character::streaming::{digit1 as digit, space1 as space},
    combinator::{complete, map, opt},
    multi::many0,
    IResult,
  };
  use std::str;

  fn parse_ints(input: &[u8]) -> IResult<&[u8], Vec<i32>> {
    many0(spaces_or_int)(input)
  }

  fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32> {
    println!("{}", input.to_hex(8));
    let (i, _) = opt(complete(space))(input)?;
    let (i, res) = map(complete(digit), |x| {
      println!("x: {:?}", x);
      let result = str::from_utf8(x).unwrap();
      println!("Result: {}", result);
      println!("int is empty?: {}", x.is_empty());
      match result.parse() {
        Ok(i) => i,
        Err(e) => panic!("UH OH! NOT A DIGIT! {:?}", e),
      }
    })(i)?;

    Ok((i, res))
  }

  #[test]
  fn issue_142() {
    let subject = parse_ints(&b"12 34 5689a"[..]);
    let expected = Ok((&b"a"[..], vec![12, 34, 5689]));
    assert_eq!(subject, expected);

    let subject = parse_ints(&b"12 34 5689 "[..]);
    let expected = Ok((&b" "[..], vec![12, 34, 5689]));
    assert_eq!(subject, expected)
  }
}

#[test]
fn usize_length_bytes_issue() {
  use nom::multi::length_data;
  use nom::number::streaming::be_u16;
  let _: IResult<&[u8], &[u8], (&[u8], ErrorKind)> = length_data(be_u16)(b"012346");
}

#[test]
fn take_till_issue() {
  use nom::bytes::streaming::take_till;

  fn nothing(i: &[u8]) -> IResult<&[u8], &[u8]> {
    take_till(|_| true)(i)
  }

  assert_eq!(nothing(b""), Err(Err::Incomplete(Needed::new(1))));
  assert_eq!(nothing(b"abc"), Ok((&b"abc"[..], &b""[..])));
}

#[test]
fn issue_655() {
  use nom::character::streaming::{line_ending, not_line_ending};
  fn twolines(i: &str) -> IResult<&str, (&str, &str)> {
    let (i, l1) = not_line_ending(i)?;
    let (i, _) = line_ending(i)?;
    let (i, l2) = not_line_ending(i)?;
    let (i, _) = line_ending(i)?;

    Ok((i, (l1, l2)))
  }

  assert_eq!(twolines("foo\nbar\n"), Ok(("", ("foo", "bar"))));
  assert_eq!(twolines("féo\nbar\n"), Ok(("", ("féo", "bar"))));
  assert_eq!(twolines("foé\nbar\n"), Ok(("", ("foé", "bar"))));
  assert_eq!(twolines("foé\r\nbar\n"), Ok(("", ("foé", "bar"))));
}

#[cfg(feature = "alloc")]
fn issue_717(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
  use nom::bytes::complete::{is_not, tag};
  use nom::multi::separated_list0;

  separated_list0(tag([0x0]), is_not([0x0u8]))(i)
}

mod issue_647 {
  use nom::bytes::streaming::tag;
  use nom::combinator::complete;
  use nom::multi::separated_list0;
  use nom::{error::Error, number::streaming::be_f64, Err, IResult};
  pub type Input<'a> = &'a [u8];

  #[derive(PartialEq, Debug, Clone)]
  struct Data {
    c: f64,
    v: Vec<f64>,
  }

  fn list<'a, 'b>(
    input: Input<'a>,
    _cs: &'b f64,
  ) -> Result<(Input<'a>, Vec<f64>), Err<Error<&'a [u8]>>> {
    separated_list0(complete(tag(",")), complete(be_f64))(input)
  }

  fn data(input: Input<'_>) -> IResult<Input<'_>, Data> {
    let (i, c) = be_f64(input)?;
    let (i, _) = tag("\n")(i)?;
    let (i, v) = list(i, &c)?;
    Ok((i, Data { c, v }))
  }
}

#[test]
fn issue_848_overflow_incomplete_bits_to_bytes() {
  fn take(i: &[u8]) -> IResult<&[u8], &[u8]> {
    use nom::bytes::streaming::take;
    take(0x2000000000000000_usize)(i)
  }
  fn parser(i: &[u8]) -> IResult<&[u8], &[u8]> {
    use nom::bits::{bits, bytes};

    bits(bytes(take))(i)
  }
  assert_eq!(
    parser(&b""[..]),
    Err(Err::Failure(nom::error_position!(
      &b""[..],
      ErrorKind::TooLarge
    )))
  );
}

#[test]
fn issue_942() {
  use nom::error::{ContextError, ParseError};
  pub fn parser<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
    i: &'a str,
  ) -> IResult<&'a str, usize, E> {
    use nom::{character::complete::char, error::context, multi::many0_count};
    many0_count(context("char_a", char('a')))(i)
  }
  assert_eq!(parser::<()>("aaa"), Ok(("", 3)));
}

#[test]
fn issue_many_m_n_with_zeros() {
  use nom::character::complete::char;
  use nom::multi::many_m_n;
  let mut parser = many_m_n::<_, _, (), _>(0, 0, char('a'));
  assert_eq!(parser("aaa"), Ok(("aaa", vec![])));
}

#[test]
fn issue_1027_convert_error_panic_nonempty() {
  use nom::character::complete::char;
  use nom::error::{convert_error, VerboseError};
  use nom::sequence::pair;

  let input = "a";

  let result: IResult<_, _, VerboseError<&str>> = pair(char('a'), char('b'))(input);
  let err = match result.unwrap_err() {
    Err::Error(e) => e,
    _ => unreachable!(),
  };

  let msg = convert_error(input, err);
  assert_eq!(
    msg,
    "0: at line 1:\na\n ^\nexpected \'b\', got end of input\n\n"
  );
}

#[test]
fn issue_1231_bits_expect_fn_closure() {
  use nom::bits::{bits, complete::take};
  use nom::error::Error;
  use nom::sequence::tuple;
  pub fn example(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
    bits::<_, _, Error<_>, _, _>(tuple((take(1usize), take(1usize))))(input)
  }
  assert_eq!(example(&[0xff]), Ok((&b""[..], (1, 1))));
}

#[test]
fn issue_1282_findtoken_char() {
  use nom::character::complete::one_of;
  use nom::error::Error;
  let parser = one_of::<_, _, Error<_>>(['a', 'b', 'c'].as_slice());
  assert_eq!(parser("aaa"), Ok(("aa", 'a')));
}
<commit_msg>as_slice is not available on array in 1.48<commit_after>//#![feature(trace_macros)]
#![allow(dead_code)]
#![cfg_attr(feature = "cargo-clippy", allow(redundant_closure))]

use nom::{error::ErrorKind, Err, IResult, Needed};

#[allow(dead_code)]
struct Range {
  start: char,
  end: char,
}

pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
  if !input.is_empty() {
    Ok((&input[1..], input[0] as char))
  } else {
    Err(Err::Incomplete(Needed::new(1)))
  }
}

#[cfg(feature = "std")]
mod parse_int {
  use nom::HexDisplay;
  use nom::{
    character::streaming::{digit1 as digit, space1 as space},
    combinator::{complete, map, opt},
    multi::many0,
    IResult,
  };
  use std::str;

  fn parse_ints(input: &[u8]) -> IResult<&[u8], Vec<i32>> {
    many0(spaces_or_int)(input)
  }

  fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32> {
    println!("{}", input.to_hex(8));
    let (i, _) = opt(complete(space))(input)?;
    let (i, res) = map(complete(digit), |x| {
      println!("x: {:?}", x);
      let result = str::from_utf8(x).unwrap();
      println!("Result: {}", result);
      println!("int is empty?: {}", x.is_empty());
      match result.parse() {
        Ok(i) => i,
        Err(e) => panic!("UH OH! NOT A DIGIT! {:?}", e),
      }
    })(i)?;

    Ok((i, res))
  }

  #[test]
  fn issue_142() {
    let subject = parse_ints(&b"12 34 5689a"[..]);
    let expected = Ok((&b"a"[..], vec![12, 34, 5689]));
    assert_eq!(subject, expected);

    let subject = parse_ints(&b"12 34 5689 "[..]);
    let expected = Ok((&b" "[..], vec![12, 34, 5689]));
    assert_eq!(subject, expected)
  }
}

#[test]
fn usize_length_bytes_issue() {
  use nom::multi::length_data;
  use nom::number::streaming::be_u16;
  let _: IResult<&[u8], &[u8], (&[u8], ErrorKind)> = length_data(be_u16)(b"012346");
}

#[test]
fn take_till_issue() {
  use nom::bytes::streaming::take_till;

  fn nothing(i: &[u8]) -> IResult<&[u8], &[u8]> {
    take_till(|_| true)(i)
  }

  assert_eq!(nothing(b""), Err(Err::Incomplete(Needed::new(1))));
  assert_eq!(nothing(b"abc"), Ok((&b"abc"[..], &b""[..])));
}

#[test]
fn issue_655() {
  use nom::character::streaming::{line_ending, not_line_ending};
  fn twolines(i: &str) -> IResult<&str, (&str, &str)> {
    let (i, l1) = not_line_ending(i)?;
    let (i, _) = line_ending(i)?;
    let (i, l2) = not_line_ending(i)?;
    let (i, _) = line_ending(i)?;

    Ok((i, (l1, l2)))
  }

  assert_eq!(twolines("foo\nbar\n"), Ok(("", ("foo", "bar"))));
  assert_eq!(twolines("féo\nbar\n"), Ok(("", ("féo", "bar"))));
  assert_eq!(twolines("foé\nbar\n"), Ok(("", ("foé", "bar"))));
  assert_eq!(twolines("foé\r\nbar\n"), Ok(("", ("foé", "bar"))));
}

#[cfg(feature = "alloc")]
fn issue_717(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
  use nom::bytes::complete::{is_not, tag};
  use nom::multi::separated_list0;

  separated_list0(tag([0x0]), is_not([0x0u8]))(i)
}

mod issue_647 {
  use nom::bytes::streaming::tag;
  use nom::combinator::complete;
  use nom::multi::separated_list0;
  use nom::{error::Error, number::streaming::be_f64, Err, IResult};
  pub type Input<'a> = &'a [u8];

  #[derive(PartialEq, Debug, Clone)]
  struct Data {
    c: f64,
    v: Vec<f64>,
  }

  fn list<'a, 'b>(
    input: Input<'a>,
    _cs: &'b f64,
  ) -> Result<(Input<'a>, Vec<f64>), Err<Error<&'a [u8]>>> {
    separated_list0(complete(tag(",")), complete(be_f64))(input)
  }

  fn data(input: Input<'_>) -> IResult<Input<'_>, Data> {
    let (i, c) = be_f64(input)?;
    let (i, _) = tag("\n")(i)?;
    let (i, v) = list(i, &c)?;
    Ok((i, Data { c, v }))
  }
}

#[test]
fn issue_848_overflow_incomplete_bits_to_bytes() {
  fn take(i: &[u8]) -> IResult<&[u8], &[u8]> {
    use nom::bytes::streaming::take;
    take(0x2000000000000000_usize)(i)
  }
  fn parser(i: &[u8]) -> IResult<&[u8], &[u8]> {
    use nom::bits::{bits, bytes};

    bits(bytes(take))(i)
  }
  assert_eq!(
    parser(&b""[..]),
    Err(Err::Failure(nom::error_position!(
      &b""[..],
      ErrorKind::TooLarge
    )))
  );
}

#[test]
fn issue_942() {
  use nom::error::{ContextError, ParseError};
  pub fn parser<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
    i: &'a str,
  ) -> IResult<&'a str, usize, E> {
    use nom::{character::complete::char, error::context, multi::many0_count};
    many0_count(context("char_a", char('a')))(i)
  }
  assert_eq!(parser::<()>("aaa"), Ok(("", 3)));
}

#[test]
fn issue_many_m_n_with_zeros() {
  use nom::character::complete::char;
  use nom::multi::many_m_n;
  let mut parser = many_m_n::<_, _, (), _>(0, 0, char('a'));
  assert_eq!(parser("aaa"), Ok(("aaa", vec![])));
}

#[test]
fn issue_1027_convert_error_panic_nonempty() {
  use nom::character::complete::char;
  use nom::error::{convert_error, VerboseError};
  use nom::sequence::pair;

  let input = "a";

  let result: IResult<_, _, VerboseError<&str>> = pair(char('a'), char('b'))(input);
  let err = match result.unwrap_err() {
    Err::Error(e) => e,
    _ => unreachable!(),
  };

  let msg = convert_error(input, err);
  assert_eq!(
    msg,
    "0: at line 1:\na\n ^\nexpected \'b\', got end of input\n\n"
  );
}

#[test]
fn issue_1231_bits_expect_fn_closure() {
  use nom::bits::{bits, complete::take};
  use nom::error::Error;
  use nom::sequence::tuple;
  pub fn example(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
    bits::<_, _, Error<_>, _, _>(tuple((take(1usize), take(1usize))))(input)
  }
  assert_eq!(example(&[0xff]), Ok((&b""[..], (1, 1))));
}

#[test]
fn issue_1282_findtoken_char() {
  use nom::character::complete::one_of;
  use nom::error::Error;
  let parser = one_of::<_, _, Error<_>>(&['a', 'b', 'c'][..]);
  assert_eq!(parser("aaa"), Ok(("aa", 'a')));
}
<|endoftext|>


<commit_before>//#![feature(trace_macros)]
#[macro_use]
extern crate nom;
#[macro_use]
extern crate lazy_static;
extern crate regex;

use nom::{IResult,Needed,space,digit,be_u16,le_u64};

#[allow(dead_code)]
struct Range {
  start: char,
  end:   char
}

pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
  if input.len() > 0 {
    IResult::Done(&input[1..], input[0] as char)
  } else {
    IResult::Incomplete(Needed::Size(1))
  }
}

//trace_macros!(true);

#[allow(dead_code)]
named!(range<&[u8], Range>,
    alt!(
        do_parse!(
            start: take_char >>
            tag!("-")        >>
            end: take_char   >>
            (Range {
                start: start,
                end:   end,
            })
        ) |
        map!(
            take_char,
            |c| {
                Range {
                    start: c,
                    end:   c,
                }
            }
        )
    )
);

#[allow(dead_code)]
named!(literal<&[u8], Vec<char> >,
    map!(
        many1!(take_char),
        |cs| {
          cs
        }
    )
);

#[test]
fn issue_58() {
  range(&b"abcd"[..]);
  literal(&b"abcd"[..]);
}

//trace_macros!(false);

#[cfg(feature = "std")]
mod parse_int {
  use nom::HexDisplay;
  use nom::{IResult,Needed,space,digit,be_u16};
  use std::str;

  named!(parse_ints< Vec<i32> >, many0!(spaces_or_int));

  fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32>{
    println!("{}", input.to_hex(8));
    do_parse!(input,
      opt!(complete!(space)) >>
      res: map!(complete!(digit),
      |x| {
        println!("x: {:?}", x);
        let result = str::from_utf8(x).unwrap();
        println!("Result: {}", result);
        println!("int is empty?: {}", x.is_empty());
        match result.parse(){
          Ok(i) => i,
          Err(_) =>  panic!("UH OH! NOT A DIGIT!")
        }
      }) >>
      (res)
    )
  }

  #[test]
  fn issue_142(){
     let subject = parse_ints(&b"12 34 5689"[..]);
     let expected = IResult::Done(&b""[..], vec![12, 34, 5689]);
     assert_eq!(subject, expected);

     let subject = parse_ints(&b"12 34 5689 "[..]);
     let expected = IResult::Done(&b" "[..], vec![12, 34, 5689]);
     assert_eq!(subject, expected)
  }
}

#[test]
fn usize_length_bytes_issue(){
  length_bytes!(b"012346", be_u16);
}

/*
 DOES NOT COMPILE
#[test]
fn issue_152() {
  named!(take4, take!(4));
  named!(xyz, tag!("XYZ"));
  named!(abc, tag!("abc"));

  named!(sw,
    switch!(take4,
      b"abcd" => xyz |
      b"efgh" => abc
    )
  );
}
*/

#[test]
fn take_till_issue() {
    named!(nothing,
        take_till!(call!(|_| true))
    );

    assert_eq!(nothing(b""), IResult::Done(&b""[..], &b""[..]));
    assert_eq!(nothing(b"abc"), IResult::Done(&b"abc"[..], &b""[..]));
}

named!(issue_498< Vec<&[u8]> >, separated_nonempty_list!( opt!(space), tag!("abcd") ));

named!(issue_308(&str) -> bool,
    do_parse! (
        tag_s! ("foo") >>
        b: alt_complete! (
            map! (tag_s! ("1"), |_: &str|->bool {true}) |
            value! (false)
        ) >>
        (b) ));

fn issue_302(input: &[u8]) -> IResult<&[u8], Option<Vec<u64>> > {
    do_parse!(input,
        entries: cond!(true, count!(le_u64, 3)) >>
        ( entries )
    )
}

struct Node<'a> {
    prefix: Option<&'a str>,
    content: &'a str,
}

fn is_char(ch: char) -> bool {
    true
}

named!(parse_node<&str, Node>,
  do_parse!(
    prefix: opt!(re_find_static!(r"(\s*|(?m://.*$))*")) >>
    content: take_while_s!(is_char) >>
    (Node {prefix, content})
  )
);
<commit_msg>remove some warnings<commit_after>//#![feature(trace_macros)]
#[macro_use]
extern crate nom;
#[macro_use]
extern crate lazy_static;
extern crate regex;

use nom::{IResult,Needed,space,be_u16,le_u64};

#[allow(dead_code)]
struct Range {
  start: char,
  end:   char
}

pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
  if input.len() > 0 {
    IResult::Done(&input[1..], input[0] as char)
  } else {
    IResult::Incomplete(Needed::Size(1))
  }
}

//trace_macros!(true);

#[allow(dead_code)]
named!(range<&[u8], Range>,
    alt!(
        do_parse!(
            start: take_char >>
            tag!("-")        >>
            end: take_char   >>
            (Range {
                start: start,
                end:   end,
            })
        ) |
        map!(
            take_char,
            |c| {
                Range {
                    start: c,
                    end:   c,
                }
            }
        )
    )
);

#[allow(dead_code)]
named!(literal<&[u8], Vec<char> >,
    map!(
        many1!(take_char),
        |cs| {
          cs
        }
    )
);

#[test]
fn issue_58() {
  range(&b"abcd"[..]);
  literal(&b"abcd"[..]);
}

//trace_macros!(false);

#[cfg(feature = "std")]
mod parse_int {
  use nom::HexDisplay;
  use nom::{IResult,space,digit};
  use std::str;

  named!(parse_ints< Vec<i32> >, many0!(spaces_or_int));

  fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32>{
    println!("{}", input.to_hex(8));
    do_parse!(input,
      opt!(complete!(space)) >>
      res: map!(complete!(digit),
      |x| {
        println!("x: {:?}", x);
        let result = str::from_utf8(x).unwrap();
        println!("Result: {}", result);
        println!("int is empty?: {}", x.is_empty());
        match result.parse(){
          Ok(i) => i,
          Err(_) =>  panic!("UH OH! NOT A DIGIT!")
        }
      }) >>
      (res)
    )
  }

  #[test]
  fn issue_142(){
     let subject = parse_ints(&b"12 34 5689"[..]);
     let expected = IResult::Done(&b""[..], vec![12, 34, 5689]);
     assert_eq!(subject, expected);

     let subject = parse_ints(&b"12 34 5689 "[..]);
     let expected = IResult::Done(&b" "[..], vec![12, 34, 5689]);
     assert_eq!(subject, expected)
  }
}

#[test]
fn usize_length_bytes_issue(){
  length_bytes!(b"012346", be_u16);
}

/*
 DOES NOT COMPILE
#[test]
fn issue_152() {
  named!(take4, take!(4));
  named!(xyz, tag!("XYZ"));
  named!(abc, tag!("abc"));

  named!(sw,
    switch!(take4,
      b"abcd" => xyz |
      b"efgh" => abc
    )
  );
}
*/

#[test]
fn take_till_issue() {
    named!(nothing,
        take_till!(call!(|_| true))
    );

    assert_eq!(nothing(b""), IResult::Done(&b""[..], &b""[..]));
    assert_eq!(nothing(b"abc"), IResult::Done(&b"abc"[..], &b""[..]));
}

named!(issue_498< Vec<&[u8]> >, separated_nonempty_list!( opt!(space), tag!("abcd") ));

named!(issue_308(&str) -> bool,
    do_parse! (
        tag_s! ("foo") >>
        b: alt_complete! (
            map! (tag_s! ("1"), |_: &str|->bool {true}) |
            value! (false)
        ) >>
        (b) ));

fn issue_302(input: &[u8]) -> IResult<&[u8], Option<Vec<u64>> > {
    do_parse!(input,
        entries: cond!(true, count!(le_u64, 3)) >>
        ( entries )
    )
}

struct Node<'a> {
    prefix: Option<&'a str>,
    content: &'a str,
}

fn is_char(ch: char) -> bool {
    true
}

named!(parse_node<&str, Node>,
  do_parse!(
    prefix: opt!(re_find_static!(r"(\s*|(?m://.*$))*")) >>
    content: take_while_s!(is_char) >>
    (Node {prefix, content})
  )
);
<|endoftext|>


<commit_before>//! Module that defines the bindings for the patched redshift protocol.
//! See https://github.com/giucam/redshift/blob/master/src/gamma-control.xml
//! and https://github.com/jonls/redshift/issues/55
//! for more information about the spec and its status in regards to upstream.
use wayland::gamma_control::generated
    ::server::gamma_control::GammaControl;
use wayland::gamma_control::generated
    ::server::gamma_control_manager::GammaControlManager;
use rustwlc::wayland;
use rustwlc::handle::{wlc_handle_from_wl_output_resource, WlcOutput};
use rustwlc::render::{wlc_output_set_gamma, wlc_output_get_gamma_size};
use wayland_server::Resource;
use wayland_sys::common::{wl_array};
use wayland_sys::server::{WAYLAND_SERVER_HANDLE, wl_client, wl_resource};
use std::os::raw::c_void;
use nix::libc::{c_int, c_uint, uint32_t, uint16_t};
use std::sync::{Mutex};

static SET_GAMMA_ERROR: &'static str = "The gamma ramps don't have the same size!";
static INVALID_GAMMA_CODE: u32 = 0;

lazy_static!(
    static ref GAMMA_CONTROL_MANAGER: Mutex<GammaControlManagerInterface> =
        Mutex::new(GammaControlManagerInterface {
            destroy: destroy,
            get_gamma_control: get_gamma_control
        });
    static ref GAMMA_CONTROL: Mutex<GammaControlInterface> =
        Mutex::new(GammaControlInterface {
            destroy: destroy,
            set_gamma: set_gamma,
            reset_gamma: reset_gamma
        });
);

/// Generated modules from the XML protocol spec.
mod generated {
    // Generated code generally doesn't follow standards
    #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
    #![allow(non_upper_case_globals,non_snake_case,unused_imports)]

    pub mod interfaces {
        #[doc(hidden)]
        pub use wayland_server::protocol_interfaces::{wl_output_interface};
        include!(concat!(env!("OUT_DIR"), "/gamma-control_interface.rs"));
    }

    pub mod server {
        #[doc(hidden)]
        pub use wayland_server::{Resource, Handler,
                                 Client, Liveness,
                                 EventLoopHandle, EventResult};
        #[doc(hidden)]
        pub use wayland_server::protocol::{wl_output};
        #[doc(hidden)]
        pub use super::interfaces;
        include!(concat!(env!("OUT_DIR"), "/gamma-control_api.rs"));
    }
}

#[repr(C)]
/// Controls access to the gamma control interface.
/// Right now we let anyone through that wants to access it, but this
/// will allow us to limit who access to it in the future.
struct GammaControlManagerInterface {
    destroy: unsafe extern "C" fn (client: *mut wl_client,
                                   resource: *mut wl_resource),
    get_gamma_control: unsafe extern "C" fn (client: *mut wl_client,
                                             resource: *mut wl_resource,
                                             id: u32,
                                             output: *mut wl_resource)
}

#[repr(C)]
/// The interface that allows a client to control the gamma ramps.
struct GammaControlInterface {
    destroy: unsafe extern "C" fn (client: *mut wl_client,
                                   resource: *mut wl_resource),
    set_gamma: unsafe extern "C" fn (client: *mut wl_client,
                                     resource: *mut wl_resource,
                                     red: *mut wl_array,
                                     green: *mut wl_array,
                                     blue: *mut wl_array),
    reset_gamma: unsafe extern "C" fn (client: *mut wl_client,
                                       resource: *mut wl_resource)
}

/// Sets the gamma to the provided values.
/// If the sizes of the arrays are not all the same,
/// nothing is done and we post an error to the client
/// through the Wayland IPC.
unsafe extern "C" fn set_gamma(_client: *mut wl_client,
                               resource: *mut wl_resource,
                               red: *mut wl_array,
                               green: *mut wl_array,
                               blue: *mut wl_array) {
    debug!("Setting gamma");
    if (*red).size != (*green).size || (*red).size != (*blue).size {
        ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_resource_post_error,
            resource,
            INVALID_GAMMA_CODE,
            SET_GAMMA_ERROR.as_bytes().as_ptr() as *const i8);
        warn!("Color size error, can't continue");
        return
    }
    let r = (*red).data as *mut u16;
    let g = (*green).data as *mut u16;
    let b = (*blue).data as *mut u16;
    let user_data = ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_get_user_data,
        resource) as *const _;
    let output = WlcOutput(wlc_handle_from_wl_output_resource(user_data));
    // TODO Make this less stupid to check if it's a null index
    if output.as_view().is_root() {
        warn!("wl_resource didn't correspond to a wlc output");
        return;
    }
    wlc_output_set_gamma(output.0, ((*red).size / 2) as u16, r, g, b)

}

/// Resets the gamma to the original value set by the hardware.
/// This action is performed properly by `set_gamma`, so method only
/// logs that the action occured.
unsafe extern "C" fn reset_gamma(_client: *mut wl_client,
                                 _resource: *mut wl_resource) {
    debug!("Resetting gamma");
}

/// Destroys the wl_resource.
unsafe extern "C" fn destroy(_client: *mut wl_client,
                             resource: *mut wl_resource) {
    ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_destroy,
        resource
    );
}

/// The method that is called when a client attempts to access the gamma
/// control interface. If successful, this method grants access by
/// setting the implementation of the passed in wl_resource to the gamma
/// control singleton and responding to the client with the size of the gamma
/// ramps for the specified output.
unsafe extern "C" fn get_gamma_control(client: *mut wl_client,
                                       _resource: *mut wl_resource,
                                       id: uint32_t,
                                       output: *mut wl_resource) {
    debug!("Request received for control of the gamma ramps");
    let manager_resource = ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_create,
        client,
        GammaControl::interface_ptr(),
        GammaControl::supported_version() as i32,
        id);
    let wlc_output = WlcOutput(wlc_handle_from_wl_output_resource(output as *const _));
    // TODO Make this less stupid to check if it's a null index
    if wlc_output.as_view().is_root() {
        warn!("This is triggering, dis bad?");
        return;
    }
    debug!("Client requested control of the gamma ramps for {:?}", wlc_output);
    let mut gamma_control = GAMMA_CONTROL.try_lock().unwrap();
    let gamma_control_ptr = &mut *gamma_control as *mut _ as *mut c_void;
    ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_set_implementation,
        manager_resource,
        gamma_control_ptr,
        output as *mut c_void,
        None
    );
    debug!("Request granted for gamma ramp control of {:?}", wlc_output);
    gamma_control_send_gamma_size(manager_resource,
                                  wlc_output_get_gamma_size(wlc_output.0))
}

/// Binds the handler to a new Wayland resource, created by the client.
/// See https://github.com/vberger/wayland-rs/blob/451ccab330b3d0ec18eaaf72ae17ac35cf432370/wayland-server/src/event_loop.rs#L617
/// to see where I got this particular bit of magic from.
unsafe extern "C" fn bind(client: *mut wl_client,
                              _data: *mut c_void,
                              version: u32,
                              id: u32) {
    debug!("Binding Gamma Control resource");
    let cur_version = GammaControlManager::supported_version();
    if version > cur_version {
        warn!("Unsupported gamma control protocol version {}!", version);
        warn!("We only support version {}", cur_version);
        return
    }
    let resource = ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_create,
        client,
        GammaControlManager::interface_ptr(),
        version as c_int,
        id
    );
    if resource.is_null() {
        warn!("Out of memory, could not make a new wl_resource \
               for gamma control");
        ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_client_post_no_memory,
            client
        );
    }
    let mut manager = GAMMA_CONTROL_MANAGER.try_lock().unwrap();
    let global_manager_ptr = &mut *manager as *mut _ as *mut c_void;
    ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_set_implementation,
        resource,
        global_manager_ptr,
        ::std::ptr::null_mut(),
        None
    );
}

/// Send the size of the gamma ramps of the output specified by the wl_resource
/// to the client.
unsafe extern "C" fn gamma_control_send_gamma_size(resource: *mut wl_resource,
                                                   size: uint16_t) {
    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                  wl_resource_post_event,
                  resource,
                  0,
                  size as c_uint);
}

/// Sets up Way Cooler to announce it uses the gamma control interface.
pub fn init() {
    let w_display = wayland::get_display();
    unsafe {
        debug!("Initializing gamma control manager");
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_global_create,
                      w_display as *mut _,
                      GammaControlManager::interface_ptr(),
                      GammaControlManager::supported_version() as i32,
                      ::std::ptr::null_mut(),
                      bind
        );
    }
}

<commit_msg>Switched from lazy static to static vars<commit_after>//! Module that defines the bindings for the patched redshift protocol.
//! See https://github.com/giucam/redshift/blob/master/src/gamma-control.xml
//! and https://github.com/jonls/redshift/issues/55
//! for more information about the spec and its status in regards to upstream.
use wayland::gamma_control::generated
    ::server::gamma_control::GammaControl;
use wayland::gamma_control::generated
    ::server::gamma_control_manager::GammaControlManager;
use rustwlc::wayland;
use rustwlc::handle::{wlc_handle_from_wl_output_resource, WlcOutput};
use rustwlc::render::{wlc_output_set_gamma, wlc_output_get_gamma_size};
use wayland_server::Resource;
use wayland_sys::common::{wl_array};
use wayland_sys::server::{WAYLAND_SERVER_HANDLE, wl_client, wl_resource};
use std::os::raw::c_void;
use nix::libc::{c_int, c_uint, uint32_t, uint16_t};

static SET_GAMMA_ERROR: &'static str = "The gamma ramps don't have the same size!";
static INVALID_GAMMA_CODE: u32 = 0;

static mut GAMMA_CONTROL_MANAGER: GammaControlManagerInterface =
    GammaControlManagerInterface {
        destroy: destroy,
        get_gamma_control: get_gamma_control
    };

static mut GAMMA_CONTROL: GammaControlInterface =
    GammaControlInterface {
        destroy: destroy,
        set_gamma: set_gamma,
        reset_gamma: reset_gamma
    };

/// Generated modules from the XML protocol spec.
mod generated {
    // Generated code generally doesn't follow standards
    #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
    #![allow(non_upper_case_globals,non_snake_case,unused_imports)]

    pub mod interfaces {
        #[doc(hidden)]
        pub use wayland_server::protocol_interfaces::{wl_output_interface};
        include!(concat!(env!("OUT_DIR"), "/gamma-control_interface.rs"));
    }

    pub mod server {
        #[doc(hidden)]
        pub use wayland_server::{Resource, Handler,
                                 Client, Liveness,
                                 EventLoopHandle, EventResult};
        #[doc(hidden)]
        pub use wayland_server::protocol::{wl_output};
        #[doc(hidden)]
        pub use super::interfaces;
        include!(concat!(env!("OUT_DIR"), "/gamma-control_api.rs"));
    }
}

#[repr(C)]
/// Controls access to the gamma control interface.
/// Right now we let anyone through that wants to access it, but this
/// will allow us to limit who access to it in the future.
struct GammaControlManagerInterface {
    destroy: unsafe extern "C" fn (client: *mut wl_client,
                                   resource: *mut wl_resource),
    get_gamma_control: unsafe extern "C" fn (client: *mut wl_client,
                                             resource: *mut wl_resource,
                                             id: u32,
                                             output: *mut wl_resource)
}

#[repr(C)]
/// The interface that allows a client to control the gamma ramps.
struct GammaControlInterface {
    destroy: unsafe extern "C" fn (client: *mut wl_client,
                                   resource: *mut wl_resource),
    set_gamma: unsafe extern "C" fn (client: *mut wl_client,
                                     resource: *mut wl_resource,
                                     red: *mut wl_array,
                                     green: *mut wl_array,
                                     blue: *mut wl_array),
    reset_gamma: unsafe extern "C" fn (client: *mut wl_client,
                                       resource: *mut wl_resource)
}

/// Sets the gamma to the provided values.
/// If the sizes of the arrays are not all the same,
/// nothing is done and we post an error to the client
/// through the Wayland IPC.
unsafe extern "C" fn set_gamma(_client: *mut wl_client,
                               resource: *mut wl_resource,
                               red: *mut wl_array,
                               green: *mut wl_array,
                               blue: *mut wl_array) {
    debug!("Setting gamma");
    if (*red).size != (*green).size || (*red).size != (*blue).size {
        ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_resource_post_error,
            resource,
            INVALID_GAMMA_CODE,
            SET_GAMMA_ERROR.as_bytes().as_ptr() as *const i8);
        warn!("Color size error, can't continue");
        return
    }
    let r = (*red).data as *mut u16;
    let g = (*green).data as *mut u16;
    let b = (*blue).data as *mut u16;
    let user_data = ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_get_user_data,
        resource) as *const _;
    let output = WlcOutput(wlc_handle_from_wl_output_resource(user_data));
    // TODO Make this less stupid to check if it's a null index
    if output.as_view().is_root() {
        warn!("wl_resource didn't correspond to a wlc output");
        return;
    }
    wlc_output_set_gamma(output.0, ((*red).size / 2) as u16, r, g, b)

}

/// Resets the gamma to the original value set by the hardware.
/// This action is performed properly by `set_gamma`, so method only
/// logs that the action occured.
unsafe extern "C" fn reset_gamma(_client: *mut wl_client,
                                 _resource: *mut wl_resource) {
    debug!("Resetting gamma");
}

/// Destroys the wl_resource.
unsafe extern "C" fn destroy(_client: *mut wl_client,
                             resource: *mut wl_resource) {
    ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_destroy,
        resource
    );
}

/// The method that is called when a client attempts to access the gamma
/// control interface. If successful, this method grants access by
/// setting the implementation of the passed in wl_resource to the gamma
/// control singleton and responding to the client with the size of the gamma
/// ramps for the specified output.
unsafe extern "C" fn get_gamma_control(client: *mut wl_client,
                                       _resource: *mut wl_resource,
                                       id: uint32_t,
                                       output: *mut wl_resource) {
    debug!("Request received for control of the gamma ramps");
    let manager_resource = ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_create,
        client,
        GammaControl::interface_ptr(),
        GammaControl::supported_version() as i32,
        id);
    let wlc_output = WlcOutput(wlc_handle_from_wl_output_resource(output as *const _));
    // TODO Make this less stupid to check if it's a null index
    if wlc_output.as_view().is_root() {
        warn!("This is triggering, dis bad?");
        return;
    }
    debug!("Client requested control of the gamma ramps for {:?}", wlc_output);
    let gamma_control_ptr = &mut GAMMA_CONTROL as *mut _ as *mut c_void;
    ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_set_implementation,
        manager_resource,
        gamma_control_ptr,
        output as *mut c_void,
        None
    );
    debug!("Request granted for gamma ramp control of {:?}", wlc_output);
    gamma_control_send_gamma_size(manager_resource,
                                  wlc_output_get_gamma_size(wlc_output.0))
}

/// Binds the handler to a new Wayland resource, created by the client.
/// See https://github.com/vberger/wayland-rs/blob/451ccab330b3d0ec18eaaf72ae17ac35cf432370/wayland-server/src/event_loop.rs#L617
/// to see where I got this particular bit of magic from.
unsafe extern "C" fn bind(client: *mut wl_client,
                              _data: *mut c_void,
                              version: u32,
                              id: u32) {
    debug!("Binding Gamma Control resource");
    let cur_version = GammaControlManager::supported_version();
    if version > cur_version {
        warn!("Unsupported gamma control protocol version {}!", version);
        warn!("We only support version {}", cur_version);
        return
    }
    let resource = ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_create,
        client,
        GammaControlManager::interface_ptr(),
        version as c_int,
        id
    );
    if resource.is_null() {
        warn!("Out of memory, could not make a new wl_resource \
               for gamma control");
        ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_client_post_no_memory,
            client
        );
    }
    let global_manager_ptr = &mut GAMMA_CONTROL_MANAGER as *mut _ as *mut c_void;
    //let global_manager_ptr = &mut *manager as *mut _ as *mut c_void;
    ffi_dispatch!(
        WAYLAND_SERVER_HANDLE,
        wl_resource_set_implementation,
        resource,
        global_manager_ptr,
        ::std::ptr::null_mut(),
        None
    );
}

/// Send the size of the gamma ramps of the output specified by the wl_resource
/// to the client.
unsafe extern "C" fn gamma_control_send_gamma_size(resource: *mut wl_resource,
                                                   size: uint16_t) {
    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                  wl_resource_post_event,
                  resource,
                  0,
                  size as c_uint);
}

/// Sets up Way Cooler to announce it uses the gamma control interface.
pub fn init() {
    let w_display = wayland::get_display();
    unsafe {
        debug!("Initializing gamma control manager");
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_global_create,
                      w_display as *mut _,
                      GammaControlManager::interface_ptr(),
                      GammaControlManager::supported_version() as i32,
                      ::std::ptr::null_mut(),
                      bind
        );
    }
}

<|endoftext|>


<commit_before>use crate::StrError;
use serde::{Deserialize, Serialize};
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;

/// Aliases usize as Point ID
pub type PointId = usize;

/// Aliases usize as Cell ID
pub type CellId = usize;

/// Aliases usize as Cell's attribute ID
pub type CellAttributeId = usize;

/// Holds point data
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Point {
    /// Identification number which equals the index of the point in the mesh
    pub id: PointId,

    /// Point coordinates (2D or 3D)
    pub coords: Vec<f64>,
}

/// Holds cell (aka geometric shape, polygon, polyhedra) data
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Cell {
    /// Identification number which equals the index of the cell in the mesh
    pub id: CellId,

    /// Attribute identification number
    pub attribute_id: CellAttributeId,

    /// Space dimension of this cell
    ///
    /// The cell's ndim may be different than the space dimension of the mesh.
    /// For example, a 1D line in the 2D or 3D space or a 2D triangle in the 3D space.
    pub geo_ndim: usize,

    /// List of points defining this cell (nodes); in the right order (unsorted)
    ///
    /// Note: The list of nodes must follow a **counter-clockwise order**.
    pub points: Vec<PointId>,
}

/// Holds mesh data
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Mesh {
    /// Space dimension of the mesh
    ///
    /// The mesh's ndim may be different that an cell's ndim.
    /// For example, a 3D mesh may contain 1D lines or 2D triangles.
    pub space_ndim: usize,

    /// All points in the mesh
    pub points: Vec<Point>,

    /// All cells (aka geometric shape, polygon, polyhedra) in the mesh
    pub cells: Vec<Cell>,
}

impl Mesh {
    /// Reads a binary file containing the mesh data
    ///
    /// # Input
    ///
    /// * `full_path` -- may be a String, &str, or Path
    pub fn read<P>(full_path: &P) -> Result<Self, StrError>
    where
        P: AsRef<OsStr> + ?Sized,
    {
        let path = Path::new(full_path).to_path_buf();
        let mut file = File::open(&path).map_err(|_| "file not found")?;
        let metadata = fs::metadata(&path).map_err(|_| "unable to read metadata")?;
        let mut bin = vec![0; metadata.len() as usize];
        file.read(&mut bin).expect("buffer overflow");
        let mut des = rmp_serde::Deserializer::new(&bin[..]);
        let mesh: Mesh = Deserialize::deserialize(&mut des).map_err(|_| "deserialize failed")?;
        Ok(mesh)
    }

    /// Writes a binary file with the mesh data
    ///
    /// # Input
    ///
    /// * `full_path` -- may be a String, &str, or Path
    pub fn write<P>(&self, full_path: &P) -> Result<(), StrError>
    where
        P: AsRef<OsStr> + ?Sized,
    {
        let path = Path::new(full_path).to_path_buf();
        if let Some(p) = path.parent() {
            fs::create_dir_all(p).map_err(|_| "cannot create directory")?;
        }
        let mut bin = Vec::new();
        let mut ser = rmp_serde::Serializer::new(&mut bin);
        self.serialize(&mut ser).map_err(|_| "serialize failed")?;
        let mut file = File::create(&path).map_err(|_| "cannot create file")?;
        file.write_all(&bin).map_err(|_| "cannot write file")?;
        Ok(())
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::mesh::{Mesh, Samples};
    use crate::StrError;
    use serde_json;

    #[test]
    fn read_and_write_capture_errors() -> Result<(), StrError> {
        assert_eq!(Mesh::read("/tmp/not_found").err(), Some("file not found"));
        assert_eq!(
            Mesh::read("./data/meshes/two_quads_horizontal.msh").err(),
            Some("deserialize failed")
        );
        let mesh = Mesh {
            space_ndim: 2,
            points: Vec::new(),
            cells: Vec::new(),
        };
        assert_eq!(mesh.write("/tmp/").err(), Some("cannot create file"));
        Ok(())
    }

    #[test]
    fn read_and_write_work() -> Result<(), StrError> {
        //
        //  3--------2--------5
        //  |        |        |
        //  |        |        |
        //  |        |        |
        //  0--------1--------4
        //
        let mesh = Mesh::from_text(
            r"# header
            # space_ndim npoint ncell
                       2      6     2

            # points
            # id   x   y
               0 0.0 0.0
               1 1.0 0.0
               2 1.0 1.0
               3 0.0 1.0
               4 2.0 0.0
               5 2.0 1.0

            # cells
            # id att geo_ndim nnode  point_ids...
               0   1        2     4  0 1 2 3
               1   0        2     4  1 4 5 2",
        )?;
        mesh.write("/tmp/gemlab/test.msh")?;
        let mesh_read = Mesh::read("/tmp/gemlab/test.msh")?;
        assert_eq!(format!("{:?}", mesh), format!("{:?}", mesh_read));
        Ok(())
    }

    #[test]
    fn derive_works() -> Result<(), StrError> {
        let mesh = Samples::two_quads_horizontal();
        let mesh_clone = mesh.clone();
        let correct ="Mesh { space_ndim: 2, points: [Point { id: 0, coords: [0.0, 0.0] }, Point { id: 1, coords: [1.0, 0.0] }, Point { id: 2, coords: [1.0, 1.0] }, Point { id: 3, coords: [0.0, 1.0] }, Point { id: 4, coords: [2.0, 0.0] }, Point { id: 5, coords: [2.0, 1.0] }], cells: [Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: [0, 1, 2, 3] }, Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: [1, 4, 5, 2] }] }";
        assert_eq!(format!("{:?}", mesh), correct);
        assert_eq!(mesh_clone.space_ndim, mesh.space_ndim);
        assert_eq!(mesh_clone.points.len(), mesh.points.len());
        assert_eq!(mesh_clone.cells.len(), mesh.cells.len());
        // serialize
        let mesh_json = serde_json::to_string(&mesh).unwrap();
        // deserialize
        let mesh_read: Mesh = serde_json::from_str(&mesh_json).unwrap();
        assert_eq!(format!("{:?}", mesh_read), correct);
        Ok(())
    }
}
<commit_msg>Impl mesh Display<commit_after>use crate::StrError;
use serde::{Deserialize, Serialize};
use std::ffi::OsStr;
use std::fmt::{self, Write as FmtWrite};
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;

/// Aliases usize as Point ID
pub type PointId = usize;

/// Aliases usize as Cell ID
pub type CellId = usize;

/// Aliases usize as Cell's attribute ID
pub type CellAttributeId = usize;

/// Holds point data
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Point {
    /// Identification number which equals the index of the point in the mesh
    pub id: PointId,

    /// Point coordinates (2D or 3D)
    pub coords: Vec<f64>,
}

/// Holds cell (aka geometric shape, polygon, polyhedra) data
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Cell {
    /// Identification number which equals the index of the cell in the mesh
    pub id: CellId,

    /// Attribute identification number
    pub attribute_id: CellAttributeId,

    /// Space dimension of this cell
    ///
    /// The cell's ndim may be different than the space dimension of the mesh.
    /// For example, a 1D line in the 2D or 3D space or a 2D triangle in the 3D space.
    pub geo_ndim: usize,

    /// List of points defining this cell (nodes); in the right order (unsorted)
    ///
    /// Note: The list of nodes must follow a **counter-clockwise order**.
    pub points: Vec<PointId>,
}

/// Holds mesh data
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Mesh {
    /// Space dimension of the mesh
    ///
    /// The mesh's ndim may be different that an cell's ndim.
    /// For example, a 3D mesh may contain 1D lines or 2D triangles.
    pub space_ndim: usize,

    /// All points in the mesh
    pub points: Vec<Point>,

    /// All cells (aka geometric shape, polygon, polyhedra) in the mesh
    pub cells: Vec<Cell>,
}

impl Mesh {
    /// Reads a binary file containing the mesh data
    ///
    /// # Input
    ///
    /// * `full_path` -- may be a String, &str, or Path
    pub fn read<P>(full_path: &P) -> Result<Self, StrError>
    where
        P: AsRef<OsStr> + ?Sized,
    {
        let path = Path::new(full_path).to_path_buf();
        let mut file = File::open(&path).map_err(|_| "file not found")?;
        let metadata = fs::metadata(&path).map_err(|_| "unable to read metadata")?;
        let mut bin = vec![0; metadata.len() as usize];
        file.read(&mut bin).expect("buffer overflow");
        let mut des = rmp_serde::Deserializer::new(&bin[..]);
        let mesh: Mesh = Deserialize::deserialize(&mut des).map_err(|_| "deserialize failed")?;
        Ok(mesh)
    }

    /// Writes a binary file with the mesh data
    ///
    /// # Input
    ///
    /// * `full_path` -- may be a String, &str, or Path
    pub fn write<P>(&self, full_path: &P) -> Result<(), StrError>
    where
        P: AsRef<OsStr> + ?Sized,
    {
        let path = Path::new(full_path).to_path_buf();
        if let Some(p) = path.parent() {
            fs::create_dir_all(p).map_err(|_| "cannot create directory")?;
        }
        let mut bin = Vec::new();
        let mut ser = rmp_serde::Serializer::new(&mut bin);
        self.serialize(&mut ser).map_err(|_| "serialize failed")?;
        let mut file = File::create(&path).map_err(|_| "cannot create file")?;
        file.write_all(&bin).map_err(|_| "cannot write file")?;
        Ok(())
    }
}

impl fmt::Display for Mesh {
    /// Returns a text representation of the Mesh (can be used with [Mesh::from_text])
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "# header\n").unwrap();
        write!(f, "# space_ndim npoint ncell\n").unwrap();
        write!(f, "{} {} {}\n", self.space_ndim, self.points.len(), self.cells.len()).unwrap();
        write!(f, "\n# points\n").unwrap();
        write!(f, "# id x y {{z}}\n").unwrap();
        self.points.iter().for_each(|point| {
            if self.space_ndim == 2 {
                write!(f, "{} {} {}\n", point.id, point.coords[0], point.coords[1]).unwrap();
            } else {
                write!(
                    f,
                    "{} {} {} {}\n",
                    point.id, point.coords[0], point.coords[1], point.coords[2]
                )
                .unwrap();
            }
        });
        write!(f, "\n# cells\n").unwrap();
        write!(f, "# id attribute_id geo_ndim nnode  points\n").unwrap();
        self.cells.iter().for_each(|cell| {
            write!(
                f,
                "{} {} {} {} {}\n",
                cell.id,
                cell.attribute_id,
                cell.geo_ndim,
                cell.points.len(),
                cell.points.iter().fold(&mut String::new(), |acc, cur| {
                    write!(acc, " {}", cur).unwrap();
                    acc
                }),
            )
            .unwrap();
        });
        Ok(())
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::mesh::{Mesh, Samples};
    use crate::StrError;
    use serde_json;

    #[test]
    fn read_and_write_capture_errors() -> Result<(), StrError> {
        assert_eq!(Mesh::read("/tmp/not_found").err(), Some("file not found"));
        assert_eq!(
            Mesh::read("./data/meshes/two_quads_horizontal.msh").err(),
            Some("deserialize failed")
        );
        let mesh = Mesh {
            space_ndim: 2,
            points: Vec::new(),
            cells: Vec::new(),
        };
        assert_eq!(mesh.write("/tmp/").err(), Some("cannot create file"));
        Ok(())
    }

    #[test]
    fn read_and_write_work() -> Result<(), StrError> {
        //
        //  3--------2--------5
        //  |        |        |
        //  |        |        |
        //  |        |        |
        //  0--------1--------4
        //
        let mesh = Mesh::from_text(
            r"# header
            # space_ndim npoint ncell
                       2      6     2

            # points
            # id   x   y
               0 0.0 0.0
               1 1.0 0.0
               2 1.0 1.0
               3 0.0 1.0
               4 2.0 0.0
               5 2.0 1.0

            # cells
            # id att geo_ndim nnode  point_ids...
               0   1        2     4  0 1 2 3
               1   0        2     4  1 4 5 2",
        )?;
        mesh.write("/tmp/gemlab/test.msh")?;
        let mesh_read = Mesh::read("/tmp/gemlab/test.msh")?;
        assert_eq!(format!("{:?}", mesh), format!("{:?}", mesh_read));
        Ok(())
    }

    #[test]
    fn derive_works() -> Result<(), StrError> {
        let mesh = Samples::two_quads_horizontal();
        let mesh_clone = mesh.clone();
        let correct ="Mesh { space_ndim: 2, points: [Point { id: 0, coords: [0.0, 0.0] }, Point { id: 1, coords: [1.0, 0.0] }, Point { id: 2, coords: [1.0, 1.0] }, Point { id: 3, coords: [0.0, 1.0] }, Point { id: 4, coords: [2.0, 0.0] }, Point { id: 5, coords: [2.0, 1.0] }], cells: [Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: [0, 1, 2, 3] }, Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: [1, 4, 5, 2] }] }";
        assert_eq!(format!("{:?}", mesh), correct);
        assert_eq!(mesh_clone.space_ndim, mesh.space_ndim);
        assert_eq!(mesh_clone.points.len(), mesh.points.len());
        assert_eq!(mesh_clone.cells.len(), mesh.cells.len());
        // serialize
        let mesh_json = serde_json::to_string(&mesh).unwrap();
        // deserialize
        let mesh_read: Mesh = serde_json::from_str(&mesh_json).unwrap();
        assert_eq!(format!("{:?}", mesh_read), correct);
        Ok(())
    }

    #[test]
    fn display_works_2d() {
        let mesh = Samples::two_quads_horizontal();
        let text = format!("{}", mesh);
        assert_eq!(
            text,
            "# header\n\
             # space_ndim npoint ncell\n\
             2 6 2\n\
             \n\
             # points\n\
             # id x y {z}\n\
             0 0 0\n\
             1 1 0\n\
             2 1 1\n\
             3 0 1\n\
             4 2 0\n\
             5 2 1\n\
             \n\
             # cells\n\
             # id attribute_id geo_ndim nnode  points\n\
             0 1 2 4  0 1 2 3\n\
             1 2 2 4  1 4 5 2\n"
        );
        let mesh_in = Mesh::from_text(&text).unwrap();
        assert_eq!(format!("{}", mesh_in), text);
    }

    #[test]
    fn display_works_3d() {
        let mesh = Samples::two_cubes_vertical();
        let text = format!("{}", mesh);
        assert_eq!(
            text,
            "# header\n\
             # space_ndim npoint ncell\n\
             3 12 2\n\
             \n\
             # points\n\
             # id x y {z}\n\
             0 0 0 0\n\
             1 1 0 0\n\
             2 1 1 0\n\
             3 0 1 0\n\
             4 0 0 1\n\
             5 1 0 1\n\
             6 1 1 1\n\
             7 0 1 1\n\
             8 0 0 2\n\
             9 1 0 2\n\
             10 1 1 2\n\
             11 0 1 2\n\
             \n\
             # cells\n\
             # id attribute_id geo_ndim nnode  points\n\
             0 1 3 8  0 1 2 3 4 5 6 7\n\
             1 2 3 8  4 5 6 7 8 9 10 11\n"
        );
        let mesh_in = Mesh::from_text(&text).unwrap();
        assert_eq!(format!("{}", mesh_in), text);
    }

    #[test]
    fn display_works_mixed_2d() {
        let mesh = Samples::mixed_shapes_2d();
        let text = format!("{}", mesh);
        let mesh_in = Mesh::from_text(&text).unwrap();
        assert_eq!(format!("{}", mesh_in), text);
        assert_eq!(mesh_in.cells[0].points.len(), 2);
        assert_eq!(mesh_in.cells[1].points.len(), 4);
    }

    #[test]
    fn display_works_mixed_3d() {
        let mesh = Samples::mixed_shapes_3d();
        let text = format!("{}", mesh);
        let mesh_in = Mesh::from_text(&text).unwrap();
        assert_eq!(format!("{}", mesh_in), text);
        assert_eq!(mesh_in.cells[0].points.len(), 8);
        assert_eq!(mesh_in.cells[4].points.len(), 3);
    }
}
<|endoftext|>


<commit_before>// Support using Serde without the standard library!
#![cfg_attr(feature = "no_std", no_std)]

pub trait BitfieldRegister {
    type Data;
    const REGISTER_SIZE: usize;
    fn data(&self) -> & Self::Data;
}

pub trait FromBitfield<Array> {
    fn from_bitfield(array:Array) -> Self;
}

pub trait IntoBitfield<Array> {
    fn into_bitfield(self) -> Array;
}

impl FromBitfield<[u8;1]> for u8 {
    fn from_bitfield(array: [u8;1]) -> Self {
        return array[0];
    }
}

impl IntoBitfield<[u8;1]> for u8 {
    fn into_bitfield(self) -> [u8;1]{
        return [self;1];
    }
}

impl FromBitfield<[u8;1]> for bool {
    fn from_bitfield(array: [u8;1]) -> Self {
        return (array[0] & 1) != 0;
    }
}

impl IntoBitfield<[u8;1]> for bool {
    fn into_bitfield(self) -> [u8;1]{
        // If you cast a bool into an integer, true will be 1 and false will be 0.
        // https://doc.rust-lang.org/std/primitive.bool.html
        return [self as u8;1];
    }
}

mod tests {
    use super::FromBitfield;
    use super::IntoBitfield;

    #[test]
    fn bool_test() {
        assert_eq!(
            false.into_bitfield(),
            [0;1]
        );
        assert_eq!(
            true.into_bitfield(),
            [1;1]
        );
        assert_eq!(
            <bool as FromBitfield<[u8;1]>>::from_bitfield([0;1]),
            false
        );
        assert_eq!(
            <bool as FromBitfield<[u8;1]>>::from_bitfield([1;1]),
            true
        );
        assert_eq!(
            <bool as FromBitfield<[u8;1]>>::from_bitfield([2;1]),
            false
        );
    }
}<commit_msg>Refactor FromBitfield and IntoBitfield tests<commit_after>// Support using Serde without the standard library!
#![cfg_attr(feature = "no_std", no_std)]

pub trait BitfieldRegister {
    type Data;
    const REGISTER_SIZE: usize;
    fn data(&self) -> & Self::Data;
}

pub trait FromBitfield<Array> {
    fn from_bitfield(array:Array) -> Self;
}

pub trait IntoBitfield<Array> {
    fn into_bitfield(self) -> Array;
}

impl FromBitfield<[u8;1]> for u8 {
    fn from_bitfield(array: [u8;1]) -> Self {
        return array[0];
    }
}

impl IntoBitfield<[u8;1]> for u8 {
    fn into_bitfield(self) -> [u8;1]{
        return [self;1];
    }
}

impl FromBitfield<[u8;1]> for bool {
    fn from_bitfield(array: [u8;1]) -> Self {
        return (array[0] & 1) != 0;
    }
}

impl IntoBitfield<[u8;1]> for bool {
    fn into_bitfield(self) -> [u8;1]{
        // If you cast a bool into an integer, true will be 1 and false will be 0.
        // https://doc.rust-lang.org/std/primitive.bool.html
        return [self as u8;1];
    }
}

mod tests {
    use super::{FromBitfield, IntoBitfield};

    macro_rules! test_into {
        ($value:expr, $expected_array:expr) => (
            assert_eq!(
                $value.into_bitfield(),
                $expected_array
            );
        )
    }

    macro_rules! test_from {
        ($value_type:ty, $array_len:expr, $array:expr, $expected_value:expr) => (
            assert_eq!(
                <$value_type as FromBitfield<[u8;$array_len]>>::from_bitfield($array),
                $expected_value
            );
        )
    }

    #[test]
    fn bool_test() {
        test_into!(
            false,
            [0;1]
        );
        test_into!(
            true,
            [1;1]
        );

        test_from!(
            bool, 1,
            [0;1], false
        );
        test_from!(
            bool, 1,
            [1;1], true
        );
        test_from!(
            bool, 1,
            [0b11111110;1], false
        );
        test_from!(
            bool, 1,
            [0b11111111;1], true
        );
    }

    #[test]
    fn u8_test() {
        test_into!(
            (0 as u8),
            [0;1]
        );
        test_into!(
            (1 as u8),
            [1;1]
        );
        test_into!(
            (0xFF as u8),
            [0xFF;1]
        );

        test_from!(
            u8, 1,
            [0;1], 0
        );
        test_from!(
            u8, 1,
            [1;1], 1
        );
        test_from!(
            u8, 1,
            [0xFF;1], 0xFF
        );
    }
}<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use regex::Regex;
static RE: Regex = regex!(r"\d+");

#[test]
fn splitn() {
    let text = "cauchy123plato456tyler789binx";
    let subs: Vec<&str> = RE.splitn(text, 2).collect();
    assert_eq!(subs, vec!("cauchy", "plato456tyler789binx"));
}

#[test]
fn split() {
    let text = "cauchy123plato456tyler789binx";
    let subs: Vec<&str> = RE.split(text).collect();
    assert_eq!(subs, vec!("cauchy", "plato", "tyler", "binx"));
}
<commit_msg>tests: remove unused plugin tests<commit_after><|endoftext|>


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

use std::kinds::marker;
use types::gpointer;

pub type RefFunc = unsafe extern "C" fn(gpointer) -> gpointer;
pub type UnrefFunc = unsafe extern "C" fn(gpointer);
pub type RefcountFuncs = (*const RefFunc, *const UnrefFunc);

pub trait Refcount {
    fn refcount_funcs(&self) -> &'static RefcountFuncs;

    unsafe fn inc_ref(&mut self) {
        let (ref_func, _) = *self.refcount_funcs();
        let p: *mut Self = self;
        (*ref_func)(p as gpointer);
    }

    unsafe fn dec_ref(&mut self) {
        let (_, unref_func) = *self.refcount_funcs();
        let p: *mut Self = self;
        (*unref_func)(p as gpointer);
    }
}

pub struct Ref<T: Refcount> {
    ptr: *mut T,
    no_send: marker::NoSend,
    no_sync: marker::NoSync
}

pub mod raw {

    use super::{Ref,Refcount};
    use std::kinds::marker;

    pub unsafe fn ref_from_ptr<T: Refcount>(p: *mut T) -> Ref<T> {
        Ref {
            ptr: p,
            no_send: marker::NoSend,
            no_sync: marker::NoSync
        }
    }

}

pub struct Unowned<'a, T: 'a + Refcount> {
    ptr: *mut T,
    lifetime_marker: marker::ContravariantLifetime<'a>
}

unsafe fn make_ref<T: Refcount>(p: *mut T) -> Ref<T> {
    (*p).inc_ref();
    raw::ref_from_ptr(p)
}

unsafe fn make_unowned<'a, T: 'a + Refcount>(p: *mut T) -> Unowned<'a, T> {
    Unowned {
        ptr: p,
        lifetime_marker: marker::ContravariantLifetime
    }
}

impl<T: Refcount> Ref<T> {
    pub fn new(source: &Unowned<T>) -> Ref<T> {
        unsafe { make_ref(source.ptr) }
    }
    pub fn borrow<'a>(&'a self) -> &'a T { unsafe { &*self.ptr } }
    pub fn borrow_mut<'a>(&'a mut self) -> &'a mut T { unsafe { &mut *self.ptr } }
}

impl<'a, T: 'a + Refcount> Unowned<'a, T> {
    pub fn new_ref(&self) -> Ref<T> { unsafe { make_ref(self.ptr) } }
}

#[unsafe_destructor]
impl<T: Refcount> Drop for Ref<T> {
    fn drop(&mut self) {
        unsafe {
            (*self.ptr).dec_ref();
        }
    }
}

impl<T: Refcount> Clone for Ref<T> {

    fn clone(&self) -> Ref<T> { unsafe { make_ref(self.ptr) } }

    fn clone_from(&mut self, source: &Ref<T>) {
        unsafe {
            (*source.ptr).inc_ref();
            (*self.ptr).dec_ref();
            self.ptr = source.ptr;
        }
    }
}

impl<T: Refcount> Deref<T> for Ref<T> {
    fn deref<'a>(&'a self) -> &'a T { unsafe { &*self.ptr } }
}

impl<T: Refcount> DerefMut<T> for Ref<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T { unsafe { &mut *self.ptr } }
}

impl<'b, T: Refcount> Deref<T> for Unowned<'b, T> {
    fn deref<'a>(&'a self) -> &'a T { unsafe { &*self.ptr } }
}

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

use std::kinds::marker;
use types::gpointer;

pub type RefFunc = unsafe extern "C" fn(gpointer) -> gpointer;
pub type UnrefFunc = unsafe extern "C" fn(gpointer);
pub type RefcountFuncs = (*const RefFunc, *const UnrefFunc);

pub trait Refcount {
    fn refcount_funcs(&self) -> &'static RefcountFuncs;

    unsafe fn inc_ref(&mut self) {
        let (ref_func, _) = *self.refcount_funcs();
        let p: *mut Self = self;
        (*ref_func)(p as gpointer);
    }

    unsafe fn dec_ref(&mut self) {
        let (_, unref_func) = *self.refcount_funcs();
        let p: *mut Self = self;
        (*unref_func)(p as gpointer);
    }
}

pub struct Ref<T: Refcount> {
    ptr: *mut T,
    no_send: marker::NoSend,
    no_sync: marker::NoSync
}

pub mod raw {

    use super::{Ref,Refcount};
    use std::kinds::marker;

    pub unsafe fn ref_from_ptr<T: Refcount>(p: *mut T) -> Ref<T> {
        Ref {
            ptr: p,
            no_send: marker::NoSend,
            no_sync: marker::NoSync
        }
    }

}

unsafe fn make_ref<T: Refcount>(p: *mut T) -> Ref<T> {
    (*p).inc_ref();
    raw::ref_from_ptr(p)
}

impl<T: Refcount> Ref<T> {
    pub fn new(source: &mut T) -> Ref<T> {
        unsafe { make_ref(source as *mut T) }
    }
    pub fn borrow<'a>(&'a self) -> &'a T { unsafe { &*self.ptr } }
    pub fn borrow_mut<'a>(&'a mut self) -> &'a mut T { unsafe { &mut *self.ptr } }
}

#[unsafe_destructor]
impl<T: Refcount> Drop for Ref<T> {
    fn drop(&mut self) {
        unsafe {
            (*self.ptr).dec_ref();
        }
    }
}

impl<T: Refcount> Clone for Ref<T> {

    fn clone(&self) -> Ref<T> { unsafe { make_ref(self.ptr) } }

    fn clone_from(&mut self, source: &Ref<T>) {
        unsafe {
            (*source.ptr).inc_ref();
            (*self.ptr).dec_ref();
            self.ptr = source.ptr;
        }
    }
}

impl<T: Refcount> Deref<T> for Ref<T> {
    fn deref<'a>(&'a self) -> &'a T { unsafe { &*self.ptr } }
}

impl<T: Refcount> DerefMut<T> for Ref<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T { unsafe { &mut *self.ptr } }
}
<|endoftext|>