<commit_before>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::mem;

use self::winapi::winuser::*;
use self::winapi::windef::*;
use self::winapi::minwindef::*;
use self::winapi::wingdi::*;
use self::winapi::winnt::*;

struct MyBitmapType {
    info: BITMAPINFO,
    bytes_per_pixel: i32,
    width: i32,
    height: i32
}

static mut GLOBAL_RUNNING: bool = true;
static mut WIN32_BITMAP_INFO: MyBitmapType = MyBitmapType {
    info: BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: 0,
            biWidth: 0,
            biHeight: 0,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0
        } ,
        bmiColors: []
    },
    bytes_per_pixel: 4,
    width: 0,
    height: 0
};

static mut BITMAP_MEMORY: LPVOID = 0 as LPVOID;

unsafe fn win32_resize_dib_section(width: i32, height: i32) -> () {
    WIN32_BITMAP_INFO.width = width;
    WIN32_BITMAP_INFO.height = height;
    WIN32_BITMAP_INFO.info.bmiHeader.biWidth = width;
    WIN32_BITMAP_INFO.info.bmiHeader.biHeight = -height; //Top-down coord

    let bitmap_memory_size = (width*height)*WIN32_BITMAP_INFO.bytes_per_pixel;

    if BITMAP_MEMORY != 0 as LPVOID {
        kernel32::VirtualFree(BITMAP_MEMORY, 0 as u64, MEM_RELEASE);
    }

    BITMAP_MEMORY = kernel32::VirtualAlloc(0 as LPVOID, bitmap_memory_size as u64, MEM_COMMIT, PAGE_READWRITE);

    draw_weird_gradient(128,128);

}

unsafe fn draw_weird_gradient(x_offset: u32, y_offset: u32) {
    let width = WIN32_BITMAP_INFO.width;
    let height = WIN32_BITMAP_INFO.height;
    let bytes_per_pixel = WIN32_BITMAP_INFO.bytes_per_pixel;

    let pitch = width*bytes_per_pixel;
    let mut row: *mut u8 = BITMAP_MEMORY as *mut u8;
    for y in 0..height {
        let mut pixel: *mut u32 = row as *mut u32;
        for x in 0..width {
            *pixel = ((x as u32 + x_offset) << 0 ) + ((y as u32 + y_offset) << 8);
            pixel = pixel.offset(1);

        };
        row = row.offset(pitch as isize);
    };
}

unsafe fn win32_update_window(device_context: HDC, window_width: i32, window_height: i32) {
    gdi32::StretchDIBits(device_context,
        0, 0, WIN32_BITMAP_INFO.width, WIN32_BITMAP_INFO.height,
        0, 0, window_width, window_height,
        BITMAP_MEMORY,
        &WIN32_BITMAP_INFO.info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

pub fn main() {

    unsafe {
        WIN32_BITMAP_INFO.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
        WIN32_BITMAP_INFO.info.bmiHeader.biWidth = 1080;
        WIN32_BITMAP_INFO.info.bmiHeader.biHeight = 640;
    }

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        let device_context = user32::GetDC(window_handle);
        let mut window_rect: RECT = mem::uninitialized();
        user32::GetClientRect(window_handle, &mut window_rect);

        let mut x = 0;
        let mut y = 0;
        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }

            x += 1;
            y += 1;
            draw_weird_gradient(x,y);
            win32_update_window(device_context, window_rect.right, window_rect.bottom);
        }
    }
}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
        match msg {
            WM_SIZE => {
                println!("WM_SIZE");
                let mut window_rect: RECT = mem::uninitialized();
                user32::GetClientRect(hwnd, &mut window_rect);
                win32_resize_dib_section(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top);
            },
            WM_CLOSE => {  GLOBAL_RUNNING = false;  },
            WM_DESTROY => { GLOBAL_RUNNING = false; },
            WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
            WM_PAINT => {
                println!("WM_PAINT");
                let mut paint: PAINTSTRUCT = mem::uninitialized();
                let hdc = user32::BeginPaint(hwnd, &mut paint);
                let mut window_rect: RECT = mem::uninitialized();
                user32::GetClientRect(hwnd, &mut window_rect);
                win32_update_window(hdc, window_rect.right, window_rect.bottom);
                user32::EndPaint(hwnd, &paint);
            },
            _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
        };
        0
    }<commit_msg>Tidy up global usage<commit_after>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::mem;

use self::winapi::winuser::*;
use self::winapi::windef::*;
use self::winapi::minwindef::*;
use self::winapi::wingdi::*;
use self::winapi::winnt::*;

struct Win32OffscreenBuffer {
    info: BITMAPINFO,
    bytes_per_pixel: i32,
    width: i32,
    height: i32,
    memory: LPVOID
}

static mut GLOBAL_RUNNING: bool = true;
static mut REFRESH_DC: bool = false;

static mut OFFSCREEN_BUFFER: Win32OffscreenBuffer = Win32OffscreenBuffer {
    info: BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: 0,
            biWidth: 0,
            biHeight: 0,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0
        } ,
        bmiColors: []
    },
    bytes_per_pixel: 4,
    width: 0,
    height: 0,
    memory: 0 as LPVOID
};

unsafe fn win32_resize_dib_section(buffer: &mut Win32OffscreenBuffer, width: i32, height: i32) -> () {
    buffer.width = width;
    buffer.height = height;
    buffer.info.bmiHeader.biWidth = width;
    buffer.info.bmiHeader.biHeight = -height; //Top-down coord

    let bitmap_memory_size = (width*height)*buffer.bytes_per_pixel;

    if buffer.memory != 0 as LPVOID {
        kernel32::VirtualFree(buffer.memory, 0 as u64, MEM_RELEASE);
    }

    buffer.memory = kernel32::VirtualAlloc(0 as LPVOID, bitmap_memory_size as u64, MEM_COMMIT, PAGE_READWRITE);

}

unsafe fn draw_weird_gradient(buffer: &mut Win32OffscreenBuffer, x_offset: u32, y_offset: u32) {

    let width = buffer.width;
    let height = buffer.height;
    let bytes_per_pixel = buffer.bytes_per_pixel;

    let pitch = width*bytes_per_pixel;
    let mut row: *mut u8 = buffer.memory as *mut u8;
    for y in 0..height {
        let mut pixel: *mut u32 = row as *mut u32;
        for x in 0..width {
            *pixel = ((x as u32 + x_offset) << 0 ) + ((y as u32 + y_offset) << 8);
            pixel = pixel.offset(1);

        };
        row = row.offset(pitch as isize);
    };
}

unsafe fn win32_update_window(device_context: HDC, buffer: &mut Win32OffscreenBuffer, window_width: i32, window_height: i32) {
    gdi32::StretchDIBits(device_context,
        0, 0, buffer.width, buffer.height,
        0, 0, window_width, window_height,
        buffer.memory,
        &buffer.info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

pub fn main() {
    unsafe {
        OFFSCREEN_BUFFER.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
        OFFSCREEN_BUFFER.info.bmiHeader.biWidth = 1080;
        OFFSCREEN_BUFFER.info.bmiHeader.biHeight = 640;
    }

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        let mut device_context = user32::GetDC(window_handle);
        let mut window_rect: RECT = mem::uninitialized();
        user32::GetClientRect(window_handle, &mut window_rect);

        let mut x = 0;
        let mut y = 0;
        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }

            x += 1;
            y += 1;
            draw_weird_gradient(&mut OFFSCREEN_BUFFER, x,y);

            if REFRESH_DC {
                user32::ReleaseDC(window_handle, device_context);
                device_context = user32::GetDC(window_handle);
                user32::GetClientRect(window_handle, &mut window_rect);
                REFRESH_DC = false;
            }
            win32_update_window(device_context, &mut OFFSCREEN_BUFFER, window_rect.right, window_rect.bottom);

        }
    }
}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
    match msg {
        WM_SIZE => {
            println!("WM_SIZE");
            let mut window_rect: RECT = mem::uninitialized();
            user32::GetClientRect(hwnd, &mut window_rect);
            win32_resize_dib_section(&mut OFFSCREEN_BUFFER, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top);
            REFRESH_DC = true;
        },
        WM_CLOSE => {  GLOBAL_RUNNING = false;  },
        WM_DESTROY => { GLOBAL_RUNNING = false; },
        WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
        WM_PAINT => {
            println!("WM_PAINT");
            let mut paint: PAINTSTRUCT = mem::uninitialized();
            let hdc = user32::BeginPaint(hwnd, &mut paint);
            let mut window_rect: RECT = mem::uninitialized();
            user32::GetClientRect(hwnd, &mut window_rect);
            win32_update_window(hdc, &mut OFFSCREEN_BUFFER, window_rect.right, window_rect.bottom);
            user32::EndPaint(hwnd, &paint);
        },
        _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
    };
    0
}<|endoftext|>


<commit_before>//! Reject certain requests as instance load reaches capacity.
//!
//! The primary goal of this middleware is to avoid starving the download endpoint of resources.
//! When bots send many parallel requests that run slow database queries, download requests may
//! block and eventually timeout waiting for a database connection.
//!
//! Bots must continue to respect our crawler policy, but until we can manually block bad clients
//! we should avoid dropping download requests even if that means rejecting some legitimate
//! requests to other endpoints.

use std::env;
use std::sync::atomic::{AtomicUsize, Ordering};

use super::prelude::*;
use conduit::{RequestExt, StatusCode};

#[derive(Default)]
pub(super) struct BalanceCapacity {
    handler: Option<Box<dyn Handler>>,
    capacity: usize,
    in_flight_requests: AtomicUsize,
    report_only: bool,
    log_at_percentage: usize,
    throttle_at_percentage: usize,
    dl_only_at_percentage: usize,
}

