<commit_before>#[cfg(feature = "ndarray_volumes")]
extern crate ndarray;
#[cfg(feature = "ndarray_volumes")]
extern crate nifti;
#[cfg(feature = "ndarray_volumes")]
extern crate tempfile;

#[cfg(feature = "ndarray_volumes")]
mod tests {
    use std::{
        fs::File,
        io::Read,
        ops::{Add, Mul},
        path::{Path, PathBuf},
    };

    use ndarray::{Array, Array2, Axis, Dimension, IxDyn, ShapeBuilder};
    use tempfile::tempdir;

    use nifti::{
        header::MAGIC_CODE_NIP1,
        object::NiftiObject,
        writer::{write_nifti, write_rgb_nifti},
        InMemNiftiObject, IntoNdArray, NiftiHeader, NiftiType,
    };

    fn get_temporary_path(ext: &str) -> PathBuf {
        let dir = tempdir().unwrap();
        let mut path = dir.into_path();
        if !ext.is_empty() {
            path.push(ext);
        }
        path
    }

    pub fn generate_nifti_header(
        dim: [u16; 8],
        scl_slope: f32,
        scl_inter: f32,
        datatype: i16,
    ) -> NiftiHeader {
        NiftiHeader {
            dim,
            datatype,
            bitpix: (NiftiType::Float32.size_of() * 8) as i16,
            magic: *MAGIC_CODE_NIP1,
            scl_slope,
            scl_inter,
            ..NiftiHeader::default()
        }
    }

    fn read_as_ndarray<P, D>(path: P) -> Array<f32, D>
    where
        P: AsRef<Path>,
        D: Dimension,
    {
        let nifti_object = InMemNiftiObject::from_file(path).expect("Nifti file is unreadable.");
        let volume = nifti_object.into_volume();
        let dyn_data = volume.into_ndarray().unwrap();
        dyn_data.into_dimensionality::<D>().unwrap()
    }

    fn test_write_read(arr: &Array<f32, IxDyn>, path: &str) {
        let path = get_temporary_path(path);
        let mut dim = [1; 8];
        dim[0] = arr.ndim() as u16;
        for (i, s) in arr.shape().iter().enumerate() {
            dim[i + 1] = *s as u16;
        }
        let header = generate_nifti_header(dim, 1.0, 0.0, 16);
        write_nifti(&path, &arr, Some(&header)).unwrap();

        let read_nifti: Array2<f32> = read_as_ndarray(path);
        assert!(read_nifti.all_close(&arr, 1e-10));
    }

    fn f_order_array() -> Array<f32, IxDyn> {
        let dim = vec![4, 4];
        let vec = (0..16).map(|x| x as f32).collect();
        Array::from_shape_vec(IxDyn(&dim).f(), vec).unwrap()
    }

    fn c_order_array() -> Array<f32, IxDyn> {
        let dim = vec![4, 4];
        let vec = (0..16).map(|x| x as f32).collect();
        Array::from_shape_vec(IxDyn(&dim), vec).unwrap()
    }

    #[test]
    fn fortran_writing() {
        // Test .nii
        let arr = f_order_array();
        test_write_read(&arr, "test.nii");
        let mut arr = f_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii");

        // Test .nii.gz
        let arr = f_order_array();
        test_write_read(&arr, "test.nii.gz");
        let mut arr = f_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii.gz");
    }

    #[test]
    fn c_writing() {
        // Test .nii
        let arr = c_order_array();
        test_write_read(&arr, "test.nii");

        let mut arr = c_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii");

        // Test .nii.gz
        let arr = c_order_array();
        test_write_read(&arr, "test.nii.gz");

        let mut arr = c_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii.gz");
    }

    #[test]
    fn header_slope_inter() {
        let arr = f_order_array();
        let slope = 2.2;
        let inter = 101.1;

        let path = get_temporary_path("test_slope_inter.nii");
        let mut dim = [1; 8];
        dim[0] = arr.ndim() as u16;
        for (i, s) in arr.shape().iter().enumerate() {
            dim[i + 1] = *s as u16;
        }
        let header = generate_nifti_header(dim, slope, inter, 16);
        let transformed_data = arr.mul(slope).add(inter);
        write_nifti(&path, &transformed_data, Some(&header)).unwrap();

        let read_nifti: Array2<f32> = read_as_ndarray(path);
        assert!(read_nifti.all_close(&transformed_data, 1e-10));
    }

    #[test]
    fn write_hdr_standard() {
        let mut data = Array::zeros((10, 11, 12));
        data[(5, 0, 0)] = 1.0;
        data[(6, 0, 0)] = 2.0;

        for fname in &["3d.hdr", "3d.hdr.gz"] {
            let path = get_temporary_path(fname);
            write_nifti(&path, &data, None).unwrap();
            let data_read = read_as_ndarray(path);
            assert_eq!(data, data_read);
        }
    }

