<commit_before>use crate::rect::Rect;

#[derive(Clone, Debug)]
pub struct Frame {
    pub key: String,
    pub frame: Rect,
    pub rotated: bool,
    pub trimmed: bool,

    // (x, y) is the trimmed frame position at original image
    // (w, h) is original image size
    //
    //            w
    //     +--------------+
    //     | (x, y)       |
    //     |  ^           |
    //     |  |           |
    //     |  *********   |
    //     |  *       *   |  h
    //     |  *       *   |
    //     |  *********   |
    //     |              |
    //     +--------------+
    pub source: Rect,
}
<commit_msg>docs: Document the frame module contents<commit_after>use crate::rect::Rect;

/// Boundaries and properties of a packed texture.
#[derive(Clone, Debug)]
pub struct Frame {
    /// Key used to uniquely identify this frame.
    pub key: String,
    /// Rectangle describing the texture coordinates and size.
    pub frame: Rect,
    /// True if the texture was rotated during packing.
    pub rotated: bool,
    /// True if the texture was trimmed during packing.
    pub trimmed: bool,

    // (x, y) is the trimmed frame position at original image
    // (w, h) is original image size
    //
    //            w
    //     +--------------+
    //     | (x, y)       |
    //     |  ^           |
    //     |  |           |
    //     |  *********   |
    //     |  *       *   |  h
    //     |  *       *   |
    //     |  *********   |
    //     |              |
    //     +--------------+
    /// Source texture size before any trimming.
    pub source: Rect,
}
<|endoftext|>


<commit_before>pub(crate) use self::inner::{do_alloc, Allocator, Global};

#[cfg(feature = "nightly")]
mod inner {
    use crate::alloc::alloc::Layout;
    pub use crate::alloc::alloc::{Allocator, Global};
    use core::ptr::NonNull;

    #[allow(clippy::map_err_ignore)]
    pub fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> {
        alloc
            .allocate(layout)
            .map(|ptr| ptr.as_non_null_ptr())
            .map_err(|_| ())
    }

    #[cfg(feature = "bumpalo")]
    unsafe impl Allocator for crate::BumpWrapper<'_> {
        #[inline]
        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
            match self.0.try_alloc_layout(layout) {
                Ok(ptr) => Ok(NonNull::slice_from_raw_parts(ptr, layout.size())),
                Err(_) => Err(core::alloc::AllocError),
            }
        }
        #[inline]
        unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
    }
}

#[cfg(not(feature = "nightly"))]
mod inner {
    use crate::alloc::alloc::{alloc, dealloc, Layout};
    use core::ptr::NonNull;

    pub unsafe trait Allocator {
        fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()>;
        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
    }

    #[derive(Copy, Clone)]
    pub struct Global;
    unsafe impl Allocator for Global {
        #[inline]
        fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()> {
            unsafe { NonNull::new(alloc(layout)).ok_or(()) }
        }
        #[inline]
        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
            dealloc(ptr.as_ptr(), layout);
        }
    }
    impl Default for Global {
        #[inline]
        fn default() -> Self {
            Global
        }
    }

    pub fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> {
        alloc.allocate(layout)
    }

    #[cfg(feature = "bumpalo")]
    unsafe impl Allocator for crate::BumpWrapper<'_> {
        #[allow(clippy::map_err_ignore)]
        fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()> {
            self.0.try_alloc_layout(layout).map_err(|_| ())
        }
        unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
    }
}
<commit_msg>Disable clippy::missing_safety_doc lint on Allocator trait<commit_after>pub(crate) use self::inner::{do_alloc, Allocator, Global};

#[cfg(feature = "nightly")]
mod inner {
    use crate::alloc::alloc::Layout;
    pub use crate::alloc::alloc::{Allocator, Global};
    use core::ptr::NonNull;

    #[allow(clippy::map_err_ignore)]
    pub fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> {
        alloc
            .allocate(layout)
            .map(|ptr| ptr.as_non_null_ptr())
            .map_err(|_| ())
    }

    #[cfg(feature = "bumpalo")]
    unsafe impl Allocator for crate::BumpWrapper<'_> {
        #[inline]
        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
            match self.0.try_alloc_layout(layout) {
                Ok(ptr) => Ok(NonNull::slice_from_raw_parts(ptr, layout.size())),
                Err(_) => Err(core::alloc::AllocError),
            }
        }
        #[inline]
        unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
    }
}

#[cfg(not(feature = "nightly"))]
mod inner {
    use crate::alloc::alloc::{alloc, dealloc, Layout};
    use core::ptr::NonNull;

    #[allow(clippy::missing_safety_doc)] // not exposed outside of this crate
    pub unsafe trait Allocator {
        fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()>;
        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
    }

    #[derive(Copy, Clone)]
    pub struct Global;
    unsafe impl Allocator for Global {
        #[inline]
        fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()> {
            unsafe { NonNull::new(alloc(layout)).ok_or(()) }
        }
        #[inline]
        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
            dealloc(ptr.as_ptr(), layout);
        }
    }
    impl Default for Global {
        #[inline]
        fn default() -> Self {
            Global
        }
    }

    pub fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> {
        alloc.allocate(layout)
    }

    #[cfg(feature = "bumpalo")]
    unsafe impl Allocator for crate::BumpWrapper<'_> {
        #[allow(clippy::map_err_ignore)]
        fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()> {
            self.0.try_alloc_layout(layout).map_err(|_| ())
        }
        unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
    }
}
<|endoftext|>


<commit_before>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type suseconds_t = i64;

s! {
    pub struct timeval {
        pub tv_sec: time_t,
        pub tv_usec: suseconds_t,
    }

    pub struct timespec {
        pub tv_sec: time_t,
        pub tv_nsec: c_long,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

pub const F_DUPFD: ::c_int = 0;
pub const F_GETFD: ::c_int = 1;
pub const F_SETFD: ::c_int = 2;
pub const F_GETFL: ::c_int = 3;
pub const F_SETFL: ::c_int = 4;

pub const O_RDONLY: ::c_int =     0x0001_0000;
pub const O_WRONLY: ::c_int =     0x0002_0000;
pub const O_RDWR: ::c_int =       0x0003_0000;
pub const O_NONBLOCK: ::c_int =   0x0004_0000;
pub const O_APPEND: ::c_int =     0x0008_0000;
pub const O_SHLOCK: ::c_int =     0x0010_0000;
pub const O_EXLOCK: ::c_int =     0x0020_0000;
pub const O_ASYNC: ::c_int =      0x0040_0000;
pub const O_FSYNC: ::c_int =      0x0080_0000;
pub const O_CLOEXEC: ::c_int =    0x0100_0000;
pub const O_CREAT: ::c_int =      0x0200_0000;
pub const O_TRUNC: ::c_int =      0x0400_0000;
pub const O_EXCL: ::c_int =       0x0800_0000;
pub const O_DIRECTORY: ::c_int =  0x1000_0000;
pub const O_STAT: ::c_int =       0x2000_0000;
pub const O_SYMLINK: ::c_int =    0x4000_0000;
pub const O_NOFOLLOW: ::c_int =   0x8000_0000;
pub const O_ACCMODE: ::c_int =    O_RDONLY | O_WRONLY | O_RDWR;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t)
                -> ::ssize_t;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t)
                 -> ::ssize_t;
    pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int;
    pub fn close(fd: ::c_int) -> ::c_int;
    pub fn setenv(name: *const c_char, val: *const c_char,
                  overwrite: ::c_int) -> ::c_int;
    pub fn unsetenv(name: *const c_char) -> ::c_int;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}

pub use self::net::*;

mod net;
<commit_msg>Add chown/fchown<commit_after>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type suseconds_t = i64;

s! {
    pub struct timeval {
        pub tv_sec: time_t,
        pub tv_usec: suseconds_t,
    }

    pub struct timespec {
        pub tv_sec: time_t,
        pub tv_nsec: c_long,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

pub const F_DUPFD: ::c_int = 0;
pub const F_GETFD: ::c_int = 1;
pub const F_SETFD: ::c_int = 2;
pub const F_GETFL: ::c_int = 3;
pub const F_SETFL: ::c_int = 4;

pub const O_RDONLY: ::c_int =     0x0001_0000;
pub const O_WRONLY: ::c_int =     0x0002_0000;
pub const O_RDWR: ::c_int =       0x0003_0000;
pub const O_NONBLOCK: ::c_int =   0x0004_0000;
pub const O_APPEND: ::c_int =     0x0008_0000;
pub const O_SHLOCK: ::c_int =     0x0010_0000;
pub const O_EXLOCK: ::c_int =     0x0020_0000;
pub const O_ASYNC: ::c_int =      0x0040_0000;
pub const O_FSYNC: ::c_int =      0x0080_0000;
pub const O_CLOEXEC: ::c_int =    0x0100_0000;
pub const O_CREAT: ::c_int =      0x0200_0000;
pub const O_TRUNC: ::c_int =      0x0400_0000;
pub const O_EXCL: ::c_int =       0x0800_0000;
pub const O_DIRECTORY: ::c_int =  0x1000_0000;
pub const O_STAT: ::c_int =       0x2000_0000;
pub const O_SYMLINK: ::c_int =    0x4000_0000;
pub const O_NOFOLLOW: ::c_int =   0x8000_0000;
pub const O_ACCMODE: ::c_int =    O_RDONLY | O_WRONLY | O_RDWR;

extern {
    pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> ::c_int;
    pub fn close(fd: ::c_int) -> ::c_int;
    pub fn fchown(fd: ::c_int, uid: ::uid_t, gid: ::gid_t) -> ::c_int;
    pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int;
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t) -> ::ssize_t;
    pub fn setenv(name: *const c_char, val: *const c_char, overwrite: ::c_int) -> ::c_int;
    pub fn unsetenv(name: *const c_char) -> ::c_int;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t) -> ::ssize_t;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}