impl BalanceCapacity {
    pub fn new(capacity: usize) -> Self {
        Self {
            handler: None,
            capacity,
            in_flight_requests: AtomicUsize::new(0),
            report_only: env::var("WEB_CAPACITY_REPORT_ONLY").ok().is_some(),
            log_at_percentage: read_env_percentage("WEB_CAPACITY_LOG_PCT", 50),
            throttle_at_percentage: read_env_percentage("WEB_CAPACITY_THROTTLE_PCT", 70),
            dl_only_at_percentage: read_env_percentage("WEB_CAPACITY_DL_ONLY_PCT", 80),
        }
    }
}

impl AroundMiddleware for BalanceCapacity {
    fn with_handler(&mut self, handler: Box<dyn Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for BalanceCapacity {
    fn call(&self, request: &mut dyn RequestExt) -> AfterResult {
        // The _drop_on_exit ensures the counter is decremented for all exit paths (including panics)
        let (_drop_on_exit, count) = RequestCounter::add_one(&self.in_flight_requests);
        let handler = self.handler.as_ref().unwrap();
        let load = 100 * count / self.capacity;

        // Begin logging request count so early stages of load increase can be located
        if load >= self.log_at_percentage {
            super::log_request::add_custom_metadata(request, "in_flight_requests", count);
        }

        // In report-only mode we serve all requests and only enforce the logging limit above
        if self.report_only {
            return handler.call(request);
        }

        // Download requests are always accepted
        if request.path().starts_with("/api/v1/crates/") && request.path().ends_with("/download") {
            return handler.call(request);
        }

        // Reject read-only requests as load nears capacity. Bots are likely to send only safe
        // requests and this helps prioritize requests that users may be reluctant to retry.
        if load >= self.throttle_at_percentage && request.method().is_safe() {
            return over_capacity_response(request);
        }

        // As load reaches capacity, all non-download requests are rejected
        if load >= self.dl_only_at_percentage {
            return over_capacity_response(request);
        }

        handler.call(request)
    }
}

fn over_capacity_response(request: &mut dyn RequestExt) -> AfterResult {
    // TODO: Generate an alert so we can investigate
    super::log_request::add_custom_metadata(request, "cause", "over capacity");
    let body = "Service temporarily unavailable";
    Response::builder()
        .status(StatusCode::SERVICE_UNAVAILABLE)
        .header(header::CONTENT_LENGTH, body.len())
        .body(Body::from_static(body.as_bytes()))
        .map_err(box_error)
}

fn read_env_percentage(name: &str, default: usize) -> usize {
    if let Ok(value) = env::var(name) {
        value.parse().unwrap_or(default)
    } else {
        default
    }
}

// FIXME(JTG): I've copied the following from my `conduit-hyper` crate.  Once we transition from
// `civet`, we could pass the in_flight_request count from `condut-hyper` via a request extension.

/// A struct that stores a reference to an atomic counter so it can be decremented when dropped
struct RequestCounter<'a> {
    counter: &'a AtomicUsize,
}

impl<'a> RequestCounter<'a> {
    fn add_one(counter: &'a AtomicUsize) -> (Self, usize) {
        let previous = counter.fetch_add(1, Ordering::SeqCst);
        (Self { counter }, previous + 1)
    }
}

impl<'a> Drop for RequestCounter<'a> {
    fn drop(&mut self) {
        self.counter.fetch_sub(1, Ordering::SeqCst);
    }
}
<commit_msg>Update report-only mode to include (proposed) rejection reason<commit_after>//! Reject certain requests as instance load reaches capacity.
//!
//! The primary goal of this middleware is to avoid starving the download endpoint of resources.
//! When bots send many parallel requests that run slow database queries, download requests may
//! block and eventually timeout waiting for a database connection.
//!
//! Bots must continue to respect our crawler policy, but until we can manually block bad clients
//! we should avoid dropping download requests even if that means rejecting some legitimate
//! requests to other endpoints.

use std::env;
use std::sync::atomic::{AtomicUsize, Ordering};

use super::prelude::*;
use conduit::{RequestExt, StatusCode};

#[derive(Default)]
pub(super) struct BalanceCapacity {
    handler: Option<Box<dyn Handler>>,
    capacity: usize,
    in_flight_requests: AtomicUsize,
    report_only: bool,
    log_at_percentage: usize,
    throttle_at_percentage: usize,
    dl_only_at_percentage: usize,
}

impl BalanceCapacity {
    pub fn new(capacity: usize) -> Self {
        Self {
            handler: None,
            capacity,
            in_flight_requests: AtomicUsize::new(0),
            report_only: env::var("WEB_CAPACITY_REPORT_ONLY").ok().is_some(),
            log_at_percentage: read_env_percentage("WEB_CAPACITY_LOG_PCT", 50),
            throttle_at_percentage: read_env_percentage("WEB_CAPACITY_THROTTLE_PCT", 70),
            dl_only_at_percentage: read_env_percentage("WEB_CAPACITY_DL_ONLY_PCT", 80),
        }
    }

    /// Handle a request normally
    fn handle(&self, request: &mut dyn RequestExt) -> AfterResult {
        self.handler.as_ref().unwrap().call(request)
    }

    /// Handle a request when load exceeds a threshold
    ///
    /// In report-only mode, log metadata is added but the request is still served. Otherwise,
    /// the request is rejected with a service unavailable response.
    fn handle_high_load(&self, request: &mut dyn RequestExt, note: &str) -> AfterResult {
        if self.report_only {
            // In report-only mode we serve all requests but add log metadata
            super::log_request::add_custom_metadata(request, "would_reject", note);
            self.handle(request)
        } else {
            // Reject the request
            super::log_request::add_custom_metadata(request, "cause", note);
            let body = "Service temporarily unavailable";
            Response::builder()
                .status(StatusCode::SERVICE_UNAVAILABLE)
                .header(header::CONTENT_LENGTH, body.len())
                .body(Body::from_static(body.as_bytes()))
                .map_err(box_error)
        }
    }
}

impl AroundMiddleware for BalanceCapacity {
    fn with_handler(&mut self, handler: Box<dyn Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for BalanceCapacity {
    fn call(&self, request: &mut dyn RequestExt) -> AfterResult {
        // The _drop_on_exit ensures the counter is decremented for all exit paths (including panics)
        let (_drop_on_exit, count) = RequestCounter::add_one(&self.in_flight_requests);
        let load = 100 * count / self.capacity;

        // Begin logging request count so early stages of load increase can be located
        if load >= self.log_at_percentage {
            super::log_request::add_custom_metadata(request, "in_flight_requests", count);
        }

        // Download requests are always accepted
        if request.path().starts_with("/api/v1/crates/") && request.path().ends_with("/download") {
            return self.handle(request);
        }

        // Reject read-only requests as load nears capacity. Bots are likely to send only safe
        // requests and this helps prioritize requests that users may be reluctant to retry.
        if load >= self.throttle_at_percentage && request.method().is_safe() {
            return self.handle_high_load(request, "over capacity (throttle)");
        }

        // As load reaches capacity, all non-download requests are rejected
        if load >= self.dl_only_at_percentage {
            return self.handle_high_load(request, "over capacity (download only)");
        }

        self.handle(request)
    }
}

fn read_env_percentage(name: &str, default: usize) -> usize {
    if let Ok(value) = env::var(name) {
        value.parse().unwrap_or(default)
    } else {
        default
    }
}

// FIXME(JTG): I've copied the following from my `conduit-hyper` crate.  Once we transition from
// `civet`, we could pass the in_flight_request count from `condut-hyper` via a request extension.

/// A struct that stores a reference to an atomic counter so it can be decremented when dropped
struct RequestCounter<'a> {
    counter: &'a AtomicUsize,
}

impl<'a> RequestCounter<'a> {
    fn add_one(counter: &'a AtomicUsize) -> (Self, usize) {
        let previous = counter.fetch_add(1, Ordering::SeqCst);
        (Self { counter }, previous + 1)
    }
}

impl<'a> Drop for RequestCounter<'a> {
    fn drop(&mut self) {
        self.counter.fetch_sub(1, Ordering::SeqCst);
    }
}
<|endoftext|>


<commit_before>use euclid::Point2D;
use calx_grid::{FovValue, HexGeom};
use world::World;
use location::Location;
use terraform::TerrainQuery;
use terrain;

#[derive(Clone)]
pub struct SightFov<'a> {
    w: &'a World,
    range: u32,
    pub origin: Location,
    prev_offset: Point2D<i32>,
}

impl<'a> SightFov<'a> {
    pub fn new(w: &'a World, range: u32, origin: Location) -> SightFov<'a> {
        SightFov {
            w: w,
            range: range,
            origin: origin,
            prev_offset: Point2D::new(0, 0),
        }
    }
}

impl<'a> PartialEq for SightFov<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.w as *const World == other.w as *const World && self.range == other.range &&
        self.origin == other.origin && self.prev_offset == other.prev_offset
    }
}

impl<'a> Eq for SightFov<'a> {}

impl<'a> FovValue for SightFov<'a> {
    fn advance(&self, offset: Point2D<i32>) -> Option<Self> {
        if offset.hex_dist() as u32 > self.range {
            return None;
        }

        if self.w.terrain(self.origin + self.prev_offset).blocks_sight() {
            return None;
        }

        let mut ret = self.clone();
        ret.prev_offset = offset;
        if let Some(dest) = self.w.visible_portal(self.origin + offset) {
            ret.origin = dest - offset;
        }

        Some(ret)
    }