    #[test]
    fn write_3d_rgb() {
        let mut data = Array::from_elem((3, 3, 3), [0u8, 0u8, 0u8]);
        data[(0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1)] = [55, 0, 55];
        data[(0, 1, 0)] = [0, 55, 55];

        let path = get_temporary_path("rgb.nii");
        write_rgb_nifti(&path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 3D RGB image in ressources/rgb/.
        let mut rgb_bytes = vec![];
        let _ = File::open(path)
            .unwrap()
            .read_to_end(&mut rgb_bytes)
            .unwrap();
        let mut gt_bytes = vec![];
        let _ = File::open("resources/rgb/3D.nii")
            .unwrap()
            .read_to_end(&mut gt_bytes)
            .unwrap();
        assert_eq!(rgb_bytes, gt_bytes);
    }

    #[test]
    fn write_4d_rgb() {
        let mut data = Array::from_elem((3, 3, 3, 2), [0u8, 0u8, 0u8]);
        data[(0, 0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1, 0)] = [55, 0, 55];
        data[(0, 1, 0, 0)] = [0, 55, 55];
        data[(0, 0, 0, 1)] = [55, 55, 0];
        data[(0, 1, 0, 1)] = [55, 0, 55];
        data[(1, 0, 0, 1)] = [0, 55, 55];

        let path = get_temporary_path("rgb.nii");
        write_rgb_nifti(&path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 4D RGB image in ressources/rgb/.
        let mut rgb_bytes = vec![];
        let _ = File::open(path)
            .unwrap()
            .read_to_end(&mut rgb_bytes)
            .unwrap();
        let mut gt_bytes = vec![];
        let _ = File::open("resources/rgb/4D.nii")
            .unwrap()
            .read_to_end(&mut gt_bytes)
            .unwrap();
        assert_eq!(rgb_bytes, gt_bytes);
    }
}
<commit_msg>Add RGB hdr writing test<commit_after>#[cfg(feature = "ndarray_volumes")]
extern crate ndarray;
#[cfg(feature = "ndarray_volumes")]
extern crate nifti;
#[cfg(feature = "ndarray_volumes")]
extern crate tempfile;

#[cfg(feature = "ndarray_volumes")]
mod tests {
    use std::{
        fs::{self, File},
        io::Read,
        ops::{Add, Mul},
        path::{Path, PathBuf},
    };

    use ndarray::{Array, Array2, Axis, Dimension, IxDyn, ShapeBuilder};
    use tempfile::tempdir;

    use nifti::{
        header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1},
        object::NiftiObject,
        writer::{write_nifti, write_rgb_nifti},
        InMemNiftiObject, IntoNdArray, NiftiHeader, NiftiType,
    };

    fn get_temporary_path(ext: &str) -> PathBuf {
        let dir = tempdir().unwrap();
        let mut path = dir.into_path();
        if !ext.is_empty() {
            path.push(ext);
        }
        path
    }

    pub fn generate_nifti_header(
        dim: [u16; 8],
        scl_slope: f32,
        scl_inter: f32,
        datatype: i16,
    ) -> NiftiHeader {
        NiftiHeader {
            dim,
            datatype,
            bitpix: (NiftiType::Float32.size_of() * 8) as i16,
            magic: *MAGIC_CODE_NIP1,
            scl_slope,
            scl_inter,
            ..NiftiHeader::default()
        }
    }

    fn read_as_ndarray<P, D>(path: P) -> Array<f32, D>
    where
        P: AsRef<Path>,
        D: Dimension,
    {
        let nifti_object = InMemNiftiObject::from_file(path).expect("Nifti file is unreadable.");
        let volume = nifti_object.into_volume();
        let dyn_data = volume.into_ndarray().unwrap();
        dyn_data.into_dimensionality::<D>().unwrap()
    }

    fn test_write_read(arr: &Array<f32, IxDyn>, path: &str) {
        let path = get_temporary_path(path);
        let mut dim = [1; 8];
        dim[0] = arr.ndim() as u16;
        for (i, s) in arr.shape().iter().enumerate() {
            dim[i + 1] = *s as u16;
        }
        let header = generate_nifti_header(dim, 1.0, 0.0, 16);
        write_nifti(&path, &arr, Some(&header)).unwrap();

        let read_nifti: Array2<f32> = read_as_ndarray(path);
        assert!(read_nifti.all_close(&arr, 1e-10));
    }

    fn f_order_array() -> Array<f32, IxDyn> {
        let dim = vec![4, 4];
        let vec = (0..16).map(|x| x as f32).collect();
        Array::from_shape_vec(IxDyn(&dim).f(), vec).unwrap()
    }

    fn c_order_array() -> Array<f32, IxDyn> {
        let dim = vec![4, 4];
        let vec = (0..16).map(|x| x as f32).collect();
        Array::from_shape_vec(IxDyn(&dim), vec).unwrap()
    }

    #[test]
    fn fortran_writing() {
        // Test .nii
        let arr = f_order_array();
        test_write_read(&arr, "test.nii");
        let mut arr = f_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii");

        // Test .nii.gz
        let arr = f_order_array();
        test_write_read(&arr, "test.nii.gz");
        let mut arr = f_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii.gz");
    }

    #[test]
    fn c_writing() {
        // Test .nii
        let arr = c_order_array();
        test_write_read(&arr, "test.nii");

        let mut arr = c_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii");

        // Test .nii.gz
        let arr = c_order_array();
        test_write_read(&arr, "test.nii.gz");

        let mut arr = c_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii.gz");
    }

    #[test]
    fn header_slope_inter() {
        let arr = f_order_array();
        let slope = 2.2;
        let inter = 101.1;

        let path = get_temporary_path("test_slope_inter.nii");
        let mut dim = [1; 8];
        dim[0] = arr.ndim() as u16;
        for (i, s) in arr.shape().iter().enumerate() {
            dim[i + 1] = *s as u16;
        }
        let header = generate_nifti_header(dim, slope, inter, 16);
        let transformed_data = arr.mul(slope).add(inter);
        write_nifti(&path, &transformed_data, Some(&header)).unwrap();

        let read_nifti: Array2<f32> = read_as_ndarray(path);
        assert!(read_nifti.all_close(&transformed_data, 1e-10));
    }

    #[test]
    fn write_hdr_standard() {
        let mut data = Array::zeros((10, 11, 12));
        data[(5, 0, 0)] = 1.0;
        data[(6, 0, 0)] = 2.0;

        for fname in &["3d.hdr", "3d.hdr.gz"] {
            let path = get_temporary_path(fname);
            write_nifti(&path, &data, None).unwrap();
            let data_read = read_as_ndarray(path);
            assert_eq!(data, data_read);
        }
    }

    #[test]
    fn write_3d_rgb_hdr() {
        let mut data = Array::from_elem((3, 3, 3), [0u8, 0u8, 0u8]);
        data[(0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1)] = [55, 0, 55];
        data[(0, 1, 0)] = [0, 55, 55];

        let header_path = get_temporary_path("3d.hdr");
        let data_path = header_path.with_extension("img");
        write_rgb_nifti(&header_path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 3D RGB image in ressources/rgb/. However, we need to
        // set the bytes of vox_offset to 0.0 and of magic to MAGIC_CODE_NI1. The data bytes should
        // be identical though.
        let mut gt_bytes = fs::read("resources/rgb/3D.nii").unwrap();
        for i in 110..114 {
            gt_bytes[i] = 0;
        }
        for i in 0..4 {
            gt_bytes[344 + i] = MAGIC_CODE_NI1[i];
        }
        assert_eq!(fs::read(header_path).unwrap(), &gt_bytes[..352]);
        assert_eq!(fs::read(data_path).unwrap(), &gt_bytes[352..]);
    }

    #[test]
    fn write_3d_rgb() {
        let mut data = Array::from_elem((3, 3, 3), [0u8, 0u8, 0u8]);
        data[(0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1)] = [55, 0, 55];
        data[(0, 1, 0)] = [0, 55, 55];

        let path = get_temporary_path("rgb.nii");
        write_rgb_nifti(&path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 3D RGB image in ressources/rgb/.
        let mut rgb_bytes = vec![];
        let _ = File::open(path)
            .unwrap()
            .read_to_end(&mut rgb_bytes)
            .unwrap();
        let mut gt_bytes = vec![];
        let _ = File::open("resources/rgb/3D.nii")
            .unwrap()
            .read_to_end(&mut gt_bytes)
            .unwrap();
        assert_eq!(rgb_bytes, gt_bytes);
    }

    #[test]
    fn write_4d_rgb() {
        let mut data = Array::from_elem((3, 3, 3, 2), [0u8, 0u8, 0u8]);
        data[(0, 0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1, 0)] = [55, 0, 55];
        data[(0, 1, 0, 0)] = [0, 55, 55];
        data[(0, 0, 0, 1)] = [55, 55, 0];
        data[(0, 1, 0, 1)] = [55, 0, 55];
        data[(1, 0, 0, 1)] = [0, 55, 55];

        let path = get_temporary_path("rgb.nii");
        write_rgb_nifti(&path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 4D RGB image in ressources/rgb/.
        let mut rgb_bytes = vec![];
        let _ = File::open(path)
            .unwrap()
            .read_to_end(&mut rgb_bytes)
            .unwrap();
        let mut gt_bytes = vec![];
        let _ = File::open("resources/rgb/4D.nii")
            .unwrap()
            .read_to_end(&mut gt_bytes)
            .unwrap();
        assert_eq!(rgb_bytes, gt_bytes);
    }
}
<|endoftext|>


<commit_before>extern crate ncurses;

use self::ncurses::*;

pub const RIGHT_PANEL_WIDTH: i32  = 30;
pub const CMD_ENTRY_HEIGHT: i32   = 3;
pub const STATS_PANEL_HEIGHT: i32 = 20;

#[derive(Debug, Copy, Clone)]
pub struct Size {
    width: i32,
    height: i32,
}

impl Size {
    pub fn new(width: i32, height: i32) -> Size {
        Size {
            width: width,
            height: height,
        }
    }
}

// Wrapping the raw ncurses window pointer in a struct will allow us to send it across threads.
pub struct Window {
    id: WINDOW
}

// These trait implementations must be marked as unsafe because we're dealing with a raw pointer.
// While ncurses is NOT thread safe, there (hopefully) shouldn't be any issues in this program's use case.
unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl Window {
    fn new(id: WINDOW) -> Window {
        Window { id: id }
    }

    fn get_size_raw(window: WINDOW) -> Size {
        let mut x = 0;
        let mut y = 0;
        getmaxyx(window, &mut y, &mut x);
        Size::new(x, y)
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        delwin(self.id);
    }
}

pub struct Chat {
    parent: Window,
    child:  Window,
}

impl Chat {
    fn new(size: Size) -> Chat {
        let parent = newwin(size.height - CMD_ENTRY_HEIGHT,
                            size.width - RIGHT_PANEL_WIDTH,
                            0,
                            0);
        box_(parent, 0, 0);
        wrefresh(parent);

        let child = derwin(parent,
                           size.height - CMD_ENTRY_HEIGHT - 2,
                           size.width - RIGHT_PANEL_WIDTH - 2,
                           1,
                           1);
        scrollok(child, true);

        Chat {
            parent: Window::new(parent),
            child:  Window::new(child),
        }
    }

    pub fn add_message(&self, msg: &str) {
        wprintw(self.child.id, &format!("{}\n", msg));
        wrefresh(self.child.id);
    }
}

pub struct CommandEntry {
    parent: Window,
    child:  Window,
}

impl CommandEntry {
    fn new(size: Size) -> CommandEntry {
        let parent = newwin(CMD_ENTRY_HEIGHT,
                            size.width,
                            size.height - CMD_ENTRY_HEIGHT,
                            0);
        box_(parent, 0, 0);
        wrefresh(parent);

        let child = derwin(parent,
                           CMD_ENTRY_HEIGHT - 2,
                           size.width - 2,
                           1,
                           1);
        scrollok(child, true);

        CommandEntry {
            parent: Window::new(parent),
            child:  Window::new(child),
        }
    }

    pub fn read_input_char(&self) -> Option<char> {
        match wgetch(self.child.id) {
            -1 => None,
            i  => ::std::char::from_u32(i as u32),
        }
    }

    pub fn add_char(&self, ch: char) {
        wprintw(self.child.id, &ch.to_string());
        wrefresh(self.child.id);
    }
}

pub struct UI {
    pub chat:          Chat,
    pub command_entry: CommandEntry,
    pub channel_list:  Window,
    pub channel_stats: Window,
}

impl UI {
    fn create_channel_list(size: Size) -> Window {
        let w = newwin(size.height - STATS_PANEL_HEIGHT - CMD_ENTRY_HEIGHT,
                       RIGHT_PANEL_WIDTH,
                       0,
                       size.width - RIGHT_PANEL_WIDTH);
        box_(w, 0, 0);
        wrefresh(w);
        Window::new(w)
    }

    fn create_channel_stats(size: Size) -> Window {
        let w = newwin(STATS_PANEL_HEIGHT,
                       RIGHT_PANEL_WIDTH,
                       size.height - STATS_PANEL_HEIGHT - CMD_ENTRY_HEIGHT,
                       size.width - RIGHT_PANEL_WIDTH);
        box_(w, 0, 0);
        wrefresh(w);
        Window::new(w)
    }

    pub fn create() -> UI {
        initscr();
        start_color();
        noecho();
        curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);

        let term_size = Window::get_size_raw(stdscr());

        UI {
            chat:          Chat::new(term_size),
            command_entry: CommandEntry::new(term_size),
            channel_list:  UI::create_channel_list(term_size),
            channel_stats: UI::create_channel_stats(term_size),
        }
    }
}

impl Drop for UI {
    fn drop(&mut self) {
        endwin();
    }
}<commit_msg>Move get_size_raw to a more appropriate place<commit_after>extern crate ncurses;

use self::ncurses::*;

pub const RIGHT_PANEL_WIDTH: i32  = 30;
pub const CMD_ENTRY_HEIGHT: i32   = 3;
pub const STATS_PANEL_HEIGHT: i32 = 20;

#[derive(Debug, Copy, Clone)]
pub struct Size {
    width: i32,
    height: i32,
}

impl Size {
    pub fn new(width: i32, height: i32) -> Size {
        Size {
            width: width,
            height: height,
        }
    }
}

// Wrapping the raw ncurses window pointer in a struct will allow us to send it across threads.
pub struct Window {
    id: WINDOW
}

// These trait implementations must be marked as unsafe because we're dealing with a raw pointer.
// While ncurses is NOT thread safe, there (hopefully) shouldn't be any issues in this program's use case.
unsafe impl Send for Window {}
unsafe impl Sync for Window {}

impl Window {
    fn new(id: WINDOW) -> Window {
        Window { id: id }
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        delwin(self.id);
    }
}

pub struct Chat {
    parent: Window,
    child:  Window,
}

impl Chat {
    fn new(size: Size) -> Chat {
        let parent = newwin(size.height - CMD_ENTRY_HEIGHT,
                            size.width - RIGHT_PANEL_WIDTH,
                            0,
                            0);
        box_(parent, 0, 0);
        wrefresh(parent);

        let child = derwin(parent,
                           size.height - CMD_ENTRY_HEIGHT - 2,
                           size.width - RIGHT_PANEL_WIDTH - 2,
                           1,
                           1);
        scrollok(child, true);

        Chat {
            parent: Window::new(parent),
            child:  Window::new(child),
        }
    }

    pub fn add_message(&self, msg: &str) {
        wprintw(self.child.id, &format!("{}\n", msg));
        wrefresh(self.child.id);
    }
}

pub struct CommandEntry {
    parent: Window,
    child:  Window,
}

impl CommandEntry {
    fn new(size: Size) -> CommandEntry {
        let parent = newwin(CMD_ENTRY_HEIGHT,
                            size.width,
                            size.height - CMD_ENTRY_HEIGHT,
                            0);
        box_(parent, 0, 0);
        wrefresh(parent);

        let child = derwin(parent,
                           CMD_ENTRY_HEIGHT - 2,
                           size.width - 2,
                           1,
                           1);
        scrollok(child, true);

        CommandEntry {
            parent: Window::new(parent),
            child:  Window::new(child),
        }
    }

    pub fn read_input_char(&self) -> Option<char> {
        match wgetch(self.child.id) {
            -1 => None,
            i  => ::std::char::from_u32(i as u32),
        }
    }

    pub fn add_char(&self, ch: char) {
        wprintw(self.child.id, &ch.to_string());
        wrefresh(self.child.id);
    }
}

pub struct UI {
    pub chat:          Chat,
    pub command_entry: CommandEntry,
    pub channel_list:  Window,
    pub channel_stats: Window,
}

impl UI {
    fn create_channel_list(size: Size) -> Window {
        let w = newwin(size.height - STATS_PANEL_HEIGHT - CMD_ENTRY_HEIGHT,
                       RIGHT_PANEL_WIDTH,
                       0,
                       size.width - RIGHT_PANEL_WIDTH);
        box_(w, 0, 0);
        wrefresh(w);
        Window::new(w)
    }

    fn create_channel_stats(size: Size) -> Window {
        let w = newwin(STATS_PANEL_HEIGHT,
                       RIGHT_PANEL_WIDTH,
                       size.height - STATS_PANEL_HEIGHT - CMD_ENTRY_HEIGHT,
                       size.width - RIGHT_PANEL_WIDTH);
        box_(w, 0, 0);
        wrefresh(w);
        Window::new(w)
    }

    pub fn create() -> UI {
        initscr();
        start_color();
        noecho();
        curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);

        let term_size = UI::get_size_raw(stdscr());

        UI {
            chat:          Chat::new(term_size),
            command_entry: CommandEntry::new(term_size),
            channel_list:  UI::create_channel_list(term_size),
            channel_stats: UI::create_channel_stats(term_size),
        }
    }

    fn get_size_raw(window: WINDOW) -> Size {
        let mut x = 0;
        let mut y = 0;
        getmaxyx(window, &mut y, &mut x);
        Size::new(x, y)
    }
}

impl Drop for UI {
    fn drop(&mut self) {
        endwin();
    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate mdbook;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate open;

// Dependencies for the Watch feature
#[cfg(feature = "watch")]
extern crate notify;
#[cfg(feature = "watch")]
extern crate time;
#[cfg(feature = "watch")]
extern crate crossbeam;

// Dependencies for the Serve feature
#[cfg(feature = "serve")]
extern crate iron;
#[cfg(feature = "serve")]
extern crate staticfile;
#[cfg(feature = "serve")]
extern crate ws;

use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use clap::{App, ArgMatches, SubCommand, AppSettings};

// Uses for the Watch feature
#[cfg(feature = "watch")]
use notify::Watcher;
#[cfg(feature = "watch")]
use std::time::Duration;
#[cfg(feature = "watch")]
use std::sync::mpsc::channel;

use mdbook::MDBook;

const NAME: &'static str = "mdbook";

fn main() {
    env_logger::init().unwrap();

    // Create a list of valid arguments and sub-commands
    let matches = App::new(NAME)
                    .about("Create a book in form of a static website from markdown files")
                    .author("Mathieu David <mathieudavid@mathieudavid.org>")
                    // Get the version from our Cargo.toml using clap's crate_version!() macro
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .after_help("For more information about a specific command, try `mdbook <command> --help`\nSource code for mdbook available at: https://github.com/azerupi/mdBook")
                    .subcommand(SubCommand::with_name("init")
                        .about("Create boilerplate structure and files in the directory")
                        // the {n} denotes a newline which will properly aligned in all help messages
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")
                        .arg_from_usage("--theme 'Copies the default theme into your source folder'")
                        .arg_from_usage("--force 'skip confirmation prompts'"))
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
                    .subcommand(SubCommand::with_name("watch")
                        .about("Watch the files for changes")
                        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
                    .subcommand(SubCommand::with_name("serve")
                        .about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")
                        .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
                        .arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'")
                        .arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'")
                        .arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface address)'")
                        .arg_from_usage("-o, --open 'Open the book server in a web browser'"))
                    .subcommand(SubCommand::with_name("test")
                        .about("Test that code samples compile"))
                    .get_matches();

    // Check which subcomamnd the user ran...
    let res = match matches.subcommand() {
        ("init", Some(sub_matches)) => init(sub_matches),
        ("build", Some(sub_matches)) => build(sub_matches),
        #[cfg(feature = "watch")]
        ("watch", Some(sub_matches)) => watch(sub_matches),
        #[cfg(feature = "serve")]
        ("serve", Some(sub_matches)) => serve(sub_matches),
        ("test", Some(sub_matches)) => test(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
        ::std::process::exit(101);
    }
}

// Simple function that user comfirmation
fn confirm() -> bool {
    io::stdout().flush().unwrap();
    let mut s = String::new();
    io::stdin().read_line(&mut s).ok();
    match &*s.trim() {
        "Y" | "y" | "yes" | "Yes" => true,
        _ => false,
    }
}

// Init command implementation
fn init(args: &ArgMatches) -> Result<(), Box<Error>> {

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir);

    // Call the function that does the initialization
    try!(book.init());

    // If flag `--theme` is present, copy theme to src
    if args.is_present("theme") {

        // Skip this if `--force` is present
        if !args.is_present("force") {
            // Print warning
            print!("\nCopying the default theme to {:?}", book.get_src());
            println!("could potentially overwrite files already present in that directory.");
            print!("\nAre you sure you want to continue? (y/n) ");

            // Read answer from user and exit if it's not 'yes'
            if !confirm() {
                println!("\nSkipping...\n");
                println!("All done, no errors...");
                ::std::process::exit(0);
            }
        }

        // Call the function that copies the theme
        try!(book.copy_theme());
        println!("\nTheme copied.");

    }

    // Because of `src/book/mdbook.rs#L37-L39`, `dest` will always start with `root`
    let is_dest_inside_root = book.get_dest().starts_with(book.get_root());

    if !args.is_present("force") && is_dest_inside_root {
        println!("\nDo you want a .gitignore to be created? (y/n)");

        if confirm() {
            book.create_gitignore();
            println!("\n.gitignore created.");
        }
    }

    println!("\nAll done, no errors...");

    Ok(())
}

// Build command implementation
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    try!(book.build());

    if args.is_present("open") {
        open(book.get_dest().join("index.html"));
    }

    Ok(())
}

// Watch command implementation
#[cfg(feature = "watch")]
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    if args.is_present("open") {
        try!(book.build());
        open(book.get_dest().join("index.html"));
    }

    trigger_on_change(&mut book, |path, book| {
        println!("File changed: {:?}\nBuilding book...\n", path);
        match book.build() {
            Err(e) => println!("Error while building: {:?}", e),
            _ => {},
        }
        println!("");
    });

    Ok(())
}

// Watch command implementation
#[cfg(feature = "serve")]
fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
    const RELOAD_COMMAND: &'static str = "reload";

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();
    let port = args.value_of("port").unwrap_or("3000");
    let ws_port = args.value_of("ws-port").unwrap_or("3001");
    let interface = args.value_of("interface").unwrap_or("localhost");
    let public_address = args.value_of("address").unwrap_or(interface);
    let open_browser = args.is_present("open");

    let address = format!("{}:{}", interface, port);
    let ws_address = format!("{}:{}", interface, ws_port);

    book.set_livereload(format!(r#"
        <script type="text/javascript">
            var socket = new WebSocket("ws://{}:{}");
            socket.onmessage = function (event) {{
                if (event.data === "{}") {{
                    socket.close();
                    location.reload(true); // force reload from server (not from cache)
                }}
            }};

            window.onbeforeunload = function() {{
                socket.close();
            }}
        </script>
    "#, public_address, ws_port, RELOAD_COMMAND).to_owned());

    try!(book.build());

    let staticfile = staticfile::Static::new(book.get_dest());
    let iron = iron::Iron::new(staticfile);
    let _iron = iron.http(&*address).unwrap();

    let ws_server = ws::WebSocket::new(|_| {
        |_| {
            Ok(())
        }
    }).unwrap();

    let broadcaster = ws_server.broadcaster();

    std::thread::spawn(move || {
        ws_server.listen(&*ws_address).unwrap();
    });

    println!("\nServing on {}", address);

    if open_browser {
        open(format!("http://{}", address));
    }

    trigger_on_change(&mut book, move |path, book| {
        println!("File changed: {:?}\nBuilding book...\n", path);
        match book.build() {
            Err(e) => println!("Error while building: {:?}", e),
            _ => broadcaster.send(RELOAD_COMMAND).unwrap(),
        }
        println!("");
    });

    Ok(())
}

fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    try!(book.test());

    Ok(())
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}

fn open<P: AsRef<OsStr>>(path: P) {
    if let Err(e) = open::that(path) {
        println!("Error opening web browser: {}", e);
    }
}

// Calls the closure when a book source file is changed. This is blocking!
#[cfg(feature = "watch")]
fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
    where F: Fn(&Path, &mut MDBook) -> ()
{
    use notify::RecursiveMode::*;
    use notify::DebouncedEvent::*;

    // Create a channel to receive the events.
    let (tx, rx) = channel();

    let mut watcher = match notify::watcher(tx, Duration::from_secs(1)) {
        Ok(w) => w,
        Err(e) => {
            println!("Error while trying to watch the files:\n\n\t{:?}", e);
            ::std::process::exit(0);
        }
    };

    // Add the source directory to the watcher
    if let Err(e) = watcher.watch(book.get_src(), Recursive) {
        println!("Error while watching {:?}:\n    {:?}", book.get_src(), e);
        ::std::process::exit(0);
    };

    // Add the book.{json,toml} file to the watcher if it exists, because it's not
    // located in the source directory
    if let Err(_) = watcher.watch(book.get_root().join("book.json"), NonRecursive) {
        // do nothing if book.json is not found
    }
    println!("\nListening for changes...\n");

    loop {
        match rx.recv() {
            Ok(event) => match event {
                NoticeWrite(path) |
                NoticeRemove(path) |
                Create(path) |
                Write(path) |
                Remove(path) |
                Rename(_, path) => {
                    closure(&path, book);
                }
                _ => {}
            },
            Err(e) => {
                println!("An error occured: {:?}", e);
            },
        }
    }
}
<commit_msg>Watch both book.json and book.toml<commit_after>#[macro_use]
extern crate mdbook;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate open;

// Dependencies for the Watch feature
#[cfg(feature = "watch")]
extern crate notify;
#[cfg(feature = "watch")]
extern crate time;
#[cfg(feature = "watch")]
extern crate crossbeam;

// Dependencies for the Serve feature
#[cfg(feature = "serve")]
extern crate iron;
#[cfg(feature = "serve")]
extern crate staticfile;
#[cfg(feature = "serve")]
extern crate ws;

use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use clap::{App, ArgMatches, SubCommand, AppSettings};

// Uses for the Watch feature
#[cfg(feature = "watch")]
use notify::Watcher;
#[cfg(feature = "watch")]
use std::time::Duration;
#[cfg(feature = "watch")]
use std::sync::mpsc::channel;

use mdbook::MDBook;

const NAME: &'static str = "mdbook";

fn main() {
    env_logger::init().unwrap();

    // Create a list of valid arguments and sub-commands
    let matches = App::new(NAME)
                    .about("Create a book in form of a static website from markdown files")
                    .author("Mathieu David <mathieudavid@mathieudavid.org>")
                    // Get the version from our Cargo.toml using clap's crate_version!() macro
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .after_help("For more information about a specific command, try `mdbook <command> --help`\nSource code for mdbook available at: https://github.com/azerupi/mdBook")
                    .subcommand(SubCommand::with_name("init")
                        .about("Create boilerplate structure and files in the directory")
                        // the {n} denotes a newline which will properly aligned in all help messages
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")
                        .arg_from_usage("--theme 'Copies the default theme into your source folder'")
                        .arg_from_usage("--force 'skip confirmation prompts'"))
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
                    .subcommand(SubCommand::with_name("watch")
                        .about("Watch the files for changes")
                        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
                    .subcommand(SubCommand::with_name("serve")
                        .about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")
                        .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
                        .arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'")
                        .arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'")
                        .arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface address)'")
                        .arg_from_usage("-o, --open 'Open the book server in a web browser'"))
                    .subcommand(SubCommand::with_name("test")
                        .about("Test that code samples compile"))
                    .get_matches();

    // Check which subcomamnd the user ran...
    let res = match matches.subcommand() {
        ("init", Some(sub_matches)) => init(sub_matches),
        ("build", Some(sub_matches)) => build(sub_matches),
        #[cfg(feature = "watch")]
        ("watch", Some(sub_matches)) => watch(sub_matches),
        #[cfg(feature = "serve")]
        ("serve", Some(sub_matches)) => serve(sub_matches),
        ("test", Some(sub_matches)) => test(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
        ::std::process::exit(101);
    }
}

// Simple function that user comfirmation
fn confirm() -> bool {
    io::stdout().flush().unwrap();
    let mut s = String::new();
    io::stdin().read_line(&mut s).ok();
    match &*s.trim() {
        "Y" | "y" | "yes" | "Yes" => true,
        _ => false,
    }
}

// Init command implementation
fn init(args: &ArgMatches) -> Result<(), Box<Error>> {

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir);

    // Call the function that does the initialization
    try!(book.init());

    // If flag `--theme` is present, copy theme to src
    if args.is_present("theme") {

        // Skip this if `--force` is present
        if !args.is_present("force") {
            // Print warning
            print!("\nCopying the default theme to {:?}", book.get_src());
            println!("could potentially overwrite files already present in that directory.");
            print!("\nAre you sure you want to continue? (y/n) ");

            // Read answer from user and exit if it's not 'yes'
            if !confirm() {
                println!("\nSkipping...\n");
                println!("All done, no errors...");
                ::std::process::exit(0);
            }
        }

        // Call the function that copies the theme
        try!(book.copy_theme());
        println!("\nTheme copied.");

    }

    // Because of `src/book/mdbook.rs#L37-L39`, `dest` will always start with `root`
    let is_dest_inside_root = book.get_dest().starts_with(book.get_root());

    if !args.is_present("force") && is_dest_inside_root {
        println!("\nDo you want a .gitignore to be created? (y/n)");

        if confirm() {
            book.create_gitignore();
            println!("\n.gitignore created.");
        }
    }

    println!("\nAll done, no errors...");

    Ok(())
}

// Build command implementation
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    try!(book.build());

    if args.is_present("open") {
        open(book.get_dest().join("index.html"));
    }

    Ok(())
}

// Watch command implementation
#[cfg(feature = "watch")]
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    if args.is_present("open") {
        try!(book.build());
        open(book.get_dest().join("index.html"));
    }