pub use self::net::*;

mod net;
<|endoftext|>


<commit_before>use petgraph::graph::IndexType;
use sdl2;
use sdl2::event::Event;
use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect};

use sdl;
use squaregrid::{GridDirection, SquareGrid};

pub fn render_square_grid<GridIndexType>(grid: &mut SquareGrid<GridIndexType>)
    where GridIndexType: IndexType
{
    // For a non-text based view of a maze we need a GUI window if
    // we want to see anything live.
    // To just write out an image we only need an sdl surface
    // to draw on and write out as a PNG?
    // Renderer seems to require a window...though the window
    // could be hidden I guess?
    // - sdl_context -> video_subsystem -> window_builder
    // - window_builder options:
    //   - *hidden*, fullscreen, opengl enabled, borderless, resizable
    //
    // sdl2_image provides:
    // trait SaveSurface for Surface (save as PNG only)
    // trait LoadSurface for Surface (load any texture)
    // trait LoadTexture for Renderer
    //
    // sdl2 provides a Surface accessor on the Renderer type, which
    // may also work even if the Renderer is using a Texture?
    // I'm guessing that *all* renderers for a window have a Surface, but
    // textures as memory locations on the GPU are optional.
    // SDL_Surface is just a collection of pixels while SDL_Texture is an
    // efficient, driver-specific representation of pixel data
    // SDL_Texture on the other hand, is used in a hardware rendering, textures
    // are stored in VRAM and you don't have access to it directly as with SDL_Surface.
    // The rendering operations are accelerated by GPU, using, internally, either
    // OpenGL or DirectX (available only on Windows) API, which in turn are using
    // your video hardware, hence hardware rendering name.
    // http://stackoverflow.com/questions/21007329/what-is-a-sdl-renderer/21007477#21007477

    let sdl_setup = sdl::init();
    let window_width = 1280;
    let window_height = 720;
    let mut window_builder = sdl_setup.video_subsystem.window("Mazes", window_width, window_height);
    let window = window_builder.position_centered()
                               //.borderless()
                               .resizable()
                               //.opengl()
                               .build()
                               .unwrap();
    let mut renderer = window.renderer()
                             .present_vsync()
                             .accelerated()
                             .build()
                             .unwrap();

    let black = Color::RGB(0, 0, 0);
    let white = Color::RGB(0xff, 0xff, 0xff);
    let red = Color::RGB(0xff, 0, 0);
    let green = Color::RGB(0, 0xff, 0);
    let blue = Color::RGB(0, 0, 0xff);
    let yellow = Color::RGB(0xff, 0xff, 0);

    let mut events = sdl_setup.sdl_context.event_pump().unwrap();
    'event: loop {
        for event in events.poll_iter() {
            match event {
                Event::Quit{..} => break 'event,
                Event::KeyDown{keycode: Some(sdl2::keyboard::Keycode::Q), ..} => break 'event,
                _ => continue,
            }
        }

        // clear the buffer to white
        renderer.set_draw_color(white);
        renderer.clear();

        let scale = 1.0;
        renderer.set_scale(scale, scale);
        renderer.set_draw_color(blue);

        // A limitation of drawing to something that we are showing on the screen is surely that the OS
        // may not want to show a window with a stupidly large pixel size, whereas an image file can
        // be at a much large scale. The window can still be shown and closed though.
        let cell_size_pixels = 10;
        let img_width = cell_size_pixels * grid.dimension();
        let img_height = cell_size_pixels * grid.dimension();

        for cell in grid.iter() {
            let column = cell.x as usize;
            let row = cell.y as usize;

            let x1 = (column * cell_size_pixels) as i32;
            let y1 = (row * cell_size_pixels) as i32;
            let x2 = ((column + 1) * cell_size_pixels) as i32;
            let y2 = ((row + 1) * cell_size_pixels) as i32;

            // special cases north and west to handle first row and column.
            if grid.neighbour_at_direction(&cell, GridDirection::North).is_none() {
                renderer.draw_line(Point::new(x1, y1), Point::new(x2, y1));
            }
            if grid.neighbour_at_direction(&cell, GridDirection::West).is_none() {
                renderer.draw_line(Point::new(x1, y1), Point::new(x1, y2));
            }

            if !grid.is_neighbour_linked(&cell, GridDirection::East) {
                renderer.draw_line(Point::new(x2, y1), Point::new(x2, y2));
            }
            if !grid.is_neighbour_linked(&cell, GridDirection::South) {
                renderer.draw_line(Point::new(x1, y2), Point::new(x2, y2));
            }
        }

        // why is the cpu maxed when vsync should be on? Number of lines I guess.
        // 1% CPU with 400 cells?, 2% 900 cells, 3.2% 1600 cells, 4.5% 2500 cells,
        // 7.5% 4900 cells, 9% 6400, 10.5% 8100, 13% 10,000. Max single core = 13% @ 4.2GHz.
        // draw_lines() can be used to avoid a context swap but all the lines in one batch must be connected
        // Need to check the FPS, assuming 60Hz until doing 10K line draws.

        renderer.present();
    }
}
<commit_msg>Comment<commit_after>use petgraph::graph::IndexType;
use sdl2;
use sdl2::event::Event;
use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect};

use sdl;
use squaregrid::{GridDirection, SquareGrid};

pub fn render_square_grid<GridIndexType>(grid: &mut SquareGrid<GridIndexType>)
    where GridIndexType: IndexType
{
    // For a non-text based view of a maze we need a GUI window if
    // we want to see anything live.
    // To just write out an image we only need an sdl surface
    // to draw on and write out as a PNG?
    // Renderer seems to require a window...though the window
    // could be hidden I guess?
    // - sdl_context -> video_subsystem -> window_builder
    // - window_builder options:
    //   - *hidden*, fullscreen, opengl enabled, borderless, resizable
    //
    // sdl2_image provides:
    // trait SaveSurface for Surface (save as PNG only)
    // trait LoadSurface for Surface (load any texture)
    // trait LoadTexture for Renderer
    //
    // sdl2 provides a Surface accessor on the Renderer type, which
    // may also work even if the Renderer is using a Texture?
    // I'm guessing that *all* renderers for a window have a Surface, but
    // textures as memory locations on the GPU are optional.
    // SDL_Surface is just a collection of pixels while SDL_Texture is an
    // efficient, driver-specific representation of pixel data
    // SDL_Texture on the other hand, is used in a hardware rendering, textures
    // are stored in VRAM and you don't have access to it directly as with SDL_Surface.
    // The rendering operations are accelerated by GPU, using, internally, either
    // OpenGL or DirectX (available only on Windows) API, which in turn are using
    // your video hardware, hence hardware rendering name.
    // http://stackoverflow.com/questions/21007329/what-is-a-sdl-renderer/21007477#21007477

    let sdl_setup = sdl::init();
    let window_width = 1280;
    let window_height = 720;
    let mut window_builder = sdl_setup.video_subsystem.window("Mazes", window_width, window_height);
    let window = window_builder.position_centered()
                               //.borderless()
                               .resizable()
                               //.opengl()
                               .build()
                               .unwrap();
    let mut renderer = window.renderer()
                             .present_vsync()
                             .accelerated()
                             .build()
                             .unwrap();

    let black = Color::RGB(0, 0, 0);
    let white = Color::RGB(0xff, 0xff, 0xff);
    let red = Color::RGB(0xff, 0, 0);
    let green = Color::RGB(0, 0xff, 0);
    let blue = Color::RGB(0, 0, 0xff);
    let yellow = Color::RGB(0xff, 0xff, 0);

    let mut events = sdl_setup.sdl_context.event_pump().unwrap();
    'event: loop {
        for event in events.poll_iter() {
            match event {
                Event::Quit{..} => break 'event,
                Event::KeyDown{keycode: Some(sdl2::keyboard::Keycode::Q), ..} => break 'event,
                _ => continue,
            }
        }

        // clear the buffer to white
        renderer.set_draw_color(white);
        renderer.clear();

        let scale = 1.0;
        renderer.set_scale(scale, scale);
        renderer.set_draw_color(blue);

        // A limitation of drawing to something that we are showing on the screen is surely that the OS
        // may not want to show a window with a stupidly large pixel size, whereas an image file can
        // be at a much large scale. The window can still be shown and closed though.
        let cell_size_pixels = 10;
        let img_width = cell_size_pixels * grid.dimension();
        let img_height = cell_size_pixels * grid.dimension();

        for cell in grid.iter() {
            let column = cell.x as usize;
            let row = cell.y as usize;

            let x1 = (column * cell_size_pixels) as i32;
            let y1 = (row * cell_size_pixels) as i32;
            let x2 = ((column + 1) * cell_size_pixels) as i32;
            let y2 = ((row + 1) * cell_size_pixels) as i32;

            // special cases north and west to handle first row and column.
            if grid.neighbour_at_direction(&cell, GridDirection::North).is_none() {
                renderer.draw_line(Point::new(x1, y1), Point::new(x2, y1));
            }
            if grid.neighbour_at_direction(&cell, GridDirection::West).is_none() {
                renderer.draw_line(Point::new(x1, y1), Point::new(x1, y2));
            }

            if !grid.is_neighbour_linked(&cell, GridDirection::East) {
                renderer.draw_line(Point::new(x2, y1), Point::new(x2, y2));
            }
            if !grid.is_neighbour_linked(&cell, GridDirection::South) {
                renderer.draw_line(Point::new(x1, y2), Point::new(x2, y2));
            }
        }

        // why is the cpu maxed when vsync should be on? Number of lines I guess.
        // 1% CPU with 400 cells?, 2% 900 cells, 3.2% 1600 cells, 4.5% 2500 cells,
        // 7.5% 4900 cells, 9% 6400, 10.5% 8100, 13% 10,000. Max single core = 13% @ 4.2GHz.
        // draw_lines() can be used to avoid a context swap but all the lines in one batch must be connected
        // Need to check the FPS, assuming 60Hz until doing 10K line draws.
        // oh...and it's not a release build...10,000 = ~7.0% CPU usage. 16,900 celss ~11% and won't fit on screen.

        renderer.present();
    }
}
<|endoftext|>