    fn is_fake_isometric_wall(&self, offset: Point2D<i32>) -> bool {
        self.w.terrain(self.origin + offset).form == terrain::Form::Wall
    }
}
<commit_msg>Less split-happy implementation for FOV stopping<commit_after>use euclid::Point2D;
use calx_grid::{FovValue, HexGeom};
use world::World;
use location::Location;
use terraform::TerrainQuery;
use terrain;

#[derive(Clone)]
pub struct SightFov<'a> {
    w: &'a World,
    range: u32,
    pub origin: Location,
    is_edge: bool,
}

impl<'a> SightFov<'a> {
    pub fn new(w: &'a World, range: u32, origin: Location) -> SightFov<'a> {
        SightFov {
            w: w,
            range: range,
            origin: origin,
            is_edge: false,
        }
    }
}

impl<'a> PartialEq for SightFov<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.w as *const World == other.w as *const World && self.range == other.range &&
        self.origin == other.origin && self.is_edge == other.is_edge
    }
}

impl<'a> Eq for SightFov<'a> {}

impl<'a> FovValue for SightFov<'a> {
    fn advance(&self, offset: Point2D<i32>) -> Option<Self> {
        if offset.hex_dist() as u32 > self.range {
            return None;
        }

        if self.is_edge {
            return None;
        }

        let mut ret = self.clone();
        if let Some(dest) = self.w.visible_portal(self.origin + offset) {
            ret.origin = dest - offset;
        }

        if self.w.terrain(self.origin + offset).blocks_sight() {
            ret.is_edge = true;
        }

        Some(ret)
    }

    fn is_fake_isometric_wall(&self, offset: Point2D<i32>) -> bool {
        self.w.terrain(self.origin + offset).form == terrain::Form::Wall
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Johan Sköld.
// License: http://opensource.org/licenses/ISC

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

fn main() {
    let target = env::var("TARGET").unwrap();
    let profile = env::var("PROFILE").unwrap();
    let target_quad = target.split("-").collect::<Vec<_>>();
    let (arch, compiler) = (target_quad.first().unwrap(), target_quad.last().unwrap());
    let bitness = if *arch == "x86_64" { 64 } else { 32 };

    build_bgfx(bitness, compiler, &profile);
}

#[cfg(target_os = "windows")]
fn build_bgfx_msvc(bitness: u32) {
    let vs_version = env::var("VisualStudioVersion").expect("Visual Studio version not detected");
    let platform = if bitness == 32 { "X86" } else { "X64" };

    let vs_release = match vs_version.as_ref() {
        "12.0" => "2013",
        "14.0" => "2015",
        _ => panic!(format!("Unknown Visual Studio version: {:?}", vs_version)),
    };

    Command::new("make.exe")
        .current_dir("bgfx")
        .arg(format!(".build/projects/vs{}", vs_release))
        .output()
        .unwrap();

    let status = Command::new("MSBuild.exe")
                     .current_dir("bgfx")
                     .arg("/p:Configuration=Release")
                     .arg(format!("/p:Platform={}", platform))
                     .arg(format!(".build/projects/vs{}/bgfx.vcxproj", vs_release))
                     .status()
                     .expect("Failed to build bgfx");

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx");
    }

    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("win{}_vs{}", bitness, vs_release));
    path.push("bin");

    println!("cargo:rustc-link-lib=static=bgfxRelease");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());
}

#[cfg(target_os = "windows")]
fn build_bgfx(bitness: u32, compiler: &str, profile: &str) {
    if compiler == "msvc" {
        build_bgfx_msvc(bitness);
        return;
    }

    Command::new("make.exe")
        .current_dir("bgfx")
        .arg(".build/projects/gmake-mingw-gcc")
        .output()
        .unwrap();

    let status = Command::new("make.exe")
                     .current_dir("bgfx")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(".build/projects/gmake-mingw-gcc")
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .unwrap_or_else(|e| panic!("Failed to build bgfx: {}", e));

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx.");
    }

    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("win{}_mingw-gcc", bitness));
    path.push("bin");

    println!("cargo:rustc-link-lib=bgfx{}",
             if profile == "debug" { "Debug" } else { "Release" });
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-lib=gdi32");
    println!("cargo:rustc-link-lib=opengl32");
    println!("cargo:rustc-link-lib=psapi");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());
}

#[cfg(target_os = "linux")]
fn build_bgfx(bitness: u32, compiler: &str, profile: &str) {
    if compiler != "gnu" {
        panic!("Unsupported compiler");
    }

    // Generate makefiles
    Command::new("make")
        .current_dir("bgfx")
        .arg(".build/projects/gmake-linux")
        .output()
        .unwrap();

    // Build bgfx
    let status = Command::new("make")
                     .current_dir("bgfx")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(".build/projects/gmake-linux")
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .unwrap_or_else(|e| panic!("Failed to build bgfx: {}", e));

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx.");
    }

    // Output linker config
    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("linux{}_gcc", bitness));
    path.push("bin");

    println!("cargo:rustc-link-lib=bgfx{}",
             if profile == "debug" { "Debug" } else { "Release" });
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-lib=GL");
    println!("cargo:rustc-link-lib=X11");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());
}
<commit_msg>Cleaning up build script<commit_after>// Copyright (c) 2015, Johan Sköld.
// License: http://opensource.org/licenses/ISC

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

fn main() {
    let target = env::var("TARGET").unwrap();
    let profile = env::var("PROFILE").unwrap();

    let first_div = target.find('-').unwrap();
    let last_div = target.rfind('-').unwrap();

    let arch = &target[..first_div];
    let platform = &target[(first_div + 1)..last_div];
    let compiler = &target[(last_div + 1)..];
    let bitness = if arch == "x86_64" { 64 } else { 32 };

    match compiler {
        "msvc" => build_msvc(bitness),
        "gnu" => build_gnu(bitness, &profile, platform),
        _ => unreachable!(),
    }
}

fn build_msvc(bitness: u32) {
    let vs_version = env::var("VisualStudioVersion").expect("Visual Studio version not detected");
    let platform = if bitness == 32 { "X86" } else { "X64" };

    let vs_release = match vs_version.as_ref() {
        "12.0" => "2013",
        "14.0" => "2015",
        _ => panic!(format!("Unknown Visual Studio version: {:?}", vs_version)),
    };

    Command::new("make.exe")
        .current_dir("bgfx")
        .arg(format!(".build/projects/vs{}", vs_release))
        .output()
        .expect("Failed to generate project files");

    let status = Command::new("MSBuild.exe")
                     .current_dir("bgfx")
                     .arg("/p:Configuration=Release")
                     .arg(format!("/p:Platform={}", platform))
                     .arg(format!(".build/projects/vs{}/bgfx.vcxproj", vs_release))
                     .status()
                     .expect("Failed to build bgfx");

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx");
    }

    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("win{}_vs{}", bitness, vs_release));
    path.push("bin");

    println!("cargo:rustc-link-lib=static=bgfxRelease");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());
}

fn build_gnu(bitness: u32, profile: &str, platform: &str) {
    let project_name = match platform {
        "windows" => "gmake-mingw-gcc",
        "unknown-linux" => "gmake-linux",
        _ => unreachable!(),
    };

    let output_name = match platform {
        "windows" => format!("win{}_mingw-gcc", bitness),
        "unknown-linux" => format!("linux{}_gcc", bitness),
        _ => unreachable!(),
    };

    // Generate makefiles
    Command::new("make")
        .current_dir("bgfx")
        .arg(format!(".build/projects/{}", project_name))
        .output()
        .expect("Failed to generate makefiles");

    // Build bgfx
    let status = Command::new("make")
                     .current_dir("bgfx")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(format!(".build/projects/{}", project_name))
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .expect("Failed to build bgfx");

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx.");
    }

    // Output linker config
    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(output_name);
    path.push("bin");

    let config = if profile == "debug" { "Debug" } else { "Release" };
    println!("cargo:rustc-link-lib=bgfx{}", config);
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());

    match platform {
        "windows" => {
            println!("cargo:rustc-link-lib=gdi32");
            println!("cargo:rustc-link-lib=opengl32");
            println!("cargo:rustc-link-lib=psapi");
        }
        "unknown-linux" => {
            println!("cargo:rustc-link-lib=GL");
            println!("cargo:rustc-link-lib=X11");
        }
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>pub use self::token::Token;
pub use self::token::Category;

pub mod token;
pub mod implementations;

pub struct StateFunction(fn(&mut Lexer) -> Option<StateFunction>);

pub struct Lexer {
    data: String,
    char_count: usize,
    token_start: usize,
    token_position: usize,
    tokens: Vec<Token>,
}

pub fn new(data: &str) -> Lexer {
    Lexer{
      data: data.to_string(),
      char_count: data.chars().count(),
      token_start: 0,
      token_position: 0,
      tokens: vec![]
    }
}

impl Lexer {
    pub fn advance(&mut self) {
        if self.token_position < self.char_count-1 {
            self.token_position += 1;
        }
    }
}

mod tests {
    use super::new;

    #[test]
    fn new_initializes_correctly_with_unicode_data() {
        let lexer_data = "différent";
        let lexer = new(lexer_data);
        assert_eq!(lexer.data, lexer_data);
        assert_eq!(lexer.char_count, 9);
        assert_eq!(lexer.token_start, 0);
        assert_eq!(lexer.token_position, 0);
        assert_eq!(lexer.tokens, vec![]);
    }

    #[test]
    fn advance_increments_the_cursor_by_one() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        assert_eq!(lexer.token_position, 1);
        lexer.advance();
        assert_eq!(lexer.token_position, 2);
    }

    #[test]
    fn advance_stops_when_there_is_no_more_data() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);

        // Try to go beyond the last character.
        for _ in 0..lexer.char_count {
            lexer.advance();
        }

        assert_eq!(lexer.token_position, lexer.char_count-1);
    }
}
<commit_msg>Implement Lexer tokenize method.<commit_after>pub use self::token::Token;
pub use self::token::Category;