    trigger_on_change(&mut book, |path, book| {
        println!("File changed: {:?}\nBuilding book...\n", path);
        match book.build() {
            Err(e) => println!("Error while building: {:?}", e),
            _ => {},
        }
        println!("");
    });

    Ok(())
}

// Watch command implementation
#[cfg(feature = "serve")]
fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
    const RELOAD_COMMAND: &'static str = "reload";

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();
    let port = args.value_of("port").unwrap_or("3000");
    let ws_port = args.value_of("ws-port").unwrap_or("3001");
    let interface = args.value_of("interface").unwrap_or("localhost");
    let public_address = args.value_of("address").unwrap_or(interface);
    let open_browser = args.is_present("open");

    let address = format!("{}:{}", interface, port);
    let ws_address = format!("{}:{}", interface, ws_port);

    book.set_livereload(format!(r#"
        <script type="text/javascript">
            var socket = new WebSocket("ws://{}:{}");
            socket.onmessage = function (event) {{
                if (event.data === "{}") {{
                    socket.close();
                    location.reload(true); // force reload from server (not from cache)
                }}
            }};

            window.onbeforeunload = function() {{
                socket.close();
            }}
        </script>
    "#, public_address, ws_port, RELOAD_COMMAND).to_owned());

    try!(book.build());

    let staticfile = staticfile::Static::new(book.get_dest());
    let iron = iron::Iron::new(staticfile);
    let _iron = iron.http(&*address).unwrap();

    let ws_server = ws::WebSocket::new(|_| {
        |_| {
            Ok(())
        }
    }).unwrap();

    let broadcaster = ws_server.broadcaster();

    std::thread::spawn(move || {
        ws_server.listen(&*ws_address).unwrap();
    });

    println!("\nServing on {}", address);

    if open_browser {
        open(format!("http://{}", address));
    }

    trigger_on_change(&mut book, move |path, book| {
        println!("File changed: {:?}\nBuilding book...\n", path);
        match book.build() {
            Err(e) => println!("Error while building: {:?}", e),
            _ => broadcaster.send(RELOAD_COMMAND).unwrap(),
        }
        println!("");
    });

    Ok(())
}

fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    try!(book.test());

    Ok(())
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}