<commit_before>use std::cell::Cell;

use ast::Ast;
use ast::Elem::{self, ElemFunction};
use ast::Expr::{self, ExprUn, ExprBin, ExprLitInt, ExprLitStr, ExprLitBool,
                ExprAssign, ExprIdent};
use ast::ExprUnType;
use ast::ExprBinType;
use ast::ExprLitIntType;
use ast::ExprLitStrType;
use ast::ExprLitBoolType;
use ast::ExprIdentType;
use ast::ExprAssignType;
use ast::Function;
use ast::Stmt::{self, StmtBlock, StmtReturn};
use ast::StmtBlockType;
use ast::StmtReturnType;
use ast::Type::{self, TypeBasic, TypeUnit};
use interner::Name;

macro_rules! dump {
    ($self_:ident, $($x:expr),*) => {{
        for _ in 0..($self_.indent*2) {
            print!(" ");
        }

        println!($($x,)*);
    }};
}

pub struct AstDumper<'a> {
    ast: &'a Ast,
    indent: u32,
}

impl<'a> AstDumper<'a> {
    pub fn new(ast: &Ast) -> AstDumper {
        AstDumper {
            ast: ast,
            indent: 0
        }
    }

    pub fn dump(&mut self) {
        for el in &self.ast.elements {
            match *el {
                ElemFunction(ref fct) => self.dump_fct(fct),
                _ => unreachable!()
            }
        }
    }

    fn dump_fct(&mut self, fct: &Function) {
        dump!(self, "fct {} @ {}", self.str(fct.name), fct.pos);

        self.indent(|d| {
            if(fct.params.is_empty()) {
                dump!(d, "no params");
            } else {
                for param in &fct.params {
                    dump!(d, "param {} @ {}", d.str(param.name), param.pos);
                    d.indent(|d| d.dump_type(&param.data_type));
                }
            }
        });

        dump!(self, "fct {} returns", self.str(fct.name));
        self.indent(|d| d.dump_type(&fct.return_type));

        dump!(self, "fct {} executes", self.str(fct.name));
        self.indent(|d| d.dump_stmt(&fct.block));
    }

    fn dump_type(&mut self, ty: &Type) {
        match *ty {
            TypeBasic(name) => dump!(self, "type {}", self.str(name)),
            TypeUnit => dump!(self, "type () / void")
        }
    }

    fn dump_stmt(&mut self, stmt: &Stmt) {
        match *stmt {
            StmtBlock(ref block) => self.dump_stmt_block(block),
            StmtReturn(ref ret) => self.dump_stmt_return(ret),
            _ => unimplemented!()
        }
    }

    fn dump_stmt_block(&mut self, block: &StmtBlockType) {
        dump!(self, "block ({} statements)", block.stmts.len());

        self.indent(|d| {
            if(block.stmts.is_empty()) {
                dump!(d, "no statements");
            } else {
                for stmt in &block.stmts {
                    d.dump_stmt(stmt);
                }
            }
        });

        dump!(self, "block end");
    }

    fn dump_stmt_return(&mut self, ret: &StmtReturnType) {
        if let Some(ref expr) = ret.expr {
            dump!(self, "return");
            self.indent(|d| d.dump_expr(expr));
        } else {
            dump!(self, "return void")
        }
    }

    fn dump_expr(&mut self, expr: &Expr) {
        match *expr {
            ExprUn(ref un) => self.dump_expr_un(un),
            ExprBin(ref bin) => self.dump_expr_bin(bin),
            ExprLitInt(ref lit) => dump!(self, "lit int {}", lit.value),
            ExprLitStr(ref lit) => dump!(self, "lit string {:?}", lit.value),
            ExprLitBool(ref lit) => dump!(self, "lit bool {}", lit.value),
            ExprIdent(ref ident) => dump!(self, "ident {}", self.str(ident.name)),
            ExprAssign(ref assign) => self.dump_expr_assign(assign),
        }
    }

    fn dump_expr_un(&mut self, expr: &ExprUnType) {
        dump!(self, "unary {:?}", expr.op);
        self.indent(|d| d.dump_expr(&expr.opnd));
    }

    fn dump_expr_bin(&mut self, expr: &ExprBinType) {
        self.indent(|d| d.dump_expr(&expr.rhs));
        dump!(self, "binary {:?}", expr.op);
        self.indent(|d| d.dump_expr(&expr.lhs));
    }

    fn dump_expr_assign(&mut self, expr: &ExprAssignType) {
        self.indent(|d| d.dump_expr(&expr.rhs));
        dump!(self, "assign (=)");
        self.indent(|d| d.dump_expr(&expr.lhs));
    }

    fn indent<F>(&mut self, fct: F) where F: Fn(&mut AstDumper) -> () {
        let old = self.indent;
        self.indent = old+1;

        fct(self);

        self.indent = old;
    }

    fn str(&self, name: Name) -> &str {
        self.ast.str(name)
    }
}
<commit_msg>added additional statements to dumper<commit_after>use std::cell::Cell;

use ast::Ast;
use ast::Elem::{self, ElemFunction};
use ast::Expr::{self, ExprUn, ExprBin, ExprLitInt, ExprLitStr, ExprLitBool,
                ExprAssign, ExprIdent};
use ast::ExprUnType;
use ast::ExprBinType;
use ast::ExprLitIntType;
use ast::ExprLitStrType;
use ast::ExprLitBoolType;
use ast::ExprIdentType;
use ast::ExprAssignType;
use ast::Function;
use ast::Stmt::{self, StmtBlock, StmtBreak, StmtContinue, StmtExpr,
                StmtIf, StmtReturn};
use ast::StmtBlockType;
use ast::StmtBreakType;
use ast::StmtContinueType;
use ast::StmtExprType;
use ast::StmtIfType;
use ast::StmtReturnType;
use ast::Type::{self, TypeBasic, TypeUnit};
use interner::Name;

macro_rules! dump {
    ($self_:ident, $($x:expr),*) => {{
        for _ in 0..($self_.indent*2) {
            print!(" ");
        }

        println!($($x,)*);
    }};
}

pub struct AstDumper<'a> {
    ast: &'a Ast,
    indent: u32,
}

impl<'a> AstDumper<'a> {
    pub fn new(ast: &Ast) -> AstDumper {
        AstDumper {
            ast: ast,
            indent: 0
        }
    }

    pub fn dump(&mut self) {
        for el in &self.ast.elements {
            match *el {
                ElemFunction(ref fct) => self.dump_fct(fct),
                _ => unreachable!()
            }
        }
    }

    fn dump_fct(&mut self, fct: &Function) {
        dump!(self, "fct {} @ {}", self.str(fct.name), fct.pos);

        self.indent(|d| {
            if(fct.params.is_empty()) {
                dump!(d, "no params");
            } else {
                for param in &fct.params {
                    dump!(d, "param {} @ {}", d.str(param.name), param.pos);
                    d.indent(|d| d.dump_type(&param.data_type));
                }
            }
        });

        dump!(self, "fct {} returns", self.str(fct.name));
        self.indent(|d| d.dump_type(&fct.return_type));

        dump!(self, "fct {} executes", self.str(fct.name));
        self.indent(|d| d.dump_stmt(&fct.block));
    }

    fn dump_type(&mut self, ty: &Type) {
        match *ty {
            TypeBasic(name) => dump!(self, "type {}", self.str(name)),
            TypeUnit => dump!(self, "type () / void")
        }
    }

    fn dump_stmt(&mut self, stmt: &Stmt) {
        match *stmt {
            StmtBlock(ref block) => self.dump_stmt_block(block),
            StmtReturn(ref ret) => self.dump_stmt_return(ret),
            StmtBreak(ref stmt) => self.dump_stmt_break(stmt),
            StmtContinue(ref stmt) => self.dump_stmt_continue(stmt),
            StmtExpr(ref expr) => self.dump_stmt_expr(expr),
            StmtIf(ref stmt) => self.dump_stmt_if(stmt),
            _ => unimplemented!()
        }
    }

    fn dump_stmt_if(&mut self, stmt: &StmtIfType) {
        dump!(self, "if @ {}", stmt.pos);

        self.indent(|d| {
            d.indent(|d| { d.dump_expr(&stmt.cond); });
            dump!(d, "then");
            d.indent(|d| { d.dump_stmt(&stmt.then_block); });
            dump!(d, "else");
            d.indent(|d| { d.dump_stmt(&stmt.then_block); });
        });
    }

    fn dump_stmt_expr(&mut self, stmt: &StmtExprType) {
        dump!(self, "expr stmt @ {}", stmt.pos);
        self.indent(|d| { d.dump_expr(&stmt.expr); });
    }

    fn dump_stmt_block(&mut self, block: &StmtBlockType) {
        dump!(self, "block ({} statements) @ {}", block.stmts.len(), block.pos);

        self.indent(|d| {
            if(block.stmts.is_empty()) {
                dump!(d, "no statements");
            } else {
                for stmt in &block.stmts {
                    d.dump_stmt(stmt);
                }
            }
        });

        dump!(self, "block end");
    }

    fn dump_stmt_return(&mut self, ret: &StmtReturnType) {
        if let Some(ref expr) = ret.expr {
            dump!(self, "return @ {}", ret.pos);
            self.indent(|d| d.dump_expr(expr));
        } else {
            dump!(self, "return void @ {}", ret.pos);
        }
    }

    fn dump_stmt_break(&mut self, stmt: &StmtBreakType) {
        dump!(self, "break @ {}", stmt.pos);
    }