pub mod token;
pub mod implementations;

pub struct StateFunction(fn(&mut Lexer) -> Option<StateFunction>);

pub struct Lexer {
    data: String,
    char_count: usize,
    token_start: usize,
    token_position: usize,
    tokens: Vec<Token>,
}

pub fn new(data: &str) -> Lexer {
    Lexer{
      data: data.to_string(),
      char_count: data.chars().count(),
      token_start: 0,
      token_position: 0,
      tokens: vec![]
    }
}

impl Lexer {
    pub fn advance(&mut self) {
        if self.token_position < self.char_count-1 {
            self.token_position += 1;
        }
    }

    pub fn tokenize(&mut self, category: Category) {
        if self.token_start != self.token_position {
            let token = Token{
                lexeme: self.data.slice_chars(self.token_start, self.token_position).to_string(),
                category: category,
            };
            self.tokens.push(token);
            self.token_start = self.token_position;
        }
    }
}

mod tests {
    use super::new;
    use super::token::Token;
    use super::token::Category;

    #[test]
    fn new_initializes_correctly_with_unicode_data() {
        let lexer_data = "différent";
        let lexer = new(lexer_data);
        assert_eq!(lexer.data, lexer_data);
        assert_eq!(lexer.char_count, 9);
        assert_eq!(lexer.token_start, 0);
        assert_eq!(lexer.token_position, 0);
        assert_eq!(lexer.tokens, vec![]);
    }

    #[test]
    fn advance_increments_the_cursor_by_one() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        assert_eq!(lexer.token_position, 1);
        lexer.advance();
        assert_eq!(lexer.token_position, 2);
    }

    #[test]
    fn advance_stops_when_there_is_no_more_data() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);

        // Try to go beyond the last character.
        for _ in 0..lexer.char_count {
            lexer.advance();
        }

        assert_eq!(lexer.token_position, lexer.char_count-1);
    }

    #[test]
    fn tokenize_advances_token_start_to_cursor() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize(Category::Text);

        assert_eq!(lexer.token_start, 2);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.advance();
        lexer.advance();
        lexer.tokenize(Category::Text);

        let token = lexer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let lexer_data = "élégant";
        let mut lexer = new(lexer_data);
        lexer.tokenize(Category::Text);

        assert_eq!(lexer.tokens.len(), 0);
        assert_eq!(lexer.token_start, 0);
        assert_eq!(lexer.token_position, 0);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::io::Read;

use crate::common::LineIter;

type Point = (i32, i32);

struct Map {
    width: usize,
    data: Vec<u8>,
}

impl Map {
    pub fn from_input(input: &mut dyn Read) -> Self {
        let mut reader = LineIter::new(input);

        let mut data = reader.next().unwrap().as_bytes().to_owned();
        let width = data.len();

        while let Some(line) = reader.next() {
            let line = line.as_bytes();
            debug_assert_eq!(line.len(), width);

            data.extend_from_slice(line);
        }

        data.iter_mut().for_each(|b| *b -= b'0');

        Self { width, data }
    }

    pub fn from_input2(input: &mut dyn Read) -> Self {
        let mut reader = LineIter::new(input);

        let mut lines = Vec::new();

        while let Some(line) = reader.next() {
            let mut line = line.as_bytes().to_owned();
            line.iter_mut().for_each(|b| *b -= b'0');
            lines.push(line);
        }

        let mut data = Vec::new();
        let width = lines[0].len();

        for _y_repeat in 0..5 {
            for line in &mut lines {
                data.extend_from_slice(line);

                for _ in 0..4 {
                    let starting_pos = data.len() - width;
                    data.extend_from_within(starting_pos..);
                    let starting_pos = data.len() - width;
                    data[starting_pos..]
                        .iter_mut()
                        .for_each(|b| *b = (*b % 9) + 1);
                }

                line.iter_mut().for_each(|b| *b = (*b % 9) + 1);
            }
        }

        Self {
            width: width * 5,
            data,
        }
    }

    pub fn shortest_path(&self, start: Point, end: Point) -> u32 {
        let mut todo = BinaryHeap::new();
        todo.push(Reverse((Self::manhattan(start, end), 0, start)));

        let mut visited = vec![false; self.data.len()];

        let height = self.height() as i32;

        while let Some(Reverse((_, distance, pos))) = todo.pop() {
            if pos == end {
                return distance;
            }

            if visited[self.index(pos)] {
                continue;
            }

            visited[self.index(pos)] = true;

            let (x, y) = pos;

            for dy in -1..=1 {
                if y + dy < 0 || y + dy >= height {
                    continue;
                }

                for dx in -1..=1 {
                    if x + dx < 0 || (x + dx) >= self.width as i32 || dx * dy != 0 {
                        continue;
                    }

                    let new = (x + dx, y + dy);
                    let index = self.index(new);

                    if visited[index] {
                        continue;
                    }

                    let new_distance = distance + self.data[index] as u32;
                    let new_guess = Self::manhattan(new, end) + new_distance;

                    todo.push(Reverse((new_guess, new_distance, new)));
                }
            }
        }

        panic!("No route found from {:?} to {:?}", start, end);
    }

    fn manhattan((xa, ya): Point, (xb, yb): Point) -> u32 {
        (xa - xb).abs() as u32 + (ya - yb).abs() as u32
    }

    pub fn height(&self) -> usize {
        self.data.len() / self.width
    }

    pub fn index(&self, (x, y): Point) -> usize {
        y as usize * self.width + x as usize
    }
}

pub fn part1(input: &mut dyn Read) -> String {
    let map = Map::from_input(input);

    map.shortest_path((0, 0), (map.width as i32 - 1, map.height() as i32 - 1))
        .to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let map = Map::from_input2(input);

    map.shortest_path((0, 0), (map.width as i32 - 1, map.height() as i32 - 1))
        .to_string()
}

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

    use crate::test_implementation;

    const SAMPLE: &[u8] = include_bytes!("samples/15.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 40);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 315);
    }
}
<commit_msg>Use Dijkstra instead of A*<commit_after>use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::io::Read;

use crate::common::LineIter;

type Point = (i32, i32);

struct Map {
    width: usize,
    data: Vec<u8>,
}

impl Map {
    pub fn from_input(input: &mut dyn Read) -> Self {
        let mut reader = LineIter::new(input);

        let mut data = reader.next().unwrap().as_bytes().to_owned();
        let width = data.len();

        while let Some(line) = reader.next() {
            let line = line.as_bytes();
            debug_assert_eq!(line.len(), width);

            data.extend_from_slice(line);
        }

        data.iter_mut().for_each(|b| *b -= b'0');

        Self { width, data }
    }

    pub fn from_input2(input: &mut dyn Read) -> Self {
        let mut reader = LineIter::new(input);

        let mut lines = Vec::new();

        while let Some(line) = reader.next() {
            let mut line = line.as_bytes().to_owned();
            line.iter_mut().for_each(|b| *b -= b'0');
            lines.push(line);
        }

        let mut data = Vec::new();
        let width = lines[0].len();

        for _y_repeat in 0..5 {
            for line in &mut lines {
                data.extend_from_slice(line);

                for _ in 0..4 {
                    let starting_pos = data.len() - width;
                    data.extend_from_within(starting_pos..);
                    let starting_pos = data.len() - width;
                    data[starting_pos..]
                        .iter_mut()
                        .for_each(|b| *b = (*b % 9) + 1);
                }

                line.iter_mut().for_each(|b| *b = (*b % 9) + 1);
            }
        }

        Self {
            width: width * 5,
            data,
        }
    }

    pub fn shortest_path(&self, start: Point, end: Point) -> u32 {
        let mut todo = BinaryHeap::new();
        todo.push(Reverse((0, start)));

        let mut visited = vec![false; self.data.len()];

        let height = self.height() as i32;

        while let Some(Reverse((distance, pos))) = todo.pop() {
            if pos == end {
                return distance;
            }

            if visited[self.index(pos)] {
                continue;
            }

            visited[self.index(pos)] = true;

            let (x, y) = pos;

            for dy in -1..=1 {
                if y + dy < 0 || y + dy >= height {
                    continue;
                }

                for dx in -1..=1 {
                    if x + dx < 0 || (x + dx) >= self.width as i32 || dx * dy != 0 {
                        continue;
                    }

                    let new = (x + dx, y + dy);
                    let index = self.index(new);

                    if visited[index] {
                        continue;
                    }

                    let new_distance = distance + self.data[index] as u32;

                    todo.push(Reverse((new_distance, new)));
                }
            }
        }

        panic!("No route found from {:?} to {:?}", start, end);
    }

    pub fn height(&self) -> usize {
        self.data.len() / self.width
    }

    pub fn index(&self, (x, y): Point) -> usize {
        y as usize * self.width + x as usize
    }
}

pub fn part1(input: &mut dyn Read) -> String {
    let map = Map::from_input(input);

    map.shortest_path((0, 0), (map.width as i32 - 1, map.height() as i32 - 1))
        .to_string()
}

pub fn part2(input: &mut dyn Read) -> String {
    let map = Map::from_input2(input);

    map.shortest_path((0, 0), (map.width as i32 - 1, map.height() as i32 - 1))
        .to_string()
}

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

    use crate::test_implementation;

    const SAMPLE: &[u8] = include_bytes!("samples/15.txt");

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 40);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 315);
    }
}
<|endoftext|>


<commit_before>use crate::hasher::Digest;
use crate::Error;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::convert::TryFrom;