fn open<P: AsRef<OsStr>>(path: P) {
    if let Err(e) = open::that(path) {
        println!("Error opening web browser: {}", e);
    }
}

// Calls the closure when a book source file is changed. This is blocking!
#[cfg(feature = "watch")]
fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
    where F: Fn(&Path, &mut MDBook) -> ()
{
    use notify::RecursiveMode::*;
    use notify::DebouncedEvent::*;

    // Create a channel to receive the events.
    let (tx, rx) = channel();

    let mut watcher = match notify::watcher(tx, Duration::from_secs(1)) {
        Ok(w) => w,
        Err(e) => {
            println!("Error while trying to watch the files:\n\n\t{:?}", e);
            ::std::process::exit(0);
        }
    };

    // Add the source directory to the watcher
    if let Err(e) = watcher.watch(book.get_src(), Recursive) {
        println!("Error while watching {:?}:\n    {:?}", book.get_src(), e);
        ::std::process::exit(0);
    };

    // Add the book.{json,toml} file to the watcher if it exists, because it's not
    // located in the source directory
    if let Err(_) = watcher.watch(book.get_root().join("book.json"), NonRecursive) {
        // do nothing if book.json is not found
    }
    if let Err(_) = watcher.watch(book.get_root().join("book.toml"), NonRecursive) {
        // do nothing if book.toml is not found
    }

    println!("\nListening for changes...\n");

    loop {
        match rx.recv() {
            Ok(event) => match event {
                NoticeWrite(path) |
                NoticeRemove(path) |
                Create(path) |
                Write(path) |
                Remove(path) |
                Rename(_, path) => {
                    closure(&path, book);
                }
                _ => {}
            },
            Err(e) => {
                println!("An error occured: {:?}", e);
            },
        }
    }
}
<|endoftext|>