    fn dump_stmt_continue(&mut self, stmt: &StmtContinueType) {
        dump!(self, "break @ {}", stmt.pos);
    }

    fn dump_expr(&mut self, expr: &Expr) {
        match *expr {
            ExprUn(ref un) => self.dump_expr_un(un),
            ExprBin(ref bin) => self.dump_expr_bin(bin),
            ExprLitInt(ref lit) => dump!(self, "lit int {}", lit.value),
            ExprLitStr(ref lit) => dump!(self, "lit string {:?}", lit.value),
            ExprLitBool(ref lit) => dump!(self, "lit bool {}", lit.value),
            ExprIdent(ref ident) => dump!(self, "ident {}", self.str(ident.name)),
            ExprAssign(ref assign) => self.dump_expr_assign(assign),
        }
    }

    fn dump_expr_un(&mut self, expr: &ExprUnType) {
        dump!(self, "unary {:?}", expr.op);
        self.indent(|d| d.dump_expr(&expr.opnd));
    }

    fn dump_expr_bin(&mut self, expr: &ExprBinType) {
        self.indent(|d| d.dump_expr(&expr.rhs));
        dump!(self, "binary {:?}", expr.op);
        self.indent(|d| d.dump_expr(&expr.lhs));
    }

    fn dump_expr_assign(&mut self, expr: &ExprAssignType) {
        self.indent(|d| d.dump_expr(&expr.rhs));
        dump!(self, "assign (=)");
        self.indent(|d| d.dump_expr(&expr.lhs));
    }

    fn indent<F>(&mut self, fct: F) where F: Fn(&mut AstDumper) -> () {
        let old = self.indent;
        self.indent = old+1;

        fct(self);

        self.indent = old;
    }

    fn str(&self, name: Name) -> &str {
        self.ast.str(name)
    }
}
<|endoftext|>


<commit_before>use core::{Distribution};

use rand::Rng;

/// A distribution that always returns the same value.
///
/// # Example
///
/// ```rust
/// # extern crate rand;
/// # extern crate distributions;
/// # fn main() {
///     use distributions::Distribution;
///
///     let d = distributions::Constant(42);
///     let v = d.sample(&mut rand::thread_rng());
///     assert_eq!(v, 42);
/// # }
/// ```
pub struct Constant<T>(pub T);

impl<T: Clone> Distribution for Constant<T> {
    type Output=T;

    #[inline]
    fn sample<R: Rng>(&self, _: &mut R) -> T {
        self.0.clone()
    }
}

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

    use core::Distribution;
    use rand::{self, Rng, thread_rng};

    #[test]
    fn test_generate_u8() {
        let mut rng: rand::XorShiftRng = rand::thread_rng().gen();

        let v: u8 =  Constant(42).sample(&mut rng);
        assert_eq!(v, 42);
    }
}
<commit_msg>Add IntoDistribution<T> impls for T for a number of types.<commit_after>use core::{Distribution, IntoDistribution};

use rand::Rng;
use std;

/// A distribution that always returns the same value.
///
/// # Example
///
/// ```rust
/// # extern crate rand;
/// # extern crate distributions;
/// # fn main() {
///     use distributions::Distribution;
///
///     let d = distributions::Constant(42);
///     let v = d.sample(&mut rand::thread_rng());
///     assert_eq!(v, 42);
/// # }
/// ```
pub struct Constant<T>(pub T);

impl<T: Clone> Distribution for Constant<T> {
    type Output=T;

    #[inline]
    fn sample<R: Rng>(&self, _: &mut R) -> T {
        self.0.clone()
    }
}

macro_rules! into_constant_distribution {
    ($($ty:ty),* ) => {
        $(
            impl IntoDistribution<$ty> for $ty {
                type Distribution = Constant<Self>;

                #[inline]
                fn into_distribution(self) -> Constant<Self> {
                    Constant(self)
                }
            }
        )*
    }
}

into_constant_distribution! {
    u8, u16, u32, u64, usize,
    i8, i16, i32, i64, isize,
    bool, char
}

macro_rules! generic_into_constant_distribution {
    ($ty:ty, $($ident:ident),* ) => {
        impl <$($ident),*> IntoDistribution<$ty> for $ty where
            $ty: Clone {
            type Distribution = Constant<Self>;

            #[inline]
            fn into_distribution(self) -> Constant<Self> {
                Constant(self)
            }
        }
    }
}

generic_into_constant_distribution! { Vec<T>, T }
generic_into_constant_distribution! { std::collections::VecDeque<T>, T }
generic_into_constant_distribution! { std::collections::LinkedList<T>, T }
generic_into_constant_distribution! { std::collections::HashMap<K, V>, K, V }
generic_into_constant_distribution! { std::collections::BTreeMap<K, V>, K, V }
generic_into_constant_distribution! { std::collections::HashSet<T>, T }
generic_into_constant_distribution! { std::collections::BTreeSet<T>, T }
generic_into_constant_distribution! { std::collections::BinaryHeap<T>, T }

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

    use core::{Distribution, IntoDistribution};
    use rand::{self, Rng, thread_rng};

    #[test]
    fn test_generate_u8() {
        let mut rng: rand::XorShiftRng = rand::thread_rng().gen();

        let v: u8 =  Constant(42).sample(&mut rng);
        assert_eq!(v, 42);
    }

    #[test]
    fn test_into_distribution() {
        let mut rng: rand::XorShiftRng = rand::thread_rng().gen();

        let v: u8 =  42u8.into_distribution().sample(&mut rng);
        assert_eq!(v, 42);
    }

    #[test]
    fn test_vec_into_distribution() {
        let mut rng: rand::XorShiftRng = rand::thread_rng().gen();

        let v: Vec<u8> =  vec![42u8].into_distribution().sample(&mut rng);
        assert_eq!(v, vec![42u8]);
    }
}
<|endoftext|>


<commit_before>extern mod std;
use io::{Reader,ReaderUtil};

mod environment;
use environment::Environment;
mod expression;
use expression::Expression;
use expression::{Int,Float,Symbol,List,Proc};
mod parse;
use parse::parse;

fn test_env() -> @Environment {
    @Environment::new_global_environment()
}

fn test_eval( expr:&str, result:&str ) {
    let evaluated = eval(parse(expr), test_env());
    let expected = parse(result);
    if expected != evaluated.first() {
        fail fmt!("Expected: %s -> Got %s", expected.to_str(), evaluated.first().to_str())
    }
}

fn test_eval_fails( expr:&str, result:&str, reason:&str ) {
    let evaluated = eval(parse(expr), test_env());
    let expected = parse(result);
    if expected == evaluated.first() {
        fail fmt!("%s should not have evaluated to %s (%s)", expr, result, reason)
    }
}

#[test]
fn test_eval_returns_number_when_passed_number() {
    test_eval( ~"1", ~"1" );
}

#[test]
fn test_eval_returns_expression_when_passed_quote() {
    test_eval( ~"(quote (a))", ~"(a)" );
}

#[test]
fn test_eval_returns_last_expression_when_passed_begin() {
    test_eval( ~"(begin 1 2 3)", ~"3" );
}

#[test]
fn test_if_returns_third_part_when_if_is_true() {
    test_eval( ~"(if 1 2 3)", ~"2" );
}

#[test]
fn test_if_returns_fourth_part_when_if_is_false() {
    test_eval( ~"(if 0 2 3)", ~"3" );
}

#[test]
fn test_that_if_evaluates_the_then_branch() {
    let expression = ~"(if 1 (begin 1 2) 7)";
    test_eval_fails( expression, ~"(begin 1 2)", ~"if just returned the raw then" );
    test_eval( expression, ~"2" );
}

#[test]
fn test_that_if_evaluates_the_else_branch() {
    let expression = ~"(if 0 7 (begin 1 2))";
    test_eval_fails( expression, ~"(begin 1 2)", ~"if just returned the else branch" );
    test_eval( expression, ~"2");
}

#[test]
fn test_that_if_evaluates_the_test() {
    let expression = ~"(if (begin 1 0) 1 2)";
    test_eval_fails( expression, ~"1", ~"if didn't evaluate the test" );
    test_eval( expression, ~"2" );
}