use core::convert::TryInto;
use core::fmt::Debug;
#[cfg(feature = "serde-codec")]
use serde_big_array::BigArray;

use unsigned_varint::encode as varint_encode;

#[cfg(feature = "std")]
use std::io;

#[cfg(not(feature = "std"))]
use core2::io;

/// Trait that implements hashing.
///
/// It is usually implemented by a custom code table enum that derives the [`Multihash` derive].
///
/// [`Multihash` derive]: crate::derive
pub trait MultihashDigest<const S: usize>:
    TryFrom<u64> + Into<u64> + Send + Sync + Unpin + Copy + Eq + Debug + 'static
{
    /// Calculate the hash of some input data.
    ///
    /// # Example
    ///
    /// ```
    /// // `Code` implements `MultihashDigest`
    /// use multihash::{Code, MultihashDigest};
    ///
    /// let hash = Code::Sha3_256.digest(b"Hello world!");
    /// println!("{:02x?}", hash);
    /// ```
    fn digest(&self, input: &[u8]) -> Multihash<S>;

    /// Create a multihash from an existing [`Digest`].
    ///
    /// # Example
    ///
    /// ```
    /// use multihash::{Code, MultihashDigest, Sha3_256, StatefulHasher};
    ///
    /// let mut hasher = Sha3_256::default();
    /// hasher.update(b"Hello world!");
    /// let hash = Code::multihash_from_digest(&hasher.finalize());
    /// println!("{:02x?}", hash);
    /// ```
    #[allow(clippy::needless_lifetimes)]
    fn multihash_from_digest<'a, D, const DIGEST_SIZE: usize>(digest: &'a D) -> Multihash<S>
    where
        D: Digest<DIGEST_SIZE>,
        Self: From<&'a D>;
}

/// A Multihash instance that only supports the basic functionality and no hashing.
///
/// With this Multihash implementation you can operate on Multihashes in a generic way, but
/// no hasher implementation is associated with the code.
///
/// # Example
///
/// ```
/// use multihash::Multihash;
///
/// const Sha3_256: u64 = 0x16;
/// let digest_bytes = [
///     0x16, 0x20, 0x64, 0x4b, 0xcc, 0x7e, 0x56, 0x43, 0x73, 0x04, 0x09, 0x99, 0xaa, 0xc8, 0x9e,
///     0x76, 0x22, 0xf3, 0xca, 0x71, 0xfb, 0xa1, 0xd9, 0x72, 0xfd, 0x94, 0xa3, 0x1c, 0x3b, 0xfb,
///     0xf2, 0x4e, 0x39, 0x38,
/// ];
/// let mh = Multihash::from_bytes(&digest_bytes).unwrap();
/// assert_eq!(mh.code(), Sha3_256);
/// assert_eq!(mh.size(), 32);
/// assert_eq!(mh.digest(), &digest_bytes[2..]);
/// ```
#[cfg_attr(feature = "serde-codec", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde-codec", derive(serde::Serialize))]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Multihash<const S: usize> {
    /// The code of the Multihash.
    code: u64,
    /// The actual size of the digest in bytes (not the allocated size).
    size: u8,
    /// The digest.
    #[cfg_attr(feature = "serde-codec", serde(with = "BigArray"))]
    digest: [u8; S],
}

impl<const S: usize> Default for Multihash<S> {
    fn default() -> Self {
        Self {
            code: 0,
            size: 0,
            digest: [0; S],
        }
    }
}

impl<const S: usize> Multihash<S> {
    /// Wraps the digest in a multihash.
    pub fn wrap(code: u64, input_digest: &[u8]) -> Result<Self, Error> {
        if input_digest.len() > S {
            return Err(Error::InvalidSize(input_digest.len() as _));
        }
        let size = input_digest.len();
        let mut digest = [0; S];
        digest[..size].copy_from_slice(input_digest);
        Ok(Self {
            code,
            size: size as u8,
            digest,
        })
    }

    /// Returns the code of the multihash.
    pub fn code(&self) -> u64 {
        self.code
    }

    /// Returns the size of the digest.
    pub fn size(&self) -> u8 {
        self.size
    }

    /// Returns the digest.
    pub fn digest(&self) -> &[u8] {
        &self.digest[..self.size as usize]
    }

    /// Reads a multihash from a byte stream.
    pub fn read<R: io::Read>(r: R) -> Result<Self, Error>
    where
        Self: Sized,
    {
        let (code, size, digest) = read_multihash(r)?;
        Ok(Self { code, size, digest })
    }

    /// Parses a multihash from a bytes.
    ///
    /// You need to make sure the passed in bytes have the correct length. The digest length
    /// needs to match the `size` value of the multihash.
    pub fn from_bytes(mut bytes: &[u8]) -> Result<Self, Error>
    where
        Self: Sized,
    {
        let result = Self::read(&mut bytes)?;
        // There were more bytes supplied than read
        if !bytes.is_empty() {
            return Err(Error::InvalidSize(bytes.len().try_into().expect(
                "Currently the maximum size is 255, therefore always fits into usize",
            )));
        }

        Ok(result)
    }

    /// Writes a multihash to a byte stream.
    pub fn write<W: io::Write>(&self, w: W) -> Result<(), Error> {
        write_multihash(w, self.code(), self.size(), self.digest())
    }

    #[cfg(feature = "alloc")]
    /// Returns the bytes of a multihash.
    pub fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(self.size().into());
        self.write(&mut bytes)
            .expect("writing to a vec should never fail");
        bytes
    }
}

// Don't hash the whole allocated space, but just the actual digest
#[allow(clippy::derive_hash_xor_eq)]
impl<const S: usize> core::hash::Hash for Multihash<S> {
    fn hash<T: core::hash::Hasher>(&self, state: &mut T) {
        self.code.hash(state);
        self.digest().hash(state);
    }
}

#[cfg(feature = "alloc")]
impl<const S: usize> From<Multihash<S>> for Vec<u8> {
    fn from(multihash: Multihash<S>) -> Self {
        multihash.to_bytes()
    }
}

#[cfg(feature = "scale-codec")]
impl<const S: usize> parity_scale_codec::Encode for Multihash<S> {
    fn encode_to<EncOut: parity_scale_codec::Output + ?Sized>(&self, dest: &mut EncOut) {
        let mut digest = [0; S];
        digest.copy_from_slice(&self.digest);
        self.code.encode_to(dest);
        self.size.encode_to(dest);
        // **NOTE** We write the digest directly to dest, since we have known the size of digest.
        //
        // We do not choose to encode &[u8] directly, because it will add extra bytes (the compact length of digest).
        // For a valid multihash, the length of digest must equal to `size`.
        // Therefore, we can only read raw bytes whose length is equal to `size` when decoding.
        dest.write(&digest[..self.size as usize]);
    }
}

#[cfg(feature = "scale-codec")]
impl<const S: usize> parity_scale_codec::EncodeLike for Multihash<S> {}

#[cfg(feature = "scale-codec")]
impl<const S: usize> parity_scale_codec::Decode for Multihash<S> {
    fn decode<DecIn: parity_scale_codec::Input>(
        input: &mut DecIn,
    ) -> Result<Self, parity_scale_codec::Error> {
        let code = parity_scale_codec::Decode::decode(input)?;
        let size = parity_scale_codec::Decode::decode(input)?;
        if size as usize > S {
            return Err(parity_scale_codec::Error::from("invalid size"));
        }
        // For a valid multihash, the length of digest must equal to the size.
        let mut digest = [0; S];
        input.read(&mut digest[..size as usize])?;
        Ok(Multihash { code, size, digest })
    }
}

/// Writes the multihash to a byte stream.
pub fn write_multihash<W>(mut w: W, code: u64, size: u8, digest: &[u8]) -> Result<(), Error>
where
    W: io::Write,
{
    let mut code_buf = varint_encode::u64_buffer();
    let code = varint_encode::u64(code, &mut code_buf);

    let mut size_buf = varint_encode::u8_buffer();
    let size = varint_encode::u8(size, &mut size_buf);

    w.write_all(code)?;
    w.write_all(size)?;
    w.write_all(digest)?;
    Ok(())
}

/// Reads a multihash from a byte stream that contains a full multihash (code, size and the digest)
///
/// Returns the code, size and the digest. The size is the actual size and not the
/// maximum/allocated size of the digest.
///
/// Currently the maximum size for a digest is 255 bytes.
pub fn read_multihash<R, const S: usize>(mut r: R) -> Result<(u64, u8, [u8; S]), Error>
where
    R: io::Read,
{
    let code = read_u64(&mut r)?;
    let size = read_u64(&mut r)?;

    if size > S as u64 || size > u8::MAX as u64 {
        return Err(Error::InvalidSize(size));
    }

    let mut digest = [0; S];
    r.read_exact(&mut digest[..size as usize])?;
    Ok((code, size as u8, digest))
}

#[cfg(feature = "std")]
pub(crate) use unsigned_varint::io::read_u64;