<commit_before>//! Traits and implementations for parsing.

use std::error;
use std::fmt;
use byteorder::{BigEndian, ByteOrder};

//------------ Parser --------------------------------------------------------

#[derive(Clone, Debug)]
pub struct Parser<'a> {
    bytes: &'a [u8],
    pos: usize,
    limit: usize,
}

impl<'a> Parser<'a> {
    pub fn new(bytes: &'a [u8]) -> Self {
        Parser{limit: bytes.len(), bytes: bytes, pos: 0}
    }

    /// Limits the parser to `len` bytes from its current position.
    ///
    /// If the limit would be beyond the end of the parser, returns
    /// `Err(ParseError::UnexpectedEnd)`.
    pub fn set_limit(&mut self, len: usize) -> ParseResult<()> {
        let limit = self.pos + len;
        if len > self.bytes.len() {
            Err(ParseError::UnexpectedEnd)
        }
        else {
            self.limit = limit;
            Ok(())
        }
    }

    /// Removes any limit from the parser.
    pub fn remove_limit(&mut self) {
        self.limit = self.bytes.len()
    }
}

impl<'a> Parser<'a> {
    /// Returns a reference to the complete message.
    ///
    /// The returned slice contains all bytes. It disregards the current
    /// position and any limit.
    pub fn bytes(&self) -> &'a [u8] {
        self.bytes
    }

    /// Returns the current parser position.
    ///
    /// This is the index in `self.bytes()` where the next octet would be
    /// read.
    pub fn pos(&self) -> usize {
        self.pos
    }

    /// Returns the number of bytes left to parse.
    ///
    /// If a limit is set, the returned number is up until that limit.
    pub fn remaining(&self) -> usize {
        self.limit - self.pos
    }

    /// Resets the position of the parser.
    ///
    /// The new position is relative to the beginning of the parser’s message.
    /// The function fails if the position is beyond the end of the message
    /// or, if a limit is set, beyond the limit. In either case, the
    /// function will return `Err(ParseError::UnexpectedEnd)`.
    pub fn seek(&mut self, pos: usize) -> ParseResult<()> {
        if pos > self.limit {
            Err(ParseError::UnexpectedEnd)
        }
        else {
            self.pos = pos;
            Ok(())
        }
    }
}

impl<'a> Parser<'a> {
    /// Skips over `len` bytes.
    ///
    /// If this would go beyond the current limit or the end of the message,
    /// returns `Err(ParseError::UnexpectedEnd)`.
    pub fn skip(&mut self, len: usize) -> ParseResult<()> {
        self.parse_bytes(len).map(|_| ())
    }

    /// Parses a bytes slice of the given length.
    ///
    /// The slice returned upon success references the parser’s message
    /// directly. The parser’s position is advanced until the end of the
    /// slice.
    ///
    /// The method will return `Err(ParseError::UnexpectedEnd)` if the
    /// length would take the parser beyond the current limit or the
    /// end of the message.
    pub fn parse_bytes(&mut self, len: usize) -> ParseResult<&'a [u8]> {
        let end = self.pos + len;
        if end > self.limit {
            return Err(ParseError::UnexpectedEnd)
        }
        let res = &self.bytes[self.pos..end];
        self.pos = end;
        Ok(res)
    }

    pub fn parse_u8(&mut self) -> ParseResult<u8> {
        self.parse_bytes(1).map(|res| res[0])
    }

    pub fn parse_u16(&mut self) -> ParseResult<u16> {
        self.parse_bytes(2).map(BigEndian::read_u16)
    }

    pub fn parse_u32(&mut self) -> ParseResult<u32> {
        self.parse_bytes(4).map(BigEndian::read_u32)
    }
}

//------------ ParseError and ParseResult -----------------------------------

/// An error happening during parsing of wire-format DNS data.
#[derive(Clone, Debug, PartialEq)]
pub enum ParseError {
    /// The raw data ended unexpectedly in the middle of a structure.
    UnexpectedEnd,

    /// An unknown label type was encountered in a domain name.
    ///
    /// Several possible values for label types are not currently assigned
    /// (and likely never will). This is fatal since the label type defines
    /// how a label is parsed.
    UnknownLabel,

    /// A format error was encountered.
    FormErr,
}

impl error::Error for ParseError {
    fn description(&self) -> &str {
        use self::ParseError::*;

        match *self {
            UnexpectedEnd => "unexpected end of data",
            UnknownLabel => "unknown label type in domain name",
            FormErr => "format error",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        error::Error::description(self).fmt(f)
    }
}

/// The result type for a `ParseError`.
pub type ParseResult<T> = Result<T, ParseError>;

<commit_msg>Add some documentation and tests to ::bits::parse.<commit_after>//! Parsing of DNS wire-format data.
//!
//! This module contains [`Parser`], the type wrapping the data of a DNS
//! message for parsing, as well as the error and result types for parsing.
//! You will only need to deal with parsing directly if you implement new
//! record data types. Otherwise, the [`Message`] type wraps everyhing up
//! in a nice, easy to use interface.
//!
//! [`Parser`]: struct.Parser.html
//! [`Message`]: ../message/struct.Message.html

use std::error;
use std::fmt;
use byteorder::{BigEndian, ByteOrder};

//------------ Parser --------------------------------------------------------

/// A type wrapping DNS message data for parsing.
///
/// Because of name compression, a full message needs to be available for
/// parsing of DNS data. If you have received a message over the wire, you
/// can use it to create a parser via the [`new()`] function.
///
/// The parser then allows you to successively parse one item after the other
/// out of the message via a few methods prefixed with `parse_`. Further
/// methods are available to retrieve some information about the parser
/// state, seek to a new position, or limit the amount of data the parser
/// allows to retrieve.
///
/// Parsers are `Clone`, so you can keep around a copy of a parser for later
/// use. This is, for instance, done by [`ParsedDName`] in order to be able
/// to rummage around the message bytes to find all its labels.
///
/// [`new()`]: #method.new
/// [`ParsedDName`]: ../name/struct.ParsedDName.html
#[derive(Clone, Debug)]
pub struct Parser<'a> {
    bytes: &'a [u8],
    pos: usize,
    limit: usize,
}

impl<'a> Parser<'a> {
    /// Creates a new parser atop a bytes slice.
    pub fn new(bytes: &'a [u8]) -> Self {
        Parser{limit: bytes.len(), bytes: bytes, pos: 0}
    }

    /// Limits the parser to `len` bytes from its current position.
    ///
    /// If the limit would be beyond the end of the parser, returns
    /// `Err(ParseError::UnexpectedEnd)`.
    pub fn set_limit(&mut self, len: usize) -> ParseResult<()> {
        let limit = self.pos + len;
        if len > self.bytes.len() {
            Err(ParseError::UnexpectedEnd)
        }
        else {
            self.limit = limit;
            Ok(())
        }
    }

    /// Removes any limit from the parser.
    pub fn remove_limit(&mut self) {
        self.limit = self.bytes.len()
    }
}

impl<'a> Parser<'a> {
    /// Returns a reference to the complete message.
    ///
    /// The returned slice contains all bytes. It disregards the current
    /// position and any limit.
    pub fn bytes(&self) -> &'a [u8] {
        self.bytes
    }

    /// Returns the current parser position.
    ///
    /// This is the index in `self.bytes()` where the next octet would be
    /// read.
    pub fn pos(&self) -> usize {
        self.pos
    }

    /// Returns the number of bytes left to parse.
    ///
    /// If a limit is set, the returned number is up until that limit.
    pub fn remaining(&self) -> usize {
        self.limit - self.pos
    }

    /// Resets the position of the parser.
    ///
    /// The new position is relative to the beginning of the parser’s message.
    /// The function fails if the position is beyond the end of the message
    /// or, if a limit is set, beyond the limit. In either case, the
    /// function will return `Err(ParseError::UnexpectedEnd)`.
    pub fn seek(&mut self, pos: usize) -> ParseResult<()> {
        if pos > self.limit {
            Err(ParseError::UnexpectedEnd)
        }
        else {
            self.pos = pos;
            Ok(())
        }
    }
}

impl<'a> Parser<'a> {
    /// Skips over `len` bytes.
    ///
    /// If this would go beyond the current limit or the end of the message,
    /// returns `Err(ParseError::UnexpectedEnd)`.
    pub fn skip(&mut self, len: usize) -> ParseResult<()> {
        self.parse_bytes(len).map(|_| ())
    }