#[test]
fn test_that_bare_symbol_is_interpreted_as_variable() {
    let env = test_env();
    env.define(~"monkey", Int(10));
    let expression = parse( ~"monkey" );
    let value = eval( expression, env );
    match value {
        (Int(10), _) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
#[should_fail]
fn test_that_undefined_symbol_is_an_error() {
    let env = test_env();
    let expression = parse( ~"monkey" );
    eval( expression, env );
}

#[test]
fn test_that_define_can_add_a_variable() {
    let env = test_env();
    let expression = parse( ~"(define x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
#[should_fail]
fn test_that_set_cannot_create_a_variable() {
    let env = test_env();
    let expression = parse( ~"(set! x 10)" );
    eval( expression, env );
}

#[test]
fn test_that_set_can_change_a_variable() {
    let env = test_env();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
fn test_that_set_returns_the_value_not_the_key() {
    let env = test_env();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match value {
        (Int(10), _) => (),
        (Symbol(~"x"), _) => fail ~"set! returned the key, not the value",
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
fn test_that_begin_can_handle_one_argument() {
    let env = test_env();
    let expression = parse( ~"(begin 10)" );
    let value = eval( expression, env );
    match value {
        (Int(10), _) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
fn test_that_begin_evaluates_all_arguments() {
    let env = test_env();
    let expression = parse( ~"(begin (define x 10) x)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
    match value {
        (Int(10), _) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
fn test_that_other_symbols_are_evaluated_as_procs() {
    let env = test_env();
    let expression = parse( ~"(+ 1 2)" );
    let value = eval( expression, env );
    match value {
        (Int(3), _) => (),
        _ => fail fmt!("(+ 1 2) became %s", value.first().to_str())
    }
}

#[test]
fn test_that_proc_params_are_evaluated() {
    let env=test_env();
    let expression = parse( ~"(+ (+ 1 2) 3)" );
    let value = eval (expression, env);
    match value {
        (Int(6), _) => (),
        _ => fail fmt!("(+ (+ 1 2) 3) became %s", value.first().to_str())
    }
}

#[test]
fn test_that_lambda_evaluates_to_a_proc() {
    let env=test_env();
    let expression = parse( ~"(lambda (x) (* x x))" );
    let value = eval(expression, env);
    match value {
       (Proc(_), _) => (),
        _ => fail ~"lambda doesn't turn into a Proc"
    }
}

#[test]
fn test_that_lambda_without_variables_evals() {
    let env=test_env();
    let expression = parse( ~"( (lambda () (+ 1 1))  )" );
    let value = eval(expression, env);
    match value {
        (Int(2), _) => (),
        _ => fail fmt!("lambda evaluated to %s", value.first().to_str())
    }
}

#[test]
fn test_that_lambda_with_a_variable_evals() {
    let env=test_env();
    let expression = parse( ~"( (lambda (x) (+ x 1)) 1  )" );
    let value = eval(expression, env);
    match value {
        (Int(2), _) => (),
        _ => fail fmt!("lambda evaluated to %s", value.first().to_str())
    }
}

fn eval( expression:Expression, environment:@Environment ) -> (Expression, @Environment ) {
    fn quote(expressions:~[Expression]) -> Expression {
        match expressions {
            [_, expr] => expr,
            _ => fail ~"Syntax Error: quote must take a single argument"
        }
    }

    fn begin(expressions:~[Expression], environment:@Environment) -> Expression {
        for expressions.tail().init().each() |&expression| {
            eval( expression, environment );
        }
        eval( expressions.last(), environment ).first()
    }

    fn if_(expressions:~[Expression], environment:@Environment) -> Expression {
        match expressions {
            [_, test, true_expr, false_expr] => {
                let condition = eval(test, environment).first();
                eval(if condition.to_bool() {
                    true_expr
                } else {
                    false_expr
                }, environment).first()
            }
            _ => fail ~"Syntax Error: if must take three arguments"
        }
    }

    fn reset_variable(expressions:~[Expression], environment:@Environment, function:~str) -> Expression {
        match expressions {
            [_, symbol, value] => {
                match copy symbol {
                    Symbol( key ) => {
                        environment.define(key, eval(value, environment).first());
                        symbol
                    }
                    _ => fail fmt!("Syntax Error: %s takes a symbol as its first argument", function)
                }
            }
            _ => fail fmt!("Syntax Error: %s must take two arguments", function)
        }
    }

    fn define(expressions:~[Expression], environment:@Environment) -> Expression {
        reset_variable(expressions, environment, ~"define")
    }

    fn set_bang(expressions:~[Expression], environment:@Environment) -> Expression {
        match copy expressions {
            [_, symbol, _] => {
                match copy symbol {
                    Symbol( key ) => {
                        match environment.lookup( copy key )  {
                            None => fail ~"Syntax Error: set! cannot create a variable",
                            _ => ()
                        }
                    }
                    _ => ()
                }
            }
            _ => ()
        }
        let symbol = reset_variable(expressions, environment, ~"set!");
        match copy symbol {
            Symbol( key ) => {
                match environment.lookup( copy key ) {
                    Some( value ) => value,
                    None => fail
                }
            }
            _ => fail
        }
    }

    fn proc(expressions:~[Expression], environment:@Environment) -> Expression {
        let exprs = expressions.map(|&expr| eval(expr, environment).first());
        match exprs.head() {
            Proc( procedure ) => procedure( exprs.tail(), environment ),
            _ => fail fmt!("\"%s\" is not a procedure", exprs.head().to_str())
        }
    }

    fn lambda(expressions:~[Expression], _:@Environment) -> Expression {
        match copy expressions {
            [_, List(param_names), expression] => Proc( |param_values, env| {
                    let local_env = @Environment::new( env );
                    for vec::zip(copy param_names, param_values).each |param| {
                        match param.first() {
                            Symbol(key) => local_env.define( key, param.second() ),
                            _ => fail ~"lambda params list must be list of symbols"
                        }
                    }
                    eval(copy expression, local_env).first()
                } ),
            _ => fail fmt!("Syntax Error: lambda requires 2 arguments, got \"%u\"", expressions.len()-1 )
        }
    }

    (match copy expression {
        List( expressions ) => {
            match expressions[0] {
                Symbol(~"quote") => quote(expressions),
                Symbol(~"begin") => begin(expressions, environment),
                Symbol(~"if") => if_(expressions, environment),
                Symbol(~"define") => define(expressions, environment),
                Symbol(~"set!") => set_bang(expressions, environment),
                Symbol(~"lambda") => lambda(expressions, environment),
                _ => proc(expressions, environment)
            }
        }
        Symbol( symbol ) => {
            match environment.lookup( copy symbol ) {
                Some( value ) => value,
                None => fail fmt!("Undefined symbol %s",symbol)
            }
        }
        _ => {
            expression
        }
    }, environment)
}

struct Env {
    enclosure:Option<@Env>,
    mappings:send_map::linear::LinearMap<~str, Expression>
}

fn main() {
    fn evaluate( expr:~str, env:Environment ) -> Option<Environment> {
        let sent_expr = copy expr;

        let (port, chan): (pipes::Port<Environment>, pipes::Chan<Environment>) = pipes::stream();
        chan.send(env);
        let result = do task::try |move port| {
            let env = port.recv();
            let (result, new_env) = eval( parse(sent_expr), @env );
            (result, copy *new_env)
        };
        if result.is_ok() {
            let successful_result = result.unwrap();
            let evaluated_expression = successful_result.first();
            let new_env = successful_result.second();
            io::println( fmt!("%s -> %s", expr, evaluated_expression.to_str() ));
            Some(new_env)
        } else {
            io::println( fmt!("%s gave an error.", expr) );
            None
        }
    }

    let mut env = Environment::new_global_environment();
    loop {
        io::print("rusty> ");
        let in = io::stdin().read_line();
        let result = evaluate( in, copy env );
        match result {
            Some(new_env) => env = new_env,
            None => ()
        }
    }
}
<commit_msg>Remove temp test definition<commit_after>extern mod std;
use io::{Reader,ReaderUtil};

mod environment;
use environment::Environment;
mod expression;
use expression::Expression;
use expression::{Int,Float,Symbol,List,Proc};
mod parse;
use parse::parse;

fn test_env() -> @Environment {
    @Environment::new_global_environment()
}

fn test_eval( expr:&str, result:&str ) {
    let evaluated = eval(parse(expr), test_env());
    let expected = parse(result);
    if expected != evaluated.first() {
        fail fmt!("Expected: %s -> Got %s", expected.to_str(), evaluated.first().to_str())
    }
}

fn test_eval_fails( expr:&str, result:&str, reason:&str ) {
    let evaluated = eval(parse(expr), test_env());
    let expected = parse(result);
    if expected == evaluated.first() {
        fail fmt!("%s should not have evaluated to %s (%s)", expr, result, reason)
    }
}

#[test]
fn test_eval_returns_number_when_passed_number() {
    test_eval( ~"1", ~"1" );
}

#[test]
fn test_eval_returns_expression_when_passed_quote() {
    test_eval( ~"(quote (a))", ~"(a)" );
}

#[test]
fn test_eval_returns_last_expression_when_passed_begin() {
    test_eval( ~"(begin 1 2 3)", ~"3" );
}

#[test]
fn test_if_returns_third_part_when_if_is_true() {
    test_eval( ~"(if 1 2 3)", ~"2" );
}

#[test]
fn test_if_returns_fourth_part_when_if_is_false() {
    test_eval( ~"(if 0 2 3)", ~"3" );
}

#[test]
fn test_that_if_evaluates_the_then_branch() {
    let expression = ~"(if 1 (begin 1 2) 7)";
    test_eval_fails( expression, ~"(begin 1 2)", ~"if just returned the raw then" );
    test_eval( expression, ~"2" );
}

#[test]
fn test_that_if_evaluates_the_else_branch() {
    let expression = ~"(if 0 7 (begin 1 2))";
    test_eval_fails( expression, ~"(begin 1 2)", ~"if just returned the else branch" );
    test_eval( expression, ~"2");
}

#[test]
fn test_that_if_evaluates_the_test() {
    let expression = ~"(if (begin 1 0) 1 2)";
    test_eval_fails( expression, ~"1", ~"if didn't evaluate the test" );
    test_eval( expression, ~"2" );
}

#[test]
fn test_that_bare_symbol_is_interpreted_as_variable() {
    let env = test_env();
    env.define(~"monkey", Int(10));
    let expression = parse( ~"monkey" );
    let value = eval( expression, env );
    match value {
        (Int(10), _) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
#[should_fail]
fn test_that_undefined_symbol_is_an_error() {
    let env = test_env();
    let expression = parse( ~"monkey" );
    eval( expression, env );
}

#[test]
fn test_that_define_can_add_a_variable() {
    let env = test_env();
    let expression = parse( ~"(define x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
#[should_fail]
fn test_that_set_cannot_create_a_variable() {
    let env = test_env();
    let expression = parse( ~"(set! x 10)" );
    eval( expression, env );
}

#[test]
fn test_that_set_can_change_a_variable() {
    let env = test_env();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
fn test_that_set_returns_the_value_not_the_key() {
    let env = test_env();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match value {
        (Int(10), _) => (),
        (Symbol(~"x"), _) => fail ~"set! returned the key, not the value",
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
fn test_that_begin_can_handle_one_argument() {
    let env = test_env();
    let expression = parse( ~"(begin 10)" );
    let value = eval( expression, env );
    match value {
        (Int(10), _) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
fn test_that_begin_evaluates_all_arguments() {
    let env = test_env();
    let expression = parse( ~"(begin (define x 10) x)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
    match value {
        (Int(10), _) => (),
        _ => fail fmt!("Expected 10 got %s", value.first().to_str())
    }
}

#[test]
fn test_that_other_symbols_are_evaluated_as_procs() {
    let env = test_env();
    let expression = parse( ~"(+ 1 2)" );
    let value = eval( expression, env );
    match value {
        (Int(3), _) => (),
        _ => fail fmt!("(+ 1 2) became %s", value.first().to_str())
    }
}

#[test]
fn test_that_proc_params_are_evaluated() {
    let env=test_env();
    let expression = parse( ~"(+ (+ 1 2) 3)" );
    let value = eval (expression, env);
    match value {
        (Int(6), _) => (),
        _ => fail fmt!("(+ (+ 1 2) 3) became %s", value.first().to_str())
    }
}

#[test]
fn test_that_lambda_evaluates_to_a_proc() {
    let env=test_env();
    let expression = parse( ~"(lambda (x) (* x x))" );
    let value = eval(expression, env);
    match value {
       (Proc(_), _) => (),
        _ => fail ~"lambda doesn't turn into a Proc"
    }
}

#[test]
fn test_that_lambda_without_variables_evals() {
    let env=test_env();
    let expression = parse( ~"( (lambda () (+ 1 1))  )" );
    let value = eval(expression, env);
    match value {
        (Int(2), _) => (),
        _ => fail fmt!("lambda evaluated to %s", value.first().to_str())
    }
}

#[test]
fn test_that_lambda_with_a_variable_evals() {
    let env=test_env();
    let expression = parse( ~"( (lambda (x) (+ x 1)) 1  )" );
    let value = eval(expression, env);
    match value {
        (Int(2), _) => (),
        _ => fail fmt!("lambda evaluated to %s", value.first().to_str())
    }
}

fn eval( expression:Expression, environment:@Environment ) -> (Expression, @Environment ) {
    fn quote(expressions:~[Expression]) -> Expression {
        match expressions {
            [_, expr] => expr,
            _ => fail ~"Syntax Error: quote must take a single argument"
        }
    }

    fn begin(expressions:~[Expression], environment:@Environment) -> Expression {
        for expressions.tail().init().each() |&expression| {
            eval( expression, environment );
        }
        eval( expressions.last(), environment ).first()
    }

    fn if_(expressions:~[Expression], environment:@Environment) -> Expression {
        match expressions {
            [_, test, true_expr, false_expr] => {
                let condition = eval(test, environment).first();
                eval(if condition.to_bool() {
                    true_expr
                } else {
                    false_expr
                }, environment).first()
            }
            _ => fail ~"Syntax Error: if must take three arguments"
        }
    }

    fn reset_variable(expressions:~[Expression], environment:@Environment, function:~str) -> Expression {
        match expressions {
            [_, symbol, value] => {
                match copy symbol {
                    Symbol( key ) => {
                        environment.define(key, eval(value, environment).first());
                        symbol
                    }
                    _ => fail fmt!("Syntax Error: %s takes a symbol as its first argument", function)
                }
            }
            _ => fail fmt!("Syntax Error: %s must take two arguments", function)
        }
    }

    fn define(expressions:~[Expression], environment:@Environment) -> Expression {
        reset_variable(expressions, environment, ~"define")
    }

    fn set_bang(expressions:~[Expression], environment:@Environment) -> Expression {
        match copy expressions {
            [_, symbol, _] => {
                match copy symbol {
                    Symbol( key ) => {
                        match environment.lookup( copy key )  {
                            None => fail ~"Syntax Error: set! cannot create a variable",
                            _ => ()
                        }
                    }
                    _ => ()
                }
            }
            _ => ()
        }
        let symbol = reset_variable(expressions, environment, ~"set!");
        match copy symbol {
            Symbol( key ) => {
                match environment.lookup( copy key ) {
                    Some( value ) => value,
                    None => fail
                }
            }
            _ => fail
        }
    }

    fn proc(expressions:~[Expression], environment:@Environment) -> Expression {
        let exprs = expressions.map(|&expr| eval(expr, environment).first());
        match exprs.head() {
            Proc( procedure ) => procedure( exprs.tail(), environment ),
            _ => fail fmt!("\"%s\" is not a procedure", exprs.head().to_str())
        }
    }

    fn lambda(expressions:~[Expression], _:@Environment) -> Expression {
        match copy expressions {
            [_, List(param_names), expression] => Proc( |param_values, env| {
                    let local_env = @Environment::new( env );
                    for vec::zip(copy param_names, param_values).each |param| {
                        match param.first() {
                            Symbol(key) => local_env.define( key, param.second() ),
                            _ => fail ~"lambda params list must be list of symbols"
                        }
                    }
                    eval(copy expression, local_env).first()
                } ),
            _ => fail fmt!("Syntax Error: lambda requires 2 arguments, got \"%u\"", expressions.len()-1 )
        }
    }

    (match copy expression {
        List( expressions ) => {
            match expressions[0] {
                Symbol(~"quote") => quote(expressions),
                Symbol(~"begin") => begin(expressions, environment),
                Symbol(~"if") => if_(expressions, environment),
                Symbol(~"define") => define(expressions, environment),
                Symbol(~"set!") => set_bang(expressions, environment),
                Symbol(~"lambda") => lambda(expressions, environment),
                _ => proc(expressions, environment)
            }
        }
        Symbol( symbol ) => {
            match environment.lookup( copy symbol ) {
                Some( value ) => value,
                None => fail fmt!("Undefined symbol %s",symbol)
            }
        }
        _ => {
            expression
        }
    }, environment)
}

fn main() {
    fn evaluate( expr:~str, env:Environment ) -> Option<Environment> {
        let sent_expr = copy expr;

        let (port, chan): (pipes::Port<Environment>, pipes::Chan<Environment>) = pipes::stream();
        chan.send(env);
        let result = do task::try |move port| {
            let env = port.recv();
            let (result, new_env) = eval( parse(sent_expr), @env );
            (result, copy *new_env)
        };
        if result.is_ok() {
            let successful_result = result.unwrap();
            let evaluated_expression = successful_result.first();
            let new_env = successful_result.second();
            io::println( fmt!("%s -> %s", expr, evaluated_expression.to_str() ));
            Some(new_env)
        } else {
            io::println( fmt!("%s gave an error.", expr) );
            None
        }
    }

    let mut env = Environment::new_global_environment();
    loop {
        io::print("rusty> ");
        let in = io::stdin().read_line();
        let result = evaluate( in, copy env );
        match result {
            Some(new_env) => env = new_env,
            None => ()
        }
    }
}
<|endoftext|>


<commit_before>use crate::cli::Command;
use mprovision as mp;
use std::env;
use std::io::{self, Write};
use std::path::Path;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};

mod cli;

type Result = std::result::Result<(), cli::Error>;

fn main() {
    if let Err(e) = cli::parse(env::args()).and_then(run) {
        e.exit();
    }
}

fn run(command: cli::Command) -> Result {
    match command {
        Command::List(cli::ListParams {
            text,
            expire_in_days,
            directory,
        }) => list(&text, expire_in_days, directory),
        Command::ShowUuid(cli::ShowUuidParams { uuid, directory }) => show_uuid(&uuid, directory),
        Command::ShowFile(cli::ShowFileParams { file }) => show_file(&file),
        Command::Remove(cli::RemoveParams { ids, directory }) => remove(&ids, directory),
        Command::Clean(cli::CleanParams { directory }) => clean(directory),
    }
}

fn list(text: &Option<String>, expires_in_days: Option<u64>, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(std::iter::Iterator::collect)?;
    let date =
        expires_in_days.map(|days| SystemTime::now() + Duration::from_secs(days * 24 * 60 * 60));
    let filter_string = text.as_ref();
    let mut profiles = mp::filter(entries, |profile| match (date, filter_string) {
        (Some(date), Some(string)) => {
            profile.info.expiration_date <= date && profile.info.contains(string)
        }
        (Some(date), _) => profile.info.expiration_date <= date,
        (_, Some(string)) => profile.info.contains(string),
        (_, _) => true,
    });
    profiles.sort_by(|a, b| a.info.creation_date.cmp(&b.info.creation_date));
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    for (i, profile) in profiles.iter().enumerate() {
        let separator = if i + 1 == profiles.len() { "" } else { "\n" };
        writeln!(&mut stdout, "{}{}", profile.info.description(), separator)?;
    }
    Ok(())
}

fn show_uuid(uuid: &str, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profile = mp::find_by_uuid(&dir, &uuid)?;
    show_file(&profile.path)
}

fn show_file(path: &Path) -> Result {
    let xml = mp::show(&path)?;
    writeln!(io::stdout(), "{}", xml)?;
    Ok(())
}

fn remove(ids: &[String], directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profiles = mp::find_by_ids(&dir, &ids)?;
    remove_profiles(profiles)
}

fn clean(directory: Option<PathBuf>) -> Result {
    let date = SystemTime::now();
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(std::iter::Iterator::collect)?;
    let profiles = mp::filter(entries, |profile| profile.info.expiration_date <= date);
    remove_profiles(profiles)
}

fn remove_profiles(profiles: Vec<mp::Profile>) -> Result {
    let mut errors_exist = false;
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    for (i, profile) in profiles.iter().enumerate() {
        match mp::remove(&profile.path) {
            Ok(()) => {
                let separator = if i + 1 == profiles.len() { "" } else { "\n" };
                writeln!(&mut stdout, "{}{}", profile.info.description(), separator)?
            }
            Err(err) => {
                errors_exist = true;
                writeln!(io::stderr(), "{}", err)?
            }
        }
    }
    if errors_exist {
        // Don't need to show anything – all errors are already printed.
        Err(cli::Error::Custom(String::new()))
    } else {
        Ok(())
    }
}
<commit_msg>Pass profiles by reference in remove_profiles<commit_after>use crate::cli::Command;
use mprovision as mp;
use std::env;
use std::io::{self, Write};
use std::path::Path;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};

mod cli;

type Result = std::result::Result<(), cli::Error>;

fn main() {
    if let Err(e) = cli::parse(env::args()).and_then(run) {
        e.exit();
    }
}

fn run(command: cli::Command) -> Result {
    match command {
        Command::List(cli::ListParams {
            text,
            expire_in_days,
            directory,
        }) => list(&text, expire_in_days, directory),
        Command::ShowUuid(cli::ShowUuidParams { uuid, directory }) => show_uuid(&uuid, directory),
        Command::ShowFile(cli::ShowFileParams { file }) => show_file(&file),
        Command::Remove(cli::RemoveParams { ids, directory }) => remove(&ids, directory),
        Command::Clean(cli::CleanParams { directory }) => clean(directory),
    }
}

fn list(text: &Option<String>, expires_in_days: Option<u64>, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(std::iter::Iterator::collect)?;
    let date =
        expires_in_days.map(|days| SystemTime::now() + Duration::from_secs(days * 24 * 60 * 60));
    let filter_string = text.as_ref();
    let mut profiles = mp::filter(entries, |profile| match (date, filter_string) {
        (Some(date), Some(string)) => {
            profile.info.expiration_date <= date && profile.info.contains(string)
        }
        (Some(date), _) => profile.info.expiration_date <= date,
        (_, Some(string)) => profile.info.contains(string),
        (_, _) => true,
    });
    profiles.sort_by(|a, b| a.info.creation_date.cmp(&b.info.creation_date));
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    for (i, profile) in profiles.iter().enumerate() {
        let separator = if i + 1 == profiles.len() { "" } else { "\n" };
        writeln!(&mut stdout, "{}{}", profile.info.description(), separator)?;
    }
    Ok(())
}

fn show_uuid(uuid: &str, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profile = mp::find_by_uuid(&dir, &uuid)?;
    show_file(&profile.path)
}

fn show_file(path: &Path) -> Result {
    let xml = mp::show(&path)?;
    writeln!(io::stdout(), "{}", xml)?;
    Ok(())
}

fn remove(ids: &[String], directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profiles = mp::find_by_ids(&dir, &ids)?;
    remove_profiles(&profiles)
}

fn clean(directory: Option<PathBuf>) -> Result {
    let date = SystemTime::now();
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(std::iter::Iterator::collect)?;
    let profiles = mp::filter(entries, |profile| profile.info.expiration_date <= date);
    remove_profiles(&profiles)
}

fn remove_profiles(profiles: &[mp::Profile]) -> Result {
    let mut errors_exist = false;
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    for (i, profile) in profiles.iter().enumerate() {
        match mp::remove(&profile.path) {
            Ok(()) => {
                let separator = if i + 1 == profiles.len() { "" } else { "\n" };
                writeln!(&mut stdout, "{}{}", profile.info.description(), separator)?
            }
            Err(err) => {
                errors_exist = true;
                writeln!(io::stderr(), "{}", err)?
            }
        }
    }
    if errors_exist {
        // Don't need to show anything – all errors are already printed.
        Err(cli::Error::Custom(String::new()))
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use rustc_serialize::json;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_get_global_alias(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref alias_name = read_path_parameter!(req, "alias").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Find alias
    let mut found_aliases = HashMap::new();

    for index_ref in indices.names.find(alias_name) {
        let index = match indices.get(&index_ref) {
            Some(index) => index,
            None => continue,
        };

        let mut inner_map = HashMap::new();
        let mut inner_inner_map = HashMap::new();
        inner_inner_map.insert(alias_name, HashMap::<String, String>::new());
        inner_map.insert("aliases".to_owned(), inner_inner_map);
        found_aliases.insert(index.canonical_name().clone(), inner_map);
    }

    if !found_aliases.is_empty() {
        return Ok(json_response(status::Ok, json::encode(&found_aliases).unwrap()));
    } else {
        return Ok(json_response(status::NotFound, "{}"));
    }
}

pub fn view_get_alias_list(_req: &mut Request) -> IronResult<Response> {
    // let ref system = get_system!(req);
    // let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // TODO

    return Ok(json_response(status::Ok, "{}"));
}

pub fn view_get_alias(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");
    let ref alias_name = read_path_parameter!(req, "alias").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Get index
    let index_ref = match indices.names.find_canonical(index_name) {
        Some(index_ref) => index_ref,
        None => return Ok(json_response(status::NotFound, "{}")),
    };

    // Find alias
    if indices.names.iter_index_aliases(index_ref).any(|name| &name == alias_name) {
        return Ok(json_response(status::Ok, "{}"));
    } else {
        return Ok(json_response(status::NotFound, "{}"));
    }
}

pub fn view_put_alias(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_selector = read_path_parameter!(req, "index").unwrap_or("");
    let ref alias_name = read_path_parameter!(req, "alias").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Insert alias into names registry
    let index_refs = indices.names.find(*index_selector);
    match indices.names.insert_or_replace_alias(alias_name.to_string(), index_refs) {
        Ok(true) => {
            system.log.info("[api] created alias", b!("index" => *index_selector, "alias" => *alias_name));
        }
        Ok(false) => {
            system.log.info("[api] updated alias", b!("index" => *index_selector, "alias" => *alias_name));
        }
        Err(_) => {
            // TODO
            return Ok(json_response(status::Ok, "{\"acknowledged\": false}"));
        }
    }

    Ok(json_response(status::Ok, "{\"acknowledged\": true}"))
}
<commit_msg>Serialise alias API responses with serde<commit_after>use std::collections::HashMap;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_get_global_alias(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref alias_name = read_path_parameter!(req, "alias").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Find alias
    let mut found_aliases = HashMap::new();

    for index_ref in indices.names.find(alias_name) {
        let index = match indices.get(&index_ref) {
            Some(index) => index,
            None => continue,
        };

        let mut inner_map = HashMap::new();
        let mut inner_inner_map = HashMap::new();
        inner_inner_map.insert(alias_name, HashMap::<String, String>::new());
        inner_map.insert("aliases".to_owned(), inner_inner_map);
        found_aliases.insert(index.canonical_name().clone(), inner_map);
    }

    if !found_aliases.is_empty() {
        return Ok(json_response(status::Ok, format!("{}", json!(found_aliases))));
    } else {
        return Ok(json_response(status::NotFound, "{}"));
    }
}

pub fn view_get_alias_list(_req: &mut Request) -> IronResult<Response> {
    // let ref system = get_system!(req);
    // let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // TODO

    return Ok(json_response(status::Ok, "{}"));
}

pub fn view_get_alias(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");
    let ref alias_name = read_path_parameter!(req, "alias").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Get index
    let index_ref = match indices.names.find_canonical(index_name) {
        Some(index_ref) => index_ref,
        None => return Ok(json_response(status::NotFound, "{}")),
    };

    // Find alias
    if indices.names.iter_index_aliases(index_ref).any(|name| &name == alias_name) {
        return Ok(json_response(status::Ok, "{}"));
    } else {
        return Ok(json_response(status::NotFound, "{}"));
    }
}

pub fn view_put_alias(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_selector = read_path_parameter!(req, "index").unwrap_or("");
    let ref alias_name = read_path_parameter!(req, "alias").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Insert alias into names registry
    let index_refs = indices.names.find(*index_selector);
    match indices.names.insert_or_replace_alias(alias_name.to_string(), index_refs) {
        Ok(true) => {
            system.log.info("[api] created alias", b!("index" => *index_selector, "alias" => *alias_name));
        }
        Ok(false) => {
            system.log.info("[api] updated alias", b!("index" => *index_selector, "alias" => *alias_name));
        }
        Err(_) => {
            // TODO
            return Ok(json_response(status::Ok, "{\"acknowledged\": false}"));
        }
    }

    Ok(json_response(status::Ok, "{\"acknowledged\": true}"))
}
<|endoftext|>


<commit_before>use std::str;

// Game state changes
pub const GAMEEXITED : u16 = 2;

// Broadcasted game name
const HALO_RETAIL : &'static str = "halor";

// Invalid local port of the server
const INVALID_LOCAL_PORT : u16 = 0;

// Halo game versions
const HALO_VERSION_1_09 : &'static str = "01.00.09.0620";
const HALO_VERSION_1_10 : &'static str = "01.00.10.0621";

// HaloMD uses 1.09, but Halo PC 1.10 is interoperable
const VALID_GAME_VERSIONS: [&'static str; 2] = [ HALO_VERSION_1_09, HALO_VERSION_1_10 ];

// This isn't the whole packet, just the stuff we care about.
pub struct HeartbeatPacket {
    pub localport: u16,     // Can't trust source port due to some routers using a different port than this.
    pub gamename: String,   // Must be HALO_RETAIL
    pub gamever: String,    // Must be HALO_VERSION_1_09 or HALO_VERSION_1_10 in case it's unjoinable.
    pub statechanged: u16   // If it's GAMEEXITED, then the server is shutting down.
}

impl HeartbeatPacket {
    pub fn from_buffer(buffer: &[u8]) -> Option<HeartbeatPacket> {
        let mut ret = HeartbeatPacket {localport: 0, gamename: String::new(), gamever: String::new(), statechanged: 0};

        let mut line_iterator = buffer.split(|b| *b == 0);
        loop {
            let key = match line_iterator.next() {
                None => break,
                Some(n) => str::from_utf8(n).unwrap_or("")
            };
            let value = match line_iterator.next() {
                None => break,
                Some(n) => str::from_utf8(n).unwrap_or("")
            };

            match key {
                "localport" => {
                    ret.localport = value.parse::<u16>().unwrap_or(0);
                },
                "statechanged" => {
                    ret.statechanged = value.parse::<u16>().unwrap_or(0);
                },
                "gamever" => {
                    ret.gamever = value.to_string()
                },
                "gamename" => {
                    ret.gamename = value.to_string()
                },
                _ => {}
            }
        }

        if ret.localport == INVALID_LOCAL_PORT || ret.gamename != HALO_RETAIL || !VALID_GAME_VERSIONS.contains(&&*ret.gamename) {
            None
        }
        else {
            Some(ret)
        }
    }
}
<commit_msg>s/gamename/gamever/<commit_after>use std::str;

// Game state changes
pub const GAMEEXITED : u16 = 2;

// Broadcasted game name
const HALO_RETAIL : &'static str = "halor";

// Invalid local port of the server
const INVALID_LOCAL_PORT : u16 = 0;

// Halo game versions
const HALO_VERSION_1_09 : &'static str = "01.00.09.0620";
const HALO_VERSION_1_10 : &'static str = "01.00.10.0621";

// HaloMD uses 1.09, but Halo PC 1.10 is interoperable
const VALID_GAME_VERSIONS: [&'static str; 2] = [ HALO_VERSION_1_09, HALO_VERSION_1_10 ];

// This isn't the whole packet, just the stuff we care about.
pub struct HeartbeatPacket {
    pub localport: u16,     // Can't trust source port due to some routers using a different port than this.
    pub gamename: String,   // Must be HALO_RETAIL
    pub gamever: String,    // Must be HALO_VERSION_1_09 or HALO_VERSION_1_10 in case it's unjoinable.
    pub statechanged: u16   // If it's GAMEEXITED, then the server is shutting down.
}

impl HeartbeatPacket {
    pub fn from_buffer(buffer: &[u8]) -> Option<HeartbeatPacket> {
        let mut ret = HeartbeatPacket {localport: 0, gamename: String::new(), gamever: String::new(), statechanged: 0};

        let mut line_iterator = buffer.split(|b| *b == 0);
        loop {
            let key = match line_iterator.next() {
                None => break,
                Some(n) => str::from_utf8(n).unwrap_or("")
            };
            let value = match line_iterator.next() {
                None => break,
                Some(n) => str::from_utf8(n).unwrap_or("")
            };

            match key {
                "localport" => {
                    ret.localport = value.parse::<u16>().unwrap_or(0);
                },
                "statechanged" => {
                    ret.statechanged = value.parse::<u16>().unwrap_or(0);
                },
                "gamever" => {
                    ret.gamever = value.to_string()
                },
                "gamename" => {
                    ret.gamename = value.to_string()
                },
                _ => {}
            }
        }

        if ret.localport == INVALID_LOCAL_PORT || ret.gamename != HALO_RETAIL || !VALID_GAME_VERSIONS.contains(&&*ret.gamever) {
            None
        }
        else {
            Some(ret)
        }
    }
}
<|endoftext|>


<commit_before>extern crate git2;

use std::path::PathBuf;
use std::process::Command;

pub struct Shell {
    pub cwd: PathBuf,
}

impl Shell {
    pub fn command(&self, cmd: &str) -> (String, String) {
        /* debug!("Shell::command: {}", cmd); */
        /* debug!("cwd: {:?}", self.cwd); */
        let git_dir = if self.cwd.join(".git").exists() {
            self.cwd.join(".git")
        } else {
            self.cwd.to_path_buf()
        };
        /* debug!("GIT_DIR: {:?}", git_dir); */

        let output = Command::new("sh")
            .current_dir(&self.cwd)
            .arg("-c")
            .arg(&cmd)
            .env("GIT_DIR", &git_dir)
            .output()
            .unwrap_or_else(|e| panic!("failed to execute process: {}\n{}", cmd, e));

        let stdout = String::from_utf8(output.stdout)
            .expect("failed to decode utf8")
            .trim()
            .to_string();
        let stderr = String::from_utf8(output.stderr)
            .expect("failed to decode utf8")
            .trim()
            .to_string();
        /* debug!("stdout:\n{}", &stdout); */
        /* debug!("stderr:\n{}", &stderr); */
        /* debug!("\n"); */
        /* debug!("\n"); */
        return (stdout, stderr);
    }
}
<commit_msg>add debug output<commit_after>extern crate git2;

use std::path::PathBuf;
use std::process::Command;

pub struct Shell {
    pub cwd: PathBuf,
}

impl Shell {
    pub fn command(&self, cmd: &str) -> (String, String) {
        debug!("Shell::command: {}", cmd);
        debug!("cwd: {:?}", self.cwd);
        let git_dir = if self.cwd.join(".git").exists() {
            self.cwd.join(".git")
        } else {
            self.cwd.to_path_buf()
        };
        debug!("GIT_DIR: {:?}", git_dir);

        let output = Command::new("sh")
            .current_dir(&self.cwd)
            .arg("-c")
            .arg(&cmd)
            .env("GIT_DIR", &git_dir)
            .output()
            .unwrap_or_else(|e| panic!("failed to execute process: {}\n{}", cmd, e));

        let stdout = String::from_utf8(output.stdout)
            .expect("failed to decode utf8")
            .trim()
            .to_string();
        let stderr = String::from_utf8(output.stderr)
            .expect("failed to decode utf8")
            .trim()
            .to_string();
        debug!("stdout:\n{}", &stdout);
        debug!("stderr:\n{}", &stderr);
        debug!("\n");
        debug!("\n");
        return (stdout, stderr);
    }
}
<|endoftext|>


<commit_before>//! Helper module to compute a CRC32 checksum

use std::io;
use std::io::prelude::*;

static CRC32_TABLE : [u32; 256] = [
	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
];

/// Update the checksum prev based upon the contents of buf.
pub fn update(prev: u32, buf: &[u8]) -> u32
{
    let mut crc = prev ^ !0u32;

    for byte in buf.iter()
    {
        crc = CRC32_TABLE[((crc ^ (*byte as u32)) & 0xFF) as usize] ^ (crc >> 8);
    }

    return crc ^ !0u32;
}

/// Reader that validates the CRC32 when it reaches the EOF.
pub struct Crc32Reader<R>
{
    inner: R,
    crc: u32,
    check: u32,
}

impl<R> Crc32Reader<R>
{
    /// Get a new Crc32Reader which check the inner reader against checksum.
    pub fn new(inner: R, checksum: u32) -> Crc32Reader<R>
    {
        Crc32Reader
        {
            inner: inner,
            crc: 0,
            check: checksum,
        }
    }

    fn check_matches(&self) -> bool
    {
        self.check == self.crc
    }
}

impl<R: Read> Read for Crc32Reader<R>
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>
    {
        let count = match self.inner.read(buf)
        {
            Ok(0) if !self.check_matches() => { return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) },
            Ok(n) => n,
            Err(e) => return Err(e),
        };
        self.crc = update(self.crc, &buf[0..count]);
        Ok(count)
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn samples() {
        assert_eq!(super::update(0, b""), 0);

        // test vectors from the iPXE project (input and output are bitwise negated)
        assert_eq!(super::update(!0x12345678, b""), !0x12345678);
        assert_eq!(super::update(!0xffffffff, b"hello world"), !0xf2b5ee7a);
        assert_eq!(super::update(!0xffffffff, b"hello"), !0xc9ef5979);
        assert_eq!(super::update(!0xc9ef5979, b" world"), !0xf2b5ee7a);

        // Some vectors found on Rosetta code
        assert_eq!(super::update(0, b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), 0x190A55AD);
        assert_eq!(super::update(0, b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"), 0xFF6CAB0B);
        assert_eq!(super::update(0, b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"), 0x91267E8A);
    }
}
<commit_msg>Simplify CRC32 code<commit_after>//! Helper module to compute a CRC32 checksum

use std::io;
use std::io::prelude::*;

static CRC32_TABLE : [u32; 256] = [
	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
];

/// Update the checksum prev based upon the contents of buf.
pub fn update(prev: u32, buf: &[u8]) -> u32
{
    let mut crc = !prev;

    for byte in buf.iter()
    {
        crc = CRC32_TABLE[(crc as u8 ^ *byte) as usize] ^ (crc >> 8);
    }

    !crc
}

/// Reader that validates the CRC32 when it reaches the EOF.
pub struct Crc32Reader<R>
{
    inner: R,
    crc: u32,
    check: u32,
}

impl<R> Crc32Reader<R>
{
    /// Get a new Crc32Reader which check the inner reader against checksum.
    pub fn new(inner: R, checksum: u32) -> Crc32Reader<R>
    {
        Crc32Reader
        {
            inner: inner,
            crc: 0,
            check: checksum,
        }
    }

    fn check_matches(&self) -> bool
    {
        self.check == self.crc
    }
}

impl<R: Read> Read for Crc32Reader<R>
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>
    {
        let count = match self.inner.read(buf)
        {
            Ok(0) if !self.check_matches() => { return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) },
            Ok(n) => n,
            Err(e) => return Err(e),
        };
        self.crc = update(self.crc, &buf[0..count]);
        Ok(count)
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn samples() {
        assert_eq!(super::update(0, b""), 0);

        // test vectors from the iPXE project (input and output are bitwise negated)
        assert_eq!(super::update(!0x12345678, b""), !0x12345678);
        assert_eq!(super::update(!0xffffffff, b"hello world"), !0xf2b5ee7a);
        assert_eq!(super::update(!0xffffffff, b"hello"), !0xc9ef5979);
        assert_eq!(super::update(!0xc9ef5979, b" world"), !0xf2b5ee7a);

        // Some vectors found on Rosetta code
        assert_eq!(super::update(0, b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), 0x190A55AD);
        assert_eq!(super::update(0, b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"), 0xFF6CAB0B);
        assert_eq!(super::update(0, b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"), 0x91267E8A);
    }
}
<|endoftext|>