/// Reads 64 bits from a byte array into a u64
/// Adapted from unsigned-varint's generated read_u64 function at
/// https://github.com/paritytech/unsigned-varint/blob/master/src/io.rs
#[cfg(not(feature = "std"))]
pub(crate) fn read_u64<R: io::Read>(mut r: R) -> Result<u64, Error> {
    use unsigned_varint::decode;
    let mut b = varint_encode::u64_buffer();
    for i in 0..b.len() {
        let n = r.read(&mut (b[i..i + 1]))?;
        if n == 0 {
            return Err(Error::Varint(decode::Error::Insufficient));
        } else if decode::is_last(b[i]) {
            return Ok(decode::u64(&b[..=i]).unwrap().0);
        }
    }
    Err(Error::Varint(decode::Error::Overflow))
}

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

    #[test]
    fn roundtrip() {
        let hash = Code::Sha2_256.digest(b"hello world");
        let mut buf = [0u8; 35];
        hash.write(&mut buf[..]).unwrap();
        let hash2 = Multihash::read(&buf[..]).unwrap();
        assert_eq!(hash, hash2);
    }

    #[test]
    #[cfg(feature = "scale-codec")]
    fn test_scale() {
        use crate::{Hasher, Sha2_256};
        use parity_scale_codec::{Decode, Encode};

        let mh1 = Multihash::<32>::wrap(
            Code::Sha2_256.into(),
            Sha2_256::digest(b"hello world").as_ref(),
        )
        .unwrap();
        // println!("mh1: code = {}, size = {}, digest = {:?}", mh1.code(), mh1.size(), mh1.digest());
        let mh1_bytes = mh1.encode();
        // println!("Multihash<32>: {}", hex::encode(&mh1_bytes));
        let mh2: Multihash<32> = Decode::decode(&mut &mh1_bytes[..]).unwrap();
        assert_eq!(mh1, mh2);

        let mh3: Multihash<64> = Code::Sha2_256.digest(b"hello world");
        // println!("mh3: code = {}, size = {}, digest = {:?}", mh3.code(), mh3.size(), mh3.digest());
        let mh3_bytes = mh3.encode();
        // println!("Multihash<64>: {}", hex::encode(&mh3_bytes));
        let mh4: Multihash<64> = Decode::decode(&mut &mh3_bytes[..]).unwrap();
        assert_eq!(mh3, mh4);

        assert_eq!(mh1_bytes, mh3_bytes);
    }

    #[test]
    #[cfg(feature = "serde-codec")]
    fn test_serde() {
        let mh = Multihash::<32>::default();
        let bytes = serde_json::to_string(&mh).unwrap();
        let mh2 = serde_json::from_str(&bytes).unwrap();
        assert_eq!(mh, mh2);
    }
}
<commit_msg>fix: avoid copying digests where possible<commit_after>use crate::hasher::Digest;
use crate::Error;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::convert::TryFrom;

use core::convert::TryInto;
use core::fmt::Debug;
#[cfg(feature = "serde-codec")]
use serde_big_array::BigArray;

use unsigned_varint::encode as varint_encode;

#[cfg(feature = "std")]
use std::io;

#[cfg(not(feature = "std"))]
use core2::io;

/// Trait that implements hashing.
///
/// It is usually implemented by a custom code table enum that derives the [`Multihash` derive].
///
/// [`Multihash` derive]: crate::derive
pub trait MultihashDigest<const S: usize>:
    TryFrom<u64> + Into<u64> + Send + Sync + Unpin + Copy + Eq + Debug + 'static
{
    /// Calculate the hash of some input data.
    ///
    /// # Example
    ///
    /// ```
    /// // `Code` implements `MultihashDigest`
    /// use multihash::{Code, MultihashDigest};
    ///
    /// let hash = Code::Sha3_256.digest(b"Hello world!");
    /// println!("{:02x?}", hash);
    /// ```
    fn digest(&self, input: &[u8]) -> Multihash<S>;

    /// Create a multihash from an existing [`Digest`].
    ///
    /// # Example
    ///
    /// ```
    /// use multihash::{Code, MultihashDigest, Sha3_256, StatefulHasher};
    ///
    /// let mut hasher = Sha3_256::default();
    /// hasher.update(b"Hello world!");
    /// let hash = Code::multihash_from_digest(&hasher.finalize());
    /// println!("{:02x?}", hash);
    /// ```
    #[allow(clippy::needless_lifetimes)]
    fn multihash_from_digest<'a, D, const DIGEST_SIZE: usize>(digest: &'a D) -> Multihash<S>
    where
        D: Digest<DIGEST_SIZE>,
        Self: From<&'a D>;
}

/// A Multihash instance that only supports the basic functionality and no hashing.
///
/// With this Multihash implementation you can operate on Multihashes in a generic way, but
/// no hasher implementation is associated with the code.
///
/// # Example
///
/// ```
/// use multihash::Multihash;
///
/// const Sha3_256: u64 = 0x16;
/// let digest_bytes = [
///     0x16, 0x20, 0x64, 0x4b, 0xcc, 0x7e, 0x56, 0x43, 0x73, 0x04, 0x09, 0x99, 0xaa, 0xc8, 0x9e,
///     0x76, 0x22, 0xf3, 0xca, 0x71, 0xfb, 0xa1, 0xd9, 0x72, 0xfd, 0x94, 0xa3, 0x1c, 0x3b, 0xfb,
///     0xf2, 0x4e, 0x39, 0x38,
/// ];
/// let mh = Multihash::from_bytes(&digest_bytes).unwrap();
/// assert_eq!(mh.code(), Sha3_256);
/// assert_eq!(mh.size(), 32);
/// assert_eq!(mh.digest(), &digest_bytes[2..]);
/// ```
#[cfg_attr(feature = "serde-codec", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde-codec", derive(serde::Serialize))]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Multihash<const S: usize> {
    /// The code of the Multihash.
    code: u64,
    /// The actual size of the digest in bytes (not the allocated size).
    size: u8,
    /// The digest.
    #[cfg_attr(feature = "serde-codec", serde(with = "BigArray"))]
    digest: [u8; S],
}

impl<const S: usize> Default for Multihash<S> {
    fn default() -> Self {
        Self {
            code: 0,
            size: 0,
            digest: [0; S],
        }
    }
}

impl<const S: usize> Multihash<S> {
    /// Wraps the digest in a multihash.
    pub fn wrap(code: u64, input_digest: &[u8]) -> Result<Self, Error> {
        if input_digest.len() > S {
            return Err(Error::InvalidSize(input_digest.len() as _));
        }
        let size = input_digest.len();
        let mut digest = [0; S];
        digest[..size].copy_from_slice(input_digest);
        Ok(Self {
            code,
            size: size as u8,
            digest,
        })
    }

    /// Returns the code of the multihash.
    pub fn code(&self) -> u64 {
        self.code
    }

    /// Returns the size of the digest.
    pub fn size(&self) -> u8 {
        self.size
    }

    /// Returns the digest.
    pub fn digest(&self) -> &[u8] {
        &self.digest[..self.size as usize]
    }

    /// Reads a multihash from a byte stream.
    pub fn read<R: io::Read>(r: R) -> Result<Self, Error>
    where
        Self: Sized,
    {
        let (code, size, digest) = read_multihash(r)?;
        Ok(Self { code, size, digest })
    }

    /// Parses a multihash from a bytes.
    ///
    /// You need to make sure the passed in bytes have the correct length. The digest length
    /// needs to match the `size` value of the multihash.
    pub fn from_bytes(mut bytes: &[u8]) -> Result<Self, Error>
    where
        Self: Sized,
    {
        let result = Self::read(&mut bytes)?;
        // There were more bytes supplied than read
        if !bytes.is_empty() {
            return Err(Error::InvalidSize(bytes.len().try_into().expect(
                "Currently the maximum size is 255, therefore always fits into usize",
            )));
        }

        Ok(result)
    }

    /// Writes a multihash to a byte stream.
    pub fn write<W: io::Write>(&self, w: W) -> Result<(), Error> {
        write_multihash(w, self.code(), self.size(), self.digest())
    }

    #[cfg(feature = "alloc")]
    /// Returns the bytes of a multihash.
    pub fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(self.size().into());
        self.write(&mut bytes)
            .expect("writing to a vec should never fail");
        bytes
    }
}

// Don't hash the whole allocated space, but just the actual digest
#[allow(clippy::derive_hash_xor_eq)]
impl<const S: usize> core::hash::Hash for Multihash<S> {
    fn hash<T: core::hash::Hasher>(&self, state: &mut T) {
        self.code.hash(state);
        self.digest().hash(state);
    }
}

#[cfg(feature = "alloc")]
impl<const S: usize> From<Multihash<S>> for Vec<u8> {
    fn from(multihash: Multihash<S>) -> Self {
        multihash.to_bytes()
    }
}

#[cfg(feature = "scale-codec")]
impl<const S: usize> parity_scale_codec::Encode for Multihash<S> {
    fn encode_to<EncOut: parity_scale_codec::Output + ?Sized>(&self, dest: &mut EncOut) {
        self.code.encode_to(dest);
        self.size.encode_to(dest);
        // **NOTE** We write the digest directly to dest, since we have known the size of digest.
        //
        // We do not choose to encode &[u8] directly, because it will add extra bytes (the compact length of digest).
        // For a valid multihash, the length of digest must equal to `size`.
        // Therefore, we can only read raw bytes whose length is equal to `size` when decoding.
        dest.write(self.digest());
    }
}

#[cfg(feature = "scale-codec")]
impl<const S: usize> parity_scale_codec::EncodeLike for Multihash<S> {}

#[cfg(feature = "scale-codec")]
impl<const S: usize> parity_scale_codec::Decode for Multihash<S> {
    fn decode<DecIn: parity_scale_codec::Input>(
        input: &mut DecIn,
    ) -> Result<Self, parity_scale_codec::Error> {
        let mut mh = Multihash {
            code: parity_scale_codec::Decode::decode(input)?,
            size: parity_scale_codec::Decode::decode(input)?,
            digest: [0; S],
        };
        if mh.size as usize > S {
            return Err(parity_scale_codec::Error::from("invalid size"));
        }
        // For a valid multihash, the length of digest must equal to the size.
        input.read(&mut mh.digest[..mh.size as usize])?;
        Ok(mh)
    }
}