    /// Parses a bytes slice of the given length.
    ///
    /// The slice returned upon success references the parser’s message
    /// directly. The parser’s position is advanced until the end of the
    /// slice.
    ///
    /// The method will return `Err(ParseError::UnexpectedEnd)` if the
    /// length would take the parser beyond the current limit or the
    /// end of the message.
    pub fn parse_bytes(&mut self, len: usize) -> ParseResult<&'a [u8]> {
        let end = self.pos + len;
        if end > self.limit {
            return Err(ParseError::UnexpectedEnd)
        }
        let res = &self.bytes[self.pos..end];
        self.pos = end;
        Ok(res)
    }

    pub fn parse_u8(&mut self) -> ParseResult<u8> {
        self.parse_bytes(1).map(|res| res[0])
    }

    pub fn parse_u16(&mut self) -> ParseResult<u16> {
        self.parse_bytes(2).map(BigEndian::read_u16)
    }

    pub fn parse_u32(&mut self) -> ParseResult<u32> {
        self.parse_bytes(4).map(BigEndian::read_u32)
    }
}

//------------ ParseError and ParseResult -----------------------------------

/// An error happening during parsing of wire-format DNS data.
#[derive(Clone, Debug, PartialEq)]
pub enum ParseError {
    /// The raw data ended unexpectedly in the middle of a structure.
    UnexpectedEnd,

    /// An unknown label type was encountered in a domain name.
    ///
    /// Several possible values for label types are not currently assigned
    /// (and likely never will). This is fatal since the label type defines
    /// how a label is parsed.
    UnknownLabel,

    /// A format error was encountered.
    FormErr,
}

impl error::Error for ParseError {
    fn description(&self) -> &str {
        use self::ParseError::*;

        match *self {
            UnexpectedEnd => "unexpected end of data",
            UnknownLabel => "unknown label type in domain name",
            FormErr => "format error",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        error::Error::description(self).fmt(f)
    }
}

/// The result type for a `ParseError`.
pub type ParseResult<T> = Result<T, ParseError>;

//============ Testing ======================================================

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

    fn check(parser: &Parser, pos: usize, left: &[u8]) {
        assert_eq!(parser.pos(), pos);
        assert_eq!(parser.remaining(), left.len());
        assert_eq!(&parser.bytes()[pos..], left)
    }

    #[test]
    fn parse_bytes_ok() {
        let mut parser = Parser::new(b"123456");
        check(&parser, 0, b"123456");
        assert_eq!(parser.parse_bytes(0).unwrap(), b"");
        check(&parser, 0, b"123456");
        assert_eq!(parser.parse_bytes(4).unwrap(), b"1234");
        check(&parser, 4, b"56");
        assert_eq!(parser.parse_bytes(2).unwrap(), b"56");
        check(&parser, 6, b"");
        assert_eq!(parser.parse_bytes(0).unwrap(), b"");
        check(&parser, 6, b"");
    }

    #[test]
    fn parse_bytes_err() {
        let mut parser = Parser::new(b"123456");
        check(&parser, 0, b"123456");
        assert_eq!(parser.parse_bytes(8), Err(ParseError::UnexpectedEnd));
        check(&parser, 0, b"123456");
    }

    #[test]
    fn skip() {
        let mut parser = Parser::new(b"123456");
        check(&parser, 0, b"123456");
        parser.skip(2).unwrap();
        check(&parser, 2, b"3456");
        assert_eq!(parser.skip(6), Err(ParseError::UnexpectedEnd));
        check(&parser, 2, b"3456");
    }

    #[test]
    fn parse_u8() {
        let mut parser = Parser::new(b"123");
        check(&parser, 0, b"123");
        assert_eq!(parser.parse_u8().unwrap(), b'1');
        check(&parser, 1, b"23");
    }

    #[test]
    fn parse_u16() {
        let mut parser = Parser::new(b"\x12\x3456");
        check(&parser, 0, b"\x12\x3456");
        assert_eq!(parser.parse_u16().unwrap(), 0x1234);
        check(&parser, 2, b"56");
    }