/// Writes the multihash to a byte stream.
pub fn write_multihash<W>(mut w: W, code: u64, size: u8, digest: &[u8]) -> Result<(), Error>
where
    W: io::Write,
{
    let mut code_buf = varint_encode::u64_buffer();
    let code = varint_encode::u64(code, &mut code_buf);

    let mut size_buf = varint_encode::u8_buffer();
    let size = varint_encode::u8(size, &mut size_buf);

    w.write_all(code)?;
    w.write_all(size)?;
    w.write_all(digest)?;
    Ok(())
}

/// Reads a multihash from a byte stream that contains a full multihash (code, size and the digest)
///
/// Returns the code, size and the digest. The size is the actual size and not the
/// maximum/allocated size of the digest.
///
/// Currently the maximum size for a digest is 255 bytes.
pub fn read_multihash<R, const S: usize>(mut r: R) -> Result<(u64, u8, [u8; S]), Error>
where
    R: io::Read,
{
    let code = read_u64(&mut r)?;
    let size = read_u64(&mut r)?;

    if size > S as u64 || size > u8::MAX as u64 {
        return Err(Error::InvalidSize(size));
    }

    let mut digest = [0; S];
    r.read_exact(&mut digest[..size as usize])?;
    Ok((code, size as u8, digest))
}

#[cfg(feature = "std")]
pub(crate) use unsigned_varint::io::read_u64;

/// Reads 64 bits from a byte array into a u64
/// Adapted from unsigned-varint's generated read_u64 function at
/// https://github.com/paritytech/unsigned-varint/blob/master/src/io.rs
#[cfg(not(feature = "std"))]
pub(crate) fn read_u64<R: io::Read>(mut r: R) -> Result<u64, Error> {
    use unsigned_varint::decode;
    let mut b = varint_encode::u64_buffer();
    for i in 0..b.len() {
        let n = r.read(&mut (b[i..i + 1]))?;
        if n == 0 {
            return Err(Error::Varint(decode::Error::Insufficient));
        } else if decode::is_last(b[i]) {
            return Ok(decode::u64(&b[..=i]).unwrap().0);
        }
    }
    Err(Error::Varint(decode::Error::Overflow))
}

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

    #[test]
    fn roundtrip() {
        let hash = Code::Sha2_256.digest(b"hello world");
        let mut buf = [0u8; 35];
        hash.write(&mut buf[..]).unwrap();
        let hash2 = Multihash::read(&buf[..]).unwrap();
        assert_eq!(hash, hash2);
    }

    #[test]
    #[cfg(feature = "scale-codec")]
    fn test_scale() {
        use crate::{Hasher, Sha2_256};
        use parity_scale_codec::{Decode, Encode};

        let mh1 = Multihash::<32>::wrap(
            Code::Sha2_256.into(),
            Sha2_256::digest(b"hello world").as_ref(),
        )
        .unwrap();
        // println!("mh1: code = {}, size = {}, digest = {:?}", mh1.code(), mh1.size(), mh1.digest());
        let mh1_bytes = mh1.encode();
        // println!("Multihash<32>: {}", hex::encode(&mh1_bytes));
        let mh2: Multihash<32> = Decode::decode(&mut &mh1_bytes[..]).unwrap();
        assert_eq!(mh1, mh2);

        let mh3: Multihash<64> = Code::Sha2_256.digest(b"hello world");
        // println!("mh3: code = {}, size = {}, digest = {:?}", mh3.code(), mh3.size(), mh3.digest());
        let mh3_bytes = mh3.encode();
        // println!("Multihash<64>: {}", hex::encode(&mh3_bytes));
        let mh4: Multihash<64> = Decode::decode(&mut &mh3_bytes[..]).unwrap();
        assert_eq!(mh3, mh4);

        assert_eq!(mh1_bytes, mh3_bytes);
    }

    #[test]
    #[cfg(feature = "serde-codec")]
    fn test_serde() {
        let mh = Multihash::<32>::default();
        let bytes = serde_json::to_string(&mh).unwrap();
        let mh2 = serde_json::from_str(&bytes).unwrap();
        assert_eq!(mh, mh2);
    }
}
<|endoftext|>


<commit_before>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use sync::{Arc, Mutex, RWLock};
use collections::hashmap::HashMap;
use schema;
use buffer;

#[deriving(Show, Eq, TotalEq, Hash, Clone)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str<'a>(&'a self) -> &'a str {
		let d = self.record.get_data();
		from_utf8(d).unwrap()
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan {
	relation: schema::Relation,
	segment: Arc<Mutex<schema::SPSegment>>,
	current: uint,
}

impl TableScan {
	fn new(rel: schema::Relation, seg: Arc<Mutex<schema::SPSegment>>) -> TableScan {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl Operatorish<Vec<Register>> for TableScan {
}

impl Iterator<Vec<Register>> for TableScan {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let mut seg = self.segment.lock();
			let tup = self.relation.get(seg.deref_mut(), self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			debug!("TS: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

struct Project<T> {
	input: T,
	registerids: Vec<uint>,
}

impl<T: Operatorish<Vec<Register>>> Project<T> {
	fn new(input: T, regs: Vec<uint>) -> Project<T> {
		Project {
			input: input,
			registerids: regs,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Project<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			None => None,
			Some(mut reg) => {
				let mut res = Vec::with_capacity(self.registerids.len());
				let mut regids = self.registerids.clone();
				regids.reverse();
				for index in regids.move_iter() {
					let value = reg.remove(index);
					let v = match value {
						None => fail!("Projection doesn't have vield {}", index),
						Some(v) => v,
					};
					res.push(v);
				}
				Some(res)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Project<T> {
}

#[deriving(Show)]
enum Selectable {
	Varchar(~str),
	Integer(int),
}

struct Select<T> {
	input: T,
	index: uint,
	value: Selectable,
}

impl<T: Operatorish<Vec<Register>>> Select<T> {
	fn new(input: T, index: uint, value: Selectable) -> Select<T> {
		Select {
			input: input,
			index: index,
			value: value,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Select<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		// initial value
		let mut cur = self.input.next();
		while cur.is_some() {
			// we made sure cur is Some(…), so we can unwrap safely
			let reg = cur.unwrap();

			// check what we got to select for and retrieve values
			// accordingly
			match self.value {
				// comparing to a string
				Varchar(ref v) => {
					println!("Comparing {} with {}",
						reg.get(self.index).get_str(),
						v);
					// getting the register value as string
					if reg.get(self.index).get_str() == *v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				},
				// comparing to a number
				Integer(v) => {
					// compare against reg as integer
					if reg.get(self.index).get_int() == v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				}
			}
		}
		// no more entries, signal iterator exhaustion
		None
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Select<T> {
}

struct HashJoin<T> {
	result: Vec<(Vec<Register>, Vec<Register>)>,
}

impl<T: Operatorish<Vec<Register>>> HashJoin<T> {
	fn new(mut left: T, mut right: T, on: (uint, uint)) -> HashJoin<T> {
		let mut map = HashMap::new();
		let (lindex, rindex) = on;
		for mut tuple in left {
			let element = tuple.get(lindex).clone();
			map.insert(element, tuple);
		}

		debug!("HashJoin map: {}", map);
		let mut res = Vec::new();
		for r in right {
			let element = r.get(rindex).clone();
			match map.find_copy(&element) {
				Some(s) => res.push((s, r)),
				None => continue,
			};
		}
		debug!("HashJon result: {}", res);

		HashJoin {
			result: res,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for HashJoin<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		match self.result.shift() {
			None => None,
			Some((mut s, r)) => {
				s.push_all_move(r);
				Some(s)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for HashJoin<T> {
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment::new(1, Arc::new(RWLock::new(manager)));

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));
	let segmut = Arc::new(Mutex::new(seg));

	{
		let mut ts = TableScan::new(relation.clone(), segmut.clone());
		for tuple in ts {
			println!("Got entry {}", tuple);
		}
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), segmut.clone());
			let mut pr = Print::new(ts, &mut mw);
			// force write by iterating, strange API
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), segmut.clone());
			let mut pr = Project::new(ts, vec!(0));
			let mut pr = Print::new(pr, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), segmut.clone());
			let mut se = Select::new(ts, 1, Integer(20));
			let mut pr = Print::new(se, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), segmut.clone());
			let mut se = Select::new(ts, 0, Varchar(~"Bob"));
			let mut pr = Print::new(se, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	assert!(false);
}

#[test]
fn simple_hashjoin() {
	let dir = match TempDir::new("hashjoin") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment::new(1, Arc::new(RWLock::new(manager)));

	/* first relation */
	let mut people = schema::Relation::new(~"Person");
	let id = schema::Column::new(~"id", schema::Integer, vec!(schema::NotNull));
	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	people.add_column(id);
	people.add_column(name);
	people.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Alice")));
	people.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"Bob")));
	people.insert(&mut seg, vec!(schema::Record::from_int(2), schema::Record::from_str(~"Eve")));
	people.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"Mallory")));

	/* second relation */
	let mut oses = schema::Relation::new(~"OSes");
	let ident = schema::Column::new(~"ident", schema::Integer, vec!(schema::NotNull));
	let os = schema::Column::new(~"OS", schema::Varchar(128), vec!(schema::NotNull));
	oses.add_column(ident);
	oses.add_column(os);
	oses.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Plan 9")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"NetBSD")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"GNU/Linux")));

	let mut mw = MemWriter::new();
	let segmut = Arc::new(Mutex::new(seg));
	let mut ts_left = TableScan::new(oses, segmut.clone());
	let mut ts_right = TableScan::new(people, segmut.clone());
	let mut hj = HashJoin::new(ts_left, ts_right, (0,0));
	{
		let mut pr = Print::new(hj, &mut mw);
		for _ in pr {}
	}
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap();
	println!("Saved: {}", printed);

	assert!(false);
}
<commit_msg>Fix up unit test to make it succeed<commit_after>use std::io::{TempDir, MemWriter};
use std::str::from_utf8;
use sync::{Arc, Mutex, RWLock};
use collections::hashmap::HashMap;
use schema;
use buffer;

#[deriving(Show, Eq, TotalEq, Hash, Clone)]
struct Register {
	record: schema::Record,
	datatype: schema::SqlType,
}

impl Register {
	fn new(rec: schema::Record, typ: schema::SqlType) -> Register {
		Register {
			record: rec,
			datatype: typ,
		}
	}

	fn set_int(&mut self, val: int) {
		// TODO
	}

	fn get_int(&self) -> int {
		self.record.to_int()
	}

	fn set_str(&mut self) {
		// TODO
	}

	fn get_str<'a>(&'a self) -> &'a str {
		let d = self.record.get_data();
		from_utf8(d).unwrap()
	}
}

impl Ord for Register {
	fn lt(&self, other: &Register) -> bool {
		// not the most robust implementation
		self.get_int() < other.get_int()
	}
}

trait Operatorish<T>: Iterator<T> {
	//fn open();
	//fn close(&self);
}

struct TableScan {
	relation: schema::Relation,
	segment: Arc<Mutex<schema::SPSegment>>,
	current: uint,
}

impl TableScan {
	fn new(rel: schema::Relation, seg: Arc<Mutex<schema::SPSegment>>) -> TableScan {
		TableScan {
			relation: rel,
			segment: seg,
			current: 0,
		}
	}
}

impl Operatorish<Vec<Register>> for TableScan {
}

impl Iterator<Vec<Register>> for TableScan {
	fn next(&mut self) -> Option<Vec<Register>> {
		if (self.current as u64) < self.relation.inserted {
			let mut seg = self.segment.lock();
			let tup = self.relation.get(seg.deref_mut(), self.current);
			let mut res = tup.move_iter().map(|(v, t)| Register::new(v, t)).
				collect::<Vec<Register>>();
			debug!("TS: {}", res);
			self.current += 1;
			Some(res)
		} else {
			None
		}
	}
}

struct Print<'a, T, V> {
	input: T,
	output: &'a mut V,
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Print<'a, T, V> {
	fn new(input: T, output: &'a mut V) -> Print<'a, T, V> {
		Print {
			input: input,
			output: output
		}
	}
}

impl<'a, T: Operatorish<Vec<Register>>, V: Writer> Iterator<Vec<Register>> for Print<'a, T, V> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			Some(reg) => {
				for item in reg.iter() {
					match item.datatype {
						schema::Varchar(_) => self.output.write(item.get_str().as_bytes()),
						schema::Integer => self.output.write(
							format!("{}", item.get_int()).as_bytes())
					};
					self.output.write(", ".as_bytes());
				}
				self.output.write("\n".as_bytes());
				Some(reg)
			},
			None => None,
		}
	}
}

struct Project<T> {
	input: T,
	registerids: Vec<uint>,
}

impl<T: Operatorish<Vec<Register>>> Project<T> {
	fn new(input: T, regs: Vec<uint>) -> Project<T> {
		Project {
			input: input,
			registerids: regs,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Project<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		let cur = self.input.next();
		match cur {
			None => None,
			Some(mut reg) => {
				let mut res = Vec::with_capacity(self.registerids.len());
				let mut regids = self.registerids.clone();
				regids.reverse();
				for index in regids.move_iter() {
					let value = reg.remove(index);
					let v = match value {
						None => fail!("Projection doesn't have vield {}", index),
						Some(v) => v,
					};
					res.push(v);
				}
				Some(res)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Project<T> {
}

#[deriving(Show)]
enum Selectable {
	Varchar(~str),
	Integer(int),
}

struct Select<T> {
	input: T,
	index: uint,
	value: Selectable,
}

impl<T: Operatorish<Vec<Register>>> Select<T> {
	fn new(input: T, index: uint, value: Selectable) -> Select<T> {
		Select {
			input: input,
			index: index,
			value: value,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for Select<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		// initial value
		let mut cur = self.input.next();
		while cur.is_some() {
			// we made sure cur is Some(…), so we can unwrap safely
			let reg = cur.unwrap();

			// check what we got to select for and retrieve values
			// accordingly
			match self.value {
				// comparing to a string
				Varchar(ref v) => {
					println!("Comparing {} with {}",
						reg.get(self.index).get_str(),
						v);
					// getting the register value as string
					if reg.get(self.index).get_str() == *v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				},
				// comparing to a number
				Integer(v) => {
					// compare against reg as integer
					if reg.get(self.index).get_int() == v {
						return Some(reg)
					} else {
						// not equal, skip to next entry
						cur = self.input.next();
						continue
					}
				}
			}
		}
		// no more entries, signal iterator exhaustion
		None
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for Select<T> {
}

struct HashJoin<T> {
	result: Vec<(Vec<Register>, Vec<Register>)>,
}

impl<T: Operatorish<Vec<Register>>> HashJoin<T> {
	fn new(mut left: T, mut right: T, on: (uint, uint)) -> HashJoin<T> {
		let mut map = HashMap::new();
		let (lindex, rindex) = on;
		for mut tuple in left {
			let element = tuple.get(lindex).clone();
			map.insert(element, tuple);
		}

		debug!("HashJoin map: {}", map);
		let mut res = Vec::new();
		for r in right {
			let element = r.get(rindex).clone();
			match map.find_copy(&element) {
				Some(s) => res.push((s, r)),
				None => continue,
			};
		}
		debug!("HashJon result: {}", res);

		HashJoin {
			result: res,
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Iterator<Vec<Register>> for HashJoin<T> {
	fn next(&mut self) -> Option<Vec<Register>> {
		match self.result.shift() {
			None => None,
			Some((mut s, r)) => {
				s.push_all_move(r);
				Some(s)
			}
		}
	}
}

impl<T: Operatorish<Vec<Register>>> Operatorish<Vec<Register>> for HashJoin<T> {
}

#[test]
fn simple_tablescan() {
	let dir = match TempDir::new("tablescan") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment::new(1, Arc::new(RWLock::new(manager)));

	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	let age = schema::Column::new(~"age", schema::Integer, vec!(schema::NotNull));
	let mut relation = schema::Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Alice"), schema::Record::from_int(20)));
	relation.insert(&mut seg, vec!(schema::Record::from_str(~"Bob"), schema::Record::from_int(40)));
	let segmut = Arc::new(Mutex::new(seg));

	{
		let mut ts = TableScan::new(relation.clone(), segmut.clone());
		for tuple in ts {
			println!("Got entry {}", tuple);
		}
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), segmut.clone());
			let mut pr = Print::new(ts, &mut mw);
			// force write by iterating, strange API
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), segmut.clone());
			let mut pr = Project::new(ts, vec!(0));
			let mut pr = Print::new(pr, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), segmut.clone());
			let mut se = Select::new(ts, 1, Integer(20));
			let mut pr = Print::new(se, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	{
		let mut mw = MemWriter::new();
		{
			let mut ts = TableScan::new(relation.clone(), segmut.clone());
			let mut se = Select::new(ts, 0, Varchar(~"Bob"));
			let mut pr = Print::new(se, &mut mw);
			for _ in pr {}
		}
		println!("Saved: {}", from_utf8(mw.unwrap()).unwrap());
	}

	assert!(false);
}

#[test]
fn simple_hashjoin() {
	let dir = match TempDir::new("hashjoin") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	//let p = dir.path();
	let p = Path::new(".");

	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut seg = schema::SPSegment::new(1, Arc::new(RWLock::new(manager)));

	/* first relation */
	let mut people = schema::Relation::new(~"Person");
	let id = schema::Column::new(~"id", schema::Integer, vec!(schema::NotNull));
	let name = schema::Column::new(~"name", schema::Varchar(128), vec!(schema::NotNull));
	people.add_column(id);
	people.add_column(name);
	people.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Alice")));
	people.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"Bob")));
	people.insert(&mut seg, vec!(schema::Record::from_int(2), schema::Record::from_str(~"Eve")));
	people.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"Mallory")));

	/* second relation */
	let mut oses = schema::Relation::new(~"OSes");
	let ident = schema::Column::new(~"ident", schema::Integer, vec!(schema::NotNull));
	let os = schema::Column::new(~"OS", schema::Varchar(128), vec!(schema::NotNull));
	oses.add_column(ident);
	oses.add_column(os);
	oses.insert(&mut seg, vec!(schema::Record::from_int(0), schema::Record::from_str(~"Plan 9")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(1), schema::Record::from_str(~"NetBSD")));
	oses.insert(&mut seg, vec!(schema::Record::from_int(3), schema::Record::from_str(~"GNU/Linux")));

	let mut mw = MemWriter::new();
	let segmut = Arc::new(Mutex::new(seg));
	let mut ts_left = TableScan::new(oses, segmut.clone());
	let mut ts_right = TableScan::new(people, segmut.clone());
	let mut hj = HashJoin::new(ts_left, ts_right, (0,0));
	{
		let mut pr = Print::new(hj, &mut mw);
		for _ in pr {}
	}
	let expected = ~"0, Plan 9, 0, Alice, \n1, NetBSD, 1, Bob, \n3, GNU/Linux, 3, Mallory, \n";
	let data = mw.unwrap();
	let printed = from_utf8(data).unwrap().to_owned();

	assert_eq!(expected, printed);
}
<|endoftext|>