    #[test]
    fn parse_u32() {
        let mut parser = Parser::new(b"\x12\x34\x56\x7890");
        check(&parser, 0, b"\x12\x34\x56\x7890");
        assert_eq!(parser.parse_u32().unwrap(), 0x12345678);
        check(&parser, 4, b"90");
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate apache2;

apache2_module!(https_www_handler, c_https_www_handler, https_www_module, b"mod_https_www\0");

fn https_www_handler(r: &mut apache2::Request) -> apache2::Status {
   r.write("Redirect to https and www.");

   apache2::Status::OK
}
<commit_msg>Full implementation of the https/www redirect.<commit_after>#![feature(collections)]

#[macro_use]
extern crate apache2;

apache2_module!(https_www_handler, c_https_www_handler, https_www_module, b"mod_https_www\0");

fn https_www_handler(r: &mut apache2::Request) -> apache2::Status {
   let scheme = match r.http_scheme() {
      None => {
         return apache2::Status::HTTP_INTERNAL_SERVER_ERROR;
      },
      Some(scheme) => scheme
   };

   let hostname = match r.hostname() {
      None => {
         return apache2::Status::HTTP_INTERNAL_SERVER_ERROR;
      },
      Some(hostname) => hostname
   };

   let already_www = &hostname[..4] == "www.";
   let already_https = scheme == "https";

   if already_www && already_https {
      return apache2::Status::DECLINED;
   };

   let full_hostname = if already_www {
      String::from_str(hostname)
   } else {
      format!("www.{}", hostname)
   };

   let uri = match r.unparsed_uri() {
      None => {
         return apache2::Status::HTTP_INTERNAL_SERVER_ERROR;
      },
      Some(uri) => uri
   };

   let location = format!("https://{}{}", full_hostname, uri);
   r.headers_out().unwrap().set("Location", location);

   r.set_status(apache2::Status::HTTP_MOVED_PERMANENTLY);

   apache2::Status::DONE
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate piston_window;
extern crate vecmath;
extern crate camera_controllers;
#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate glfw_window;

use std::cell::RefCell;
use std::rc::Rc;
use piston_window::*;
use piston::event::*;
use piston::window::{ AdvancedWindow, WindowSettings };
use camera_controllers::{
    FirstPersonSettings,
    FirstPerson,
    CameraPerspective,
    model_view_projection
};
use gfx::attrib::Floater;
use gfx::traits::*;
use glfw_window::{ GlfwWindow, OpenGL };

//----------------------------------------
// Cube associated data

gfx_vertex!( Vertex {
    a_pos@ a_pos: [Floater<i8>; 3],
    a_tex_coord@ a_tex_coord: [Floater<u8>; 2],
});

impl Vertex {
    fn new(pos: [i8; 3], tc: [u8; 2]) -> Vertex {
        Vertex {
            a_pos: Floater::cast3(pos),
            a_tex_coord: Floater::cast2(tc),
        }
    }
}

gfx_parameters!( Params/ParamsLink {
    u_model_view_proj@ u_model_view_proj: [[f32; 4]; 4],
    t_color@ t_color: gfx::shade::TextureParam<R>,
});

//----------------------------------------

fn main() {
    let (win_width, win_height) = (640, 480);
    let window = Rc::new(RefCell::new(GlfwWindow::new(
        OpenGL::_3_2,
        WindowSettings::new("piston-example-gfx_cube", [win_width, win_height])
        .exit_on_esc(true)
        .samples(4)
    ).capture_cursor(true)));

    let events = PistonWindow::new(window, empty_app());

    let vertex_data = vec![
        //top (0, 0, 1)
        Vertex::new([-1, -1,  1], [0, 0]),
        Vertex::new([ 1, -1,  1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //bottom (0, 0, -1)
        Vertex::new([ 1,  1, -1], [0, 0]),
        Vertex::new([-1,  1, -1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
        //right (1, 0, 0)
        Vertex::new([ 1, -1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([ 1, -1,  1], [0, 1]),
        //left (-1, 0, 0)
        Vertex::new([-1,  1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([-1,  1, -1], [0, 1]),
        //front (0, 1, 0)
        Vertex::new([-1,  1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //back (0, -1, 0)
        Vertex::new([ 1, -1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
    ];

    let mesh = events.canvas.borrow_mut().factory.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
         0,  1,  2,  2,  3,  0, // top
         4,  6,  5,  6,  4,  7, // bottom
         8,  9, 10, 10, 11,  8, // right
        12, 14, 13, 14, 12, 16, // left
        16, 18, 17, 18, 16, 19, // front
        20, 21, 22, 22, 23, 20, // back
    ];

    let slice = events.canvas.borrow_mut().factory.create_buffer_index(index_data)
                       .to_slice(gfx::PrimitiveType::TriangleList);

    let tinfo = gfx::tex::TextureInfo {
        width: 1, height: 1, depth: 1, levels: 1,
        kind: gfx::tex::TextureKind::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let img_info = tinfo.to_image_info();
    let texture = events.canvas.borrow_mut().factory.create_texture(tinfo).unwrap();
    events.canvas.borrow_mut().factory.update_texture(
        &texture,
        &img_info,
        &[0x20u8, 0xA0, 0xC0, 0x00],
        Some(gfx::tex::TextureKind::Texture2D)
    ).unwrap();

    let sampler = events.canvas.borrow_mut().factory.create_sampler(
        gfx::tex::SamplerInfo::new(gfx::tex::FilterMethod::Bilinear,
            gfx::tex::WrapMode::Clamp));

    let program = {
        let canvas = &mut *events.canvas.borrow_mut();
        let vertex = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("cube_120.glslv")),
            glsl_150: Some(include_bytes!("cube_150.glslv")),
            .. gfx::ShaderSource::empty()
        };
        let fragment = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("cube_120.glslf")),
            glsl_150: Some(include_bytes!("cube_150.glslf")),
            .. gfx::ShaderSource::empty()
        };
        canvas.factory.link_program_source(vertex, fragment,
            &canvas.device.get_capabilities()).unwrap()
    };

    let mut data = Params {
        u_model_view_proj: vecmath::mat4_id(),
        t_color: (texture, Some(sampler)),
        _r: std::marker::PhantomData,
    };

    let get_projection = |w: &PistonWindow<GlfwWindow>| {
        use piston::window::Window;

        let draw_size = w.window.borrow().draw_size();
        CameraPerspective {
            fov: 90.0, near_clip: 0.1, far_clip: 1000.0,
            aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32)
        }.projection()
    };

    let model = vecmath::mat4_id();
    let mut projection = get_projection(&events);
    let mut first_person = FirstPerson::new([0.5, 0.5, 4.0],
        FirstPersonSettings::keyboard_wasd());
    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    for e in events {
        first_person.event(&e);

        e.draw_3d(|canvas| {
            let args = e.render_args().unwrap();
            canvas.renderer.clear(
                gfx::ClearData {
                    color: [0.3, 0.3, 0.3, 1.0],
                    depth: 1.0,
                    stencil: 0,
                },
                gfx::COLOR | gfx::DEPTH,
                &canvas.output
            );
            data.u_model_view_proj = model_view_projection(
                model,
                first_person.camera(args.ext_dt).orthogonal(),
                projection
            );
            canvas.renderer.draw(&(&mesh, slice.clone(), &program, &data, &state),
                &canvas.output).unwrap();
        });

        if let Some(_) = e.resize_args() {
            projection = get_projection(&e);
        }
    }
}
<commit_msg>Upgrade gfx_cube example to latest gfx<commit_after>extern crate piston;
extern crate piston_window;
extern crate vecmath;
extern crate camera_controllers;
#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate glfw_window;

use std::cell::RefCell;
use std::rc::Rc;
use piston_window::*;
use piston::event::*;
use piston::window::{ AdvancedWindow, WindowSettings };
use camera_controllers::{
    FirstPersonSettings,
    FirstPerson,
    CameraPerspective,
    model_view_projection
};
use gfx::attrib::Floater;
use gfx::traits::*;
use glfw_window::{ GlfwWindow, OpenGL };

//----------------------------------------
// Cube associated data

gfx_vertex!( Vertex {
    a_pos@ a_pos: [Floater<i8>; 3],
    a_tex_coord@ a_tex_coord: [Floater<u8>; 2],
});

impl Vertex {
    fn new(pos: [i8; 3], tc: [u8; 2]) -> Vertex {
        Vertex {
            a_pos: Floater::cast3(pos),
            a_tex_coord: Floater::cast2(tc),
        }
    }
}

gfx_parameters!( Params {
    u_model_view_proj@ u_model_view_proj: [[f32; 4]; 4],
    t_color@ t_color: gfx::shade::TextureParam<R>,
});

//----------------------------------------

fn main() {
    let window = Rc::new(RefCell::new(GlfwWindow::new(
        OpenGL::_3_2,
        WindowSettings::new("piston-example-gfx_cube", [640, 480])
        .exit_on_esc(true)
        .samples(4)
    ).capture_cursor(true)));

    let events = PistonWindow::new(window, empty_app());

    let ref mut factory = events.device.borrow().spawn_factory();

    let vertex_data = vec![
        //top (0, 0, 1)
        Vertex::new([-1, -1,  1], [0, 0]),
        Vertex::new([ 1, -1,  1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //bottom (0, 0, -1)
        Vertex::new([ 1,  1, -1], [0, 0]),
        Vertex::new([-1,  1, -1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
        //right (1, 0, 0)
        Vertex::new([ 1, -1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([ 1, -1,  1], [0, 1]),
        //left (-1, 0, 0)
        Vertex::new([-1,  1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([-1,  1, -1], [0, 1]),
        //front (0, 1, 0)
        Vertex::new([-1,  1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //back (0, -1, 0)
        Vertex::new([ 1, -1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
    ];

    let mesh = factory.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
         0,  1,  2,  2,  3,  0, // top
         4,  6,  5,  6,  4,  7, // bottom
         8,  9, 10, 10, 11,  8, // right
        12, 14, 13, 14, 12, 16, // left
        16, 18, 17, 18, 16, 19, // front
        20, 21, 22, 22, 23, 20, // back
    ];

    let slice = index_data.to_slice(factory, gfx::PrimitiveType::TriangleList);

    let texture = factory.create_texture_rgba8_static(1, 1, &[0x00_C0_A0_20]).unwrap();

    let sampler = factory.create_sampler(
        gfx::tex::SamplerInfo::new(gfx::tex::FilterMethod::Bilinear,
                                   gfx::tex::WrapMode::Clamp)
    );

    let program = {
        let vertex = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("cube_120.glslv")),
            glsl_150: Some(include_bytes!("cube_150.glslv")),
            .. gfx::ShaderSource::empty()
        };
        let fragment = gfx::ShaderSource {
            glsl_120: Some(include_bytes!("cube_120.glslf")),
            glsl_150: Some(include_bytes!("cube_150.glslf")),
            .. gfx::ShaderSource::empty()
        };
        factory.link_program_source(vertex, fragment).unwrap()
    };

    let mut data = Params {
        u_model_view_proj: vecmath::mat4_id(),
        t_color: (texture, Some(sampler)),
        _r: std::marker::PhantomData,
    };

    let get_projection = |w: &PistonWindow<GlfwWindow>| {
        use piston::window::Window;

        let draw_size = w.window.borrow().draw_size();
        CameraPerspective {
            fov: 90.0, near_clip: 0.1, far_clip: 1000.0,
            aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32)
        }.projection()
    };

    let model = vecmath::mat4_id();
    let mut projection = get_projection(&events);
    let mut first_person = FirstPerson::new(
        [0.5, 0.5, 4.0],
        FirstPersonSettings::keyboard_wasd()
    );
    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    for e in events {
        first_person.event(&e);

        e.draw_3d(|stream| {
            let args = e.render_args().unwrap();
            stream.clear(
                gfx::ClearData {
                    color: [0.3, 0.3, 0.3, 1.0],
                    depth: 1.0,
                    stencil: 0,
                }
            );
            data.u_model_view_proj = model_view_projection(
                model,
                first_person.camera(args.ext_dt).orthogonal(),
                projection
            );
            stream.draw(&(&mesh, slice.clone(), &program, &data, &state)).unwrap();
        });

        if let Some(_) = e.resize_args() {
            projection = get_projection(&e);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]
#![feature(globs)]
#![crate_name = "cube"]

extern crate gfx;
extern crate piston;
// extern crate glfw_game_window;
extern crate sdl2;
extern crate sdl2_game_window;
#[phase(plugin)]
extern crate gfx_macros;
extern crate native;
extern crate time;

// use glfw_game_window::WindowGLFW;
use sdl2_game_window::WindowSDL2;
use gfx::{Device, DeviceHelper};
use piston::{cam, Window};
//----------------------------------------
// Cube associated data

#[vertex_format]
struct Vertex {
    #[as_float]
    a_pos: [i8, ..3],
    #[as_float]
    a_tex_coord: [u8, ..2],
}

impl Vertex {
    fn new(pos: [i8, ..3], tc: [u8, ..2]) -> Vertex {
        Vertex {
            a_pos: pos,
            a_tex_coord: tc,
        }
    }
}

#[shader_param(CubeBatch)]
struct Params {
    u_model_view_proj: [[f32, ..4], ..4],
    t_color: gfx::shade::TextureParam,
}

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    attribute vec3 a_pos;
    attribute vec2 a_tex_coord;
    varying vec2 v_TexCoord;
    uniform mat4 u_model_view_proj;
    void main() {
        v_TexCoord = a_tex_coord;
        gl_Position = u_model_view_proj * vec4(a_pos, 1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec3 a_pos;
    in vec2 a_tex_coord;
    out vec2 v_TexCoord;
    uniform mat4 u_model_view_proj;
    void main() {
        v_TexCoord = a_tex_coord;
        gl_Position = u_model_view_proj * vec4(a_pos, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    varying vec2 v_TexCoord;
    uniform sampler2D t_color;
    void main() {
        vec4 tex = texture2D(t_color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        gl_FragColor = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec2 v_TexCoord;
    out vec4 o_Color;
    uniform sampler2D t_color;
    void main() {
        vec4 tex = texture(t_color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        o_Color = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
};

//----------------------------------------

// We need to run on the main thread, so ensure we are using the `native` runtime. This is
// technically not needed, since this is the default, but it's not guaranteed.
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
     native::start(argc, argv, main)
}

fn main() {
    let (win_width, win_height) = (640, 480);
    let mut window = WindowSDL2::new(
        piston::shader_version::opengl::OpenGL_3_2,
        piston::WindowSettings {
            title: "cube".to_string(),
            size: [win_width, win_height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    window.capture_cursor(true);

    let mut device = gfx::GlDevice::new(|s| unsafe {
        std::mem::transmute(sdl2::video::gl_get_proc_address(s))
    });
    let frame = gfx::Frame::new(win_width as u16, win_height as u16);
    //let (mut device, frame) = window.gfx();
    let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

    let vertex_data = vec![
        //top (0, 0, 1)
        Vertex::new([-1, -1,  1], [0, 0]),
        Vertex::new([ 1, -1,  1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //bottom (0, 0, -1)
        Vertex::new([ 1,  1, -1], [0, 0]),
        Vertex::new([-1,  1, -1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
        //right (1, 0, 0)
        Vertex::new([ 1, -1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([ 1, -1,  1], [0, 1]),
        //left (-1, 0, 0)
        Vertex::new([-1,  1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([-1,  1, -1], [0, 1]),
        //front (0, 1, 0)
        Vertex::new([-1,  1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //back (0, -1, 0)
        Vertex::new([ 1, -1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
    ];

    let mesh = device.create_mesh(vertex_data.as_slice());

    let slice = {
        let index_data = vec![
            0u8, 1, 2, 2, 3, 0,    //top
            4, 5, 6, 6, 7, 4,       //bottom
            8, 9, 10, 10, 11, 8,    //right
            12, 13, 14, 14, 16, 12, //left
            16, 17, 18, 18, 19, 16, //front
            20, 21, 22, 22, 23, 20, //back
        ];

        let buf = device.create_buffer_static(index_data.as_slice());
        gfx::IndexSlice8(gfx::TriangleList, buf, 0, 36)
    };

    let tinfo = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        levels: 1,
        kind: gfx::tex::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let img_info = tinfo.to_image_info();
    let texture = device.create_texture(tinfo).unwrap();
    device.update_texture(
            &texture,
            &img_info,
            vec![0x20u8, 0xA0u8, 0xC0u8, 0x00u8].as_slice()
        ).unwrap();

    let sampler = device.create_sampler(
        gfx::tex::SamplerInfo::new(
            gfx::tex::Bilinear,
            gfx::tex::Clamp
        )
    );

    let program = device.link_program(
            VERTEX_SRC.clone(),
            FRAGMENT_SRC.clone()
        ).unwrap();

    let mut graphics = gfx::Graphics::new(device);
    let batch: CubeBatch = graphics.make_batch(&program, &mesh, slice, &state).unwrap();

    let mut data = Params {
        u_model_view_proj: piston::vecmath::mat4_id(),
        t_color: (texture, Some(sampler)),
    };

    let model = piston::vecmath::mat4_id();
    let projection = cam::CameraPerspective {
            fov: 90.0f32,
            near_clip: 0.1,
            far_clip: 1000.0,
            aspect_ratio: (win_width as f32) / (win_height as f32)
        }.projection();
    let mut first_person = cam::FirstPerson::new(
        [0.5f32, 0.5, 4.0],
        cam::FirstPersonSettings::keyboard_wasd()
    );

    let mut game_iter = piston::EventIterator::new(
        &mut window,
        &piston::EventSettings {
            updates_per_second: 120,
            max_frames_per_second: 60
        }
    );

    for e in game_iter {
        match e {
            piston::Render(args) => {
                graphics.clear(
                    gfx::ClearData {
                        color: [0.3, 0.3, 0.3, 1.0],
                        depth: 1.0,
                        stencil: 0,
                    },
                    gfx::Color | gfx::Depth,
                    &frame
                );
                data.u_model_view_proj = cam::model_view_projection(
                        model,
                        first_person.camera(args.ext_dt).orthogonal(),
                        projection
                    );
                graphics.draw(&batch, &data, &frame);
                graphics.end_frame();
            },
            piston::Update(args) => first_person.update(args.dt),
            piston::Input(e) => first_person.input(&e),
        }
    }
}

<commit_msg>Remove commented out line<commit_after>#![feature(phase)]
#![feature(globs)]
#![crate_name = "cube"]

extern crate gfx;
extern crate piston;
// extern crate glfw_game_window;
extern crate sdl2;
extern crate sdl2_game_window;
#[phase(plugin)]
extern crate gfx_macros;
extern crate native;
extern crate time;

// use glfw_game_window::WindowGLFW;
use sdl2_game_window::WindowSDL2;
use gfx::{Device, DeviceHelper};
use piston::{cam, Window};
//----------------------------------------
// Cube associated data

#[vertex_format]
struct Vertex {
    #[as_float]
    a_pos: [i8, ..3],
    #[as_float]
    a_tex_coord: [u8, ..2],
}

impl Vertex {
    fn new(pos: [i8, ..3], tc: [u8, ..2]) -> Vertex {
        Vertex {
            a_pos: pos,
            a_tex_coord: tc,
        }
    }
}

#[shader_param(CubeBatch)]
struct Params {
    u_model_view_proj: [[f32, ..4], ..4],
    t_color: gfx::shade::TextureParam,
}

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    attribute vec3 a_pos;
    attribute vec2 a_tex_coord;
    varying vec2 v_TexCoord;
    uniform mat4 u_model_view_proj;
    void main() {
        v_TexCoord = a_tex_coord;
        gl_Position = u_model_view_proj * vec4(a_pos, 1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec3 a_pos;
    in vec2 a_tex_coord;
    out vec2 v_TexCoord;
    uniform mat4 u_model_view_proj;
    void main() {
        v_TexCoord = a_tex_coord;
        gl_Position = u_model_view_proj * vec4(a_pos, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    varying vec2 v_TexCoord;
    uniform sampler2D t_color;
    void main() {
        vec4 tex = texture2D(t_color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        gl_FragColor = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec2 v_TexCoord;
    out vec4 o_Color;
    uniform sampler2D t_color;
    void main() {
        vec4 tex = texture(t_color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        o_Color = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
};

//----------------------------------------

// We need to run on the main thread, so ensure we are using the `native` runtime. This is
// technically not needed, since this is the default, but it's not guaranteed.
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
     native::start(argc, argv, main)
}

fn main() {
    let (win_width, win_height) = (640, 480);
    let mut window = WindowSDL2::new(
        piston::shader_version::opengl::OpenGL_3_2,
        piston::WindowSettings {
            title: "cube".to_string(),
            size: [win_width, win_height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    window.capture_cursor(true);

    let mut device = gfx::GlDevice::new(|s| unsafe {
        std::mem::transmute(sdl2::video::gl_get_proc_address(s))
    });
    let frame = gfx::Frame::new(win_width as u16, win_height as u16);
    let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

    let vertex_data = vec![
        //top (0, 0, 1)
        Vertex::new([-1, -1,  1], [0, 0]),
        Vertex::new([ 1, -1,  1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //bottom (0, 0, -1)
        Vertex::new([ 1,  1, -1], [0, 0]),
        Vertex::new([-1,  1, -1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
        //right (1, 0, 0)
        Vertex::new([ 1, -1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([ 1, -1,  1], [0, 1]),
        //left (-1, 0, 0)
        Vertex::new([-1,  1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([-1,  1, -1], [0, 1]),
        //front (0, 1, 0)
        Vertex::new([-1,  1, -1], [0, 0]),
        Vertex::new([ 1,  1, -1], [1, 0]),
        Vertex::new([ 1,  1,  1], [1, 1]),
        Vertex::new([-1,  1,  1], [0, 1]),
        //back (0, -1, 0)
        Vertex::new([ 1, -1,  1], [0, 0]),
        Vertex::new([-1, -1,  1], [1, 0]),
        Vertex::new([-1, -1, -1], [1, 1]),
        Vertex::new([ 1, -1, -1], [0, 1]),
    ];

    let mesh = device.create_mesh(vertex_data.as_slice());

    let slice = {
        let index_data = vec![
            0u8, 1, 2, 2, 3, 0,    //top
            4, 5, 6, 6, 7, 4,       //bottom
            8, 9, 10, 10, 11, 8,    //right
            12, 13, 14, 14, 16, 12, //left
            16, 17, 18, 18, 19, 16, //front
            20, 21, 22, 22, 23, 20, //back
        ];

        let buf = device.create_buffer_static(index_data.as_slice());
        gfx::IndexSlice8(gfx::TriangleList, buf, 0, 36)
    };

    let tinfo = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        levels: 1,
        kind: gfx::tex::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let img_info = tinfo.to_image_info();
    let texture = device.create_texture(tinfo).unwrap();
    device.update_texture(
            &texture,
            &img_info,
            vec![0x20u8, 0xA0u8, 0xC0u8, 0x00u8].as_slice()
        ).unwrap();

    let sampler = device.create_sampler(
        gfx::tex::SamplerInfo::new(
            gfx::tex::Bilinear,
            gfx::tex::Clamp
        )
    );

    let program = device.link_program(
            VERTEX_SRC.clone(),
            FRAGMENT_SRC.clone()
        ).unwrap();

    let mut graphics = gfx::Graphics::new(device);
    let batch: CubeBatch = graphics.make_batch(&program, &mesh, slice, &state).unwrap();

    let mut data = Params {
        u_model_view_proj: piston::vecmath::mat4_id(),
        t_color: (texture, Some(sampler)),
    };

    let model = piston::vecmath::mat4_id();
    let projection = cam::CameraPerspective {
            fov: 90.0f32,
            near_clip: 0.1,
            far_clip: 1000.0,
            aspect_ratio: (win_width as f32) / (win_height as f32)
        }.projection();
    let mut first_person = cam::FirstPerson::new(
        [0.5f32, 0.5, 4.0],
        cam::FirstPersonSettings::keyboard_wasd()
    );

    let mut game_iter = piston::EventIterator::new(
        &mut window,
        &piston::EventSettings {
            updates_per_second: 120,
            max_frames_per_second: 60
        }
    );

    for e in game_iter {
        match e {
            piston::Render(args) => {
                graphics.clear(
                    gfx::ClearData {
                        color: [0.3, 0.3, 0.3, 1.0],
                        depth: 1.0,
                        stencil: 0,
                    },
                    gfx::Color | gfx::Depth,
                    &frame
                );
                data.u_model_view_proj = cam::model_view_projection(
                        model,
                        first_person.camera(args.ext_dt).orthogonal(),
                        projection
                    );
                graphics.draw(&batch, &data, &frame);
                graphics.end_frame();
            },
            piston::Update(args) => first_person.update(args.dt),
            piston::Input(e) => first_person.input(&e),
        }
    }
}

<|endoftext|>