<commit_before>extern crate moho;
extern crate sdl2;

use std::path::Path;
use std::cell::RefCell;
use std::rc::Rc;
use sdl2::rect;
use moho::resource_manager::*;

#[test]
fn loads_texture_data() {
    let (subject, tracker) = new_subject(None);
    let texture_data = subject.load_texture("mypath/").unwrap().texture;
    assert_eq!(texture_data.path, String::from("mypath/"));
    assert_eq!(tracker.borrow().load_count, 1);
}

#[test]
fn returns_error() {
    let (subject, tracker) = new_subject(Some("FAIL".into()));
    let texture_data = subject.load_texture("mypath/");
    assert_eq!(texture_data.err(), Some("FAIL".into()));
    assert_eq!(tracker.borrow().load_count, 1);
}

#[test]
fn caches_texture_datas() {
    let (subject, tracker) = new_subject(None);

    // get a new texture_data - number of calls is 1
    let texture_data1 = subject.load_texture("mypath/1").unwrap().texture;
    assert_eq!(texture_data1.path, String::from("mypath/1"));
    assert_eq!(tracker.borrow().load_count, 1);

    // load the same texture_data - number of calls should still be 1
    let texture_data2 = subject.load_texture("mypath/1").unwrap().texture;
    assert_eq!(texture_data2.path, String::from("mypath/1"));
    assert_eq!(tracker.borrow().load_count, 1);

    // load a different texture_data - number of calls should increase
    let texture_data3 = subject.load_texture("mypath/2").unwrap().texture;
    assert_eq!(texture_data3.path, String::from("mypath/2"));
    assert_eq!(tracker.borrow().load_count, 2);
}

#[derive(Debug)]
struct MockTexture {
    path: String,
}

struct RendererTracker {
    load_count: u16,
    last_src: Option<rect::Rect>,
    last_dst: Option<rect::Rect>,
}

impl RendererTracker {
    fn new() -> Self {
        RendererTracker {
            load_count: 0,
            last_dst: None,
            last_src: None,
        }
    }
}

struct MockRenderer {
    error: Option<String>,
    tracker: Rc<RefCell<RendererTracker>>,
}

impl Renderer for MockRenderer {
    type Texture = MockTexture;

    fn load_texture(&self, path: &Path) -> Result<TextureData<MockTexture>, String> {
        self.tracker.borrow_mut().load_count += 1;
        match self.error {
            None => {
                let texture = MockTexture { path: path.to_str().unwrap_or("").into() };
                Ok(TextureData {
                    texture: Rc::new(texture),
                    width: 48,
                    height: 60,
                })
            }
            Some(ref e) => Err(e.clone()),
        }
    }

    fn copy(&mut self,
            texture: &MockTexture,
            src: Option<rect::Rect>,
            dst: Option<rect::Rect>)
            -> Result<(), String> {
        match self.error {
            None => {
                let mut tracker = self.tracker.borrow_mut();
                tracker.last_src = src;
                tracker.last_dst = dst;
                Ok(())
            }
            Some(ref e) => Err(e.clone()),
        }
    }

    fn clear(&mut self) {}

    fn present(&mut self) {}

    fn output_size(&self) -> Result<(u32, u32), String> {
        Ok((0, 0))
    }

    fn fill_rects(&mut self, rects: &[rect::Rect]) -> Result<(), String> {
        Ok(())
    }
}

fn new_subject(error: Option<String>)
               -> (ResourceManager<MockRenderer>, Rc<RefCell<RendererTracker>>) {
    let tracker = Rc::new(RefCell::new(RendererTracker::new()));
    let renderer = MockRenderer {
        error: error,
        tracker: tracker.clone(),
    };

    let subject = ResourceManager::new(renderer);
    (subject, tracker)
}
<commit_msg>fix tests<commit_after>extern crate moho;
extern crate sdl2;
extern crate glm;

use std::path::Path;
use std::cell::RefCell;
use std::rc::Rc;
use sdl2::rect;
use moho::resource_manager::*;

#[test]
fn loads_texture_data() {
    let (subject, tracker) = new_subject(None);
    let texture_data = subject.load_texture("mypath/").unwrap().texture;
    assert_eq!(texture_data.path, String::from("mypath/"));
    assert_eq!(tracker.borrow().load_count, 1);
}

#[test]
fn returns_error() {
    let (subject, tracker) = new_subject(Some("FAIL".into()));
    let texture_data = subject.load_texture("mypath/");
    assert_eq!(texture_data.err(), Some("FAIL".into()));
    assert_eq!(tracker.borrow().load_count, 1);
}

#[test]
fn caches_texture_datas() {
    let (subject, tracker) = new_subject(None);

    // get a new texture_data - number of calls is 1
    let texture_data1 = subject.load_texture("mypath/1").unwrap().texture;
    assert_eq!(texture_data1.path, String::from("mypath/1"));
    assert_eq!(tracker.borrow().load_count, 1);

    // load the same texture_data - number of calls should still be 1
    let texture_data2 = subject.load_texture("mypath/1").unwrap().texture;
    assert_eq!(texture_data2.path, String::from("mypath/1"));
    assert_eq!(tracker.borrow().load_count, 1);

    // load a different texture_data - number of calls should increase
    let texture_data3 = subject.load_texture("mypath/2").unwrap().texture;
    assert_eq!(texture_data3.path, String::from("mypath/2"));
    assert_eq!(tracker.borrow().load_count, 2);
}

#[derive(Debug)]
struct MockTexture {
    path: String,
}

struct RendererTracker {
    load_count: u16,
    last_src: Option<rect::Rect>,
    last_dst: Option<rect::Rect>,
}

impl RendererTracker {
    fn new() -> Self {
        RendererTracker {
            load_count: 0,
            last_dst: None,
            last_src: None,
        }
    }
}

struct MockRenderer {
    error: Option<String>,
    tracker: Rc<RefCell<RendererTracker>>,
}

impl Renderer for MockRenderer {
    type Texture = MockTexture;

    fn load_texture(&self, path: &Path) -> Result<TextureData<MockTexture>, String> {
        self.tracker.borrow_mut().load_count += 1;
        match self.error {
            None => {
                let texture = MockTexture { path: path.to_str().unwrap_or("").into() };
                Ok(TextureData {
                    texture: Rc::new(texture),
                    dims: glm::uvec2(48, 60),
                })
            }
            Some(ref e) => Err(e.clone()),
        }
    }

    fn copy(&mut self,
            texture: &MockTexture,
            src: Option<rect::Rect>,
            dst: Option<rect::Rect>)
            -> Result<(), String> {
        match self.error {
            None => {
                let mut tracker = self.tracker.borrow_mut();
                tracker.last_src = src;
                tracker.last_dst = dst;
                Ok(())
            }
            Some(ref e) => Err(e.clone()),
        }
    }

    fn clear(&mut self) {}

    fn present(&mut self) {}

    fn output_size(&self) -> Result<(u32, u32), String> {
        Ok((0, 0))
    }

    fn fill_rects(&mut self, rects: &[rect::Rect]) -> Result<(), String> {
        Ok(())
    }
}

fn new_subject(error: Option<String>)
               -> (ResourceManager<MockRenderer>, Rc<RefCell<RendererTracker>>) {
    let tracker = Rc::new(RefCell::new(RendererTracker::new()));
    let renderer = MockRenderer {
        error: error,
        tracker: tracker.clone(),
    };

    let subject = ResourceManager::new(renderer);
    (subject, tracker)
}
<|endoftext|>


<commit_before>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;
use std::fmt::Show;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler : Share + Send {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>>;
}

impl<T: Send + Share + Show> Handler for fn(&mut Request) -> Result<Response, T> {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        { (*self)(request) }.map_err(|e| box e as Box<Show>)
    }
}
<commit_msg>Update to master<commit_after>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;
use std::fmt::Show;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler : Sync + Send {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>>;
}

impl<T: Send + Sync + Show> Handler for fn(&mut Request) -> Result<Response, T> {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        { (*self)(request) }.map_err(|e| box e as Box<Show>)
    }
}
<|endoftext|>


<commit_before><commit_msg>handle more keys<commit_after><|endoftext|>


<commit_before>use ffi::prelude::LLVMContextRef;
use ffi::{core, LLVMContext};
use util::CBox;

/// Contains all the LLVM entities
///
/// Every single entity attached to it has its lifetime to enforce the
/// rule that things from different contexts cannot interact
pub struct Context;
native_ref!(&Context = LLVMContextRef);
impl Context {
    /// Get a reference to the global context which has the same lifetime as
    /// the LLVM holder
    ///
    /// This is marked as unsafe because this results in undefined behaviour
    /// in a multithreaded context
    pub unsafe fn get_global() -> &'static Context {
        core::LLVMGetGlobalContext().into()
    }
    /// Create a new context, owned by the block that calls it
    pub fn new<'a>() -> CBox<'a, Self> {
        CBox::new(unsafe { core::LLVMContextCreate() })
    }
}
dispose!(Context, LLVMContext, core::LLVMContextDispose);

/// Implemented by everything that is inside the context
pub trait GetContext {
    /// Get the context containing this type
    fn get_context(&self) -> &Context;
}
<commit_msg>Clarify `GetContext` documentation<commit_after>use ffi::prelude::LLVMContextRef;
use ffi::{core, LLVMContext};
use util::CBox;

/// Contains all the LLVM entities
///
/// Every single entity attached to it has its lifetime to enforce the
/// rule that things from different contexts cannot interact
pub struct Context;
native_ref!(&Context = LLVMContextRef);
impl Context {
    /// Get a reference to the global context which has the same lifetime as
    /// the LLVM holder
    ///
    /// This is marked as unsafe because this results in undefined behaviour
    /// in a multithreaded context
    pub unsafe fn get_global() -> &'static Context {
        core::LLVMGetGlobalContext().into()
    }
    /// Create a new context, owned by the block that calls it
    pub fn new<'a>() -> CBox<'a, Self> {
        CBox::new(unsafe { core::LLVMContextCreate() })
    }
}
dispose!(Context, LLVMContext, core::LLVMContextDispose);

/// Implemented by everything that is owned by a context
pub trait GetContext {
    /// Returns a reference to the context that owns this value
    fn get_context(&self) -> &Context;
}
<|endoftext|>


<commit_before>use std::mem;
use super::gl;
use super::gl_lib::types::*;
use super::Buffer;

pub struct Context;

impl Context {
    pub unsafe fn current_context() -> Self {
        Context
    }

    pub fn clear_color(&mut self, color: super::Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();
            gl::GenBuffers(1, &mut id as *mut GLuint);
            Buffer::from_id(id)
        }
    }
}
<commit_msg>Add buffer binder fields to `Context`<commit_after>use std::mem;
use super::gl;
use super::gl_lib::types::*;
use super::{Buffer, ArrayBufferBinder, ElementArrayBufferBinder};

pub struct Context {
    array_buffer: ArrayBufferBinder,
    element_array_buffer: ElementArrayBufferBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder
        }
    }

    pub fn clear_color(&mut self, color: super::Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();
            gl::GenBuffers(1, &mut id as *mut GLuint);
            Buffer::from_id(id)
        }
    }
}
<|endoftext|>


<commit_before>//! Event callbacks.

use cairo::Context;
use gdk::{EventButton, EventMotion, EventScroll, EventCrossing, ScrollDirection, EventKey,
          keyval_from_name};
use gtk::{DrawingArea, Inhibit, WidgetExt};

use app;
use coords::{DeviceCoords, XYCoords};

mod drawing;

/// Draws the sounding, connected to the on-draw event signal.
pub fn draw_sounding(cr: &Context, ac: &app::AppContextPointer) -> Inhibit {

    let mut ac = ac.borrow_mut();

    drawing::prepare_to_draw(cr, &mut ac);
    drawing::draw_background(cr, &ac);
    drawing::draw_temperature_profiles(cr, &ac);
    drawing::draw_wind_profile(cr, &ac);
    drawing::draw_labels(cr, &ac);
    drawing::draw_active_sample(cr, &ac);

    Inhibit(false)
}

/// Handles zooming from the mouse wheel. Connected to the scroll-event signal.
pub fn scroll_event(
    _sounding_area: &DrawingArea,
    event: &EventScroll,
    ac: &app::AppContextPointer,
) -> Inhibit {

    const DELTA_SCALE: f64 = 1.05;
    const MIN_ZOOM: f64 = 1.0;
    const MAX_ZOOM: f64 = 10.0;

    let mut ac = ac.borrow_mut();

    let pos = ac.skew_t.convert_device_to_xy(event.get_position().into());
    let dir = event.get_direction();

    let old_zoom = ac.get_zoom_factor();
    let mut new_zoom = old_zoom;

    match dir {
        ScrollDirection::Up => {
            new_zoom *= DELTA_SCALE;
        }
        ScrollDirection::Down => {
            new_zoom /= DELTA_SCALE;
        }
        _ => {}
    }

    if new_zoom < MIN_ZOOM {
        new_zoom = MIN_ZOOM;
    } else if new_zoom > MAX_ZOOM {
        new_zoom = MAX_ZOOM;
    }
    ac.set_zoom_factor(new_zoom);

    let translate = ac.get_skew_t_translation();
    let translate_x = pos.x - old_zoom / new_zoom * (pos.x - translate.x);
    let translate_y = pos.y - old_zoom / new_zoom * (pos.y - translate.y);
    let translate = XYCoords {
        x: translate_x,
        y: translate_y,
    };
    ac.set_skew_t_translation(translate);

    ac.queue_draw_skew_t_rh_omega();

    Inhibit(true)
}

/// Handles button press events
pub fn button_press_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    ac: &app::AppContextPointer,
) -> Inhibit {

    // Left mouse button
    if event.get_button() == 1 {
        let mut ac = ac.borrow_mut();
        ac.skew_t.last_cursor_position_skew_t = Some(event.get_position().into());
        ac.skew_t.left_button_pressed = true;
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles button release events
pub fn button_release_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    ac: &app::AppContextPointer,
) -> Inhibit {
    if event.get_button() == 1 {
        let mut ac = ac.borrow_mut();
        ac.skew_t.last_cursor_position_skew_t = None;
        ac.skew_t.left_button_pressed = false;
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles leave notify
pub fn leave_event(
    _sounding_area: &DrawingArea,
    _event: &EventCrossing,
    ac: &app::AppContextPointer,
) -> Inhibit {
    let mut ac = ac.borrow_mut();

    ac.skew_t.last_cursor_position_skew_t = None;
    ac.last_sample_pressure = None;
    ac.queue_draw_skew_t_rh_omega();

    Inhibit(false)
}

/// Handles motion events
pub fn mouse_motion_event(
    sounding_area: &DrawingArea,
    event: &EventMotion,
    ac: &app::AppContextPointer,
) -> Inhibit {

    sounding_area.grab_focus();

    let mut ac = ac.borrow_mut();
    if ac.skew_t.left_button_pressed {
        if let Some(last_position) = ac.skew_t.last_cursor_position_skew_t {
            let old_position = ac.skew_t.convert_device_to_xy(last_position);
            let new_position = DeviceCoords::from(event.get_position());
            ac.skew_t.last_cursor_position_skew_t = Some(new_position);

            let new_position = ac.skew_t.convert_device_to_xy(new_position);
            let delta = (
                new_position.x - old_position.x,
                new_position.y - old_position.y,
            );
            let mut translate = ac.get_skew_t_translation();
            translate.x -= delta.0;
            translate.y -= delta.1;
            ac.set_skew_t_translation(translate);

            ac.queue_draw_skew_t_rh_omega();
        }
    } else if ac.plottable() {
        let position: DeviceCoords = event.get_position().into();

        ac.skew_t.last_cursor_position_skew_t = Some(position);
        let tp_position = ac.skew_t.convert_device_to_tp(position);
        ac.last_sample_pressure = Some(tp_position.pressure);

        ac.queue_draw_skew_t_rh_omega();
    }
    Inhibit(false)
}

/// Handles key-release events, display next or previous sounding in a series.
pub fn key_release_event(
    _sounding_area: &DrawingArea,
    event: &EventKey,
    dc: &app::AppContextPointer,
) -> Inhibit {

    let keyval = event.get_keyval();
    if keyval == keyval_from_name("Right") || keyval == keyval_from_name("KP_Right") {
        let mut dc = dc.borrow_mut();
        dc.display_next();
        Inhibit(true)
    } else if keyval == keyval_from_name("Left") || keyval == keyval_from_name("KP_Left") {
        let mut dc = dc.borrow_mut();
        dc.display_previous();
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles key-press events
pub fn key_press_event(
    _sounding_area: &DrawingArea,
    _event: &EventKey,
    _ac: &app::AppContextPointer,
) -> Inhibit {
    Inhibit(true)
}
<commit_msg>Use key press instead of release.<commit_after>//! Event callbacks.

use cairo::Context;
use gdk::{EventButton, EventMotion, EventScroll, EventCrossing, ScrollDirection, EventKey,
          keyval_from_name};
use gtk::{DrawingArea, Inhibit, WidgetExt};

use app;
use coords::{DeviceCoords, XYCoords};

mod drawing;

/// Draws the sounding, connected to the on-draw event signal.
pub fn draw_sounding(cr: &Context, ac: &app::AppContextPointer) -> Inhibit {

    let mut ac = ac.borrow_mut();

    drawing::prepare_to_draw(cr, &mut ac);
    drawing::draw_background(cr, &ac);
    drawing::draw_temperature_profiles(cr, &ac);
    drawing::draw_wind_profile(cr, &ac);
    drawing::draw_labels(cr, &ac);
    drawing::draw_active_sample(cr, &ac);

    Inhibit(false)
}

/// Handles zooming from the mouse wheel. Connected to the scroll-event signal.
pub fn scroll_event(
    _sounding_area: &DrawingArea,
    event: &EventScroll,
    ac: &app::AppContextPointer,
) -> Inhibit {

    const DELTA_SCALE: f64 = 1.05;
    const MIN_ZOOM: f64 = 1.0;
    const MAX_ZOOM: f64 = 10.0;

    let mut ac = ac.borrow_mut();

    let pos = ac.skew_t.convert_device_to_xy(event.get_position().into());
    let dir = event.get_direction();

    let old_zoom = ac.get_zoom_factor();
    let mut new_zoom = old_zoom;

    match dir {
        ScrollDirection::Up => {
            new_zoom *= DELTA_SCALE;
        }
        ScrollDirection::Down => {
            new_zoom /= DELTA_SCALE;
        }
        _ => {}
    }

    if new_zoom < MIN_ZOOM {
        new_zoom = MIN_ZOOM;
    } else if new_zoom > MAX_ZOOM {
        new_zoom = MAX_ZOOM;
    }
    ac.set_zoom_factor(new_zoom);

    let translate = ac.get_skew_t_translation();
    let translate_x = pos.x - old_zoom / new_zoom * (pos.x - translate.x);
    let translate_y = pos.y - old_zoom / new_zoom * (pos.y - translate.y);
    let translate = XYCoords {
        x: translate_x,
        y: translate_y,
    };
    ac.set_skew_t_translation(translate);

    ac.queue_draw_skew_t_rh_omega();

    Inhibit(true)
}

/// Handles button press events
pub fn button_press_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    ac: &app::AppContextPointer,
) -> Inhibit {

    // Left mouse button
    if event.get_button() == 1 {
        let mut ac = ac.borrow_mut();
        ac.skew_t.last_cursor_position_skew_t = Some(event.get_position().into());
        ac.skew_t.left_button_pressed = true;
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles button release events
pub fn button_release_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    ac: &app::AppContextPointer,
) -> Inhibit {
    if event.get_button() == 1 {
        let mut ac = ac.borrow_mut();
        ac.skew_t.last_cursor_position_skew_t = None;
        ac.skew_t.left_button_pressed = false;
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles leave notify
pub fn leave_event(
    _sounding_area: &DrawingArea,
    _event: &EventCrossing,
    ac: &app::AppContextPointer,
) -> Inhibit {
    let mut ac = ac.borrow_mut();

    ac.skew_t.last_cursor_position_skew_t = None;
    ac.last_sample_pressure = None;
    ac.queue_draw_skew_t_rh_omega();

    Inhibit(false)
}

/// Handles motion events
pub fn mouse_motion_event(
    sounding_area: &DrawingArea,
    event: &EventMotion,
    ac: &app::AppContextPointer,
) -> Inhibit {

    sounding_area.grab_focus();

    let mut ac = ac.borrow_mut();
    if ac.skew_t.left_button_pressed {
        if let Some(last_position) = ac.skew_t.last_cursor_position_skew_t {
            let old_position = ac.skew_t.convert_device_to_xy(last_position);
            let new_position = DeviceCoords::from(event.get_position());
            ac.skew_t.last_cursor_position_skew_t = Some(new_position);

            let new_position = ac.skew_t.convert_device_to_xy(new_position);
            let delta = (
                new_position.x - old_position.x,
                new_position.y - old_position.y,
            );
            let mut translate = ac.get_skew_t_translation();
            translate.x -= delta.0;
            translate.y -= delta.1;
            ac.set_skew_t_translation(translate);

            ac.queue_draw_skew_t_rh_omega();
        }
    } else if ac.plottable() {
        let position: DeviceCoords = event.get_position().into();

        ac.skew_t.last_cursor_position_skew_t = Some(position);
        let tp_position = ac.skew_t.convert_device_to_tp(position);
        ac.last_sample_pressure = Some(tp_position.pressure);

        ac.queue_draw_skew_t_rh_omega();
    }
    Inhibit(false)
}

/// Handles key-release events, display next or previous sounding in a series.
pub fn key_release_event(
    _sounding_area: &DrawingArea,
    _event: &EventKey,
    _dc: &app::AppContextPointer,
) -> Inhibit {
    Inhibit(false)
}

/// Handles key-press events
pub fn key_press_event(
    _sounding_area: &DrawingArea,
    event: &EventKey,
    ac: &app::AppContextPointer,
) -> Inhibit {

    let keyval = event.get_keyval();
    if keyval == keyval_from_name("Right") || keyval == keyval_from_name("KP_Right") {
        let mut ac = ac.borrow_mut();
        ac.display_next();
        Inhibit(true)
    } else if keyval == keyval_from_name("Left") || keyval == keyval_from_name("KP_Left") {
        let mut ac = ac.borrow_mut();
        ac.display_previous();
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
pub mod opcodes;

pub enum Register8 {
    A,
    F,
    B,
    C,
    D,
    E,
    H,
    L,
}

#[derive(Copy, Clone)]
pub enum Register16 {
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
}

pub enum Flag {
    Z,
    N,
    H,
    C,
}

pub struct Cpu {
    /// Accumulator register
    a: u8,
    /// Flags register
    f: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
}

impl Cpu {
    /// Init a new Cpu instance
    pub fn new() -> Cpu {
        Cpu {
            a: 0x0,
            f: 0x0,
            b: 0x0,
            c: 0x0,
            d: 0x0,
            e: 0x0,
            h: 0x0,
            l: 0x0,
            sp: 0x00,
            pc: 0x00,
        }
    }

    /// Get a 8bit value from register
    pub fn get_8(&self, reg: Register8) -> u8 {
        match reg {
            Register8::A => self.a,
            Register8::F => self.f,
            Register8::B => self.b,
            Register8::C => self.c,
            Register8::D => self.d,
            Register8::E => self.e,
            Register8::H => self.h,
            Register8::L => self.l,
        }
    }

    /// Set a 8bit value to a register
    pub fn set_8(&mut self, reg: Register8, v: u8) {
        match reg {
            Register8::A => self.a = v,
            Register8::F => self.f = v,
            Register8::B => self.b = v,
            Register8::C => self.c = v,
            Register8::D => self.d = v,
            Register8::E => self.e = v,
            Register8::H => self.h = v,
            Register8::L => self.l = v,
        };
    }

    /// Get a 16bit value from a register
    pub fn get_16(&self, reg: Register16) -> u16 {
        match reg {
            Register16::AF => join_bytes!(self.a, self.f),
            Register16::BC => join_bytes!(self.b, self.c),
            Register16::DE => join_bytes!(self.d, self.e),
            Register16::HL => join_bytes!(self.h, self.l),
            Register16::SP => self.sp,
            Register16::PC => self.pc,
        }
    }

    /// Set a 16bit value to a register
    pub fn set_16(&mut self, reg: Register16, v: u16) {
        match reg {
            Register16::AF => {
                self.a = high_byte!(v);
                self.f = low_byte!(v);
            }
            Register16::BC => {
                self.b = high_byte!(v);
                self.c = low_byte!(v);
            }
            Register16::DE => {
                self.d = high_byte!(v);
                self.e = low_byte!(v);
            }
            Register16::HL => {
                self.h = high_byte!(v);
                self.l = low_byte!(v);
            }
            Register16::SP => self.sp = v,
            Register16::PC => self.pc = v,
        }
    }

    /// Set a flags
    pub fn set_flag(&mut self, flag: Flag, set: bool) {
        let f = self.get_8(Register8::F);
        match (flag, set) {
            (Flag::Z, true) => self.set_8(Register8::F, (f | 0b10000000)),
            (Flag::N, true) => self.set_8(Register8::F, (f | 0b01000000)),
            (Flag::H, true) => self.set_8(Register8::F, (f | 0b00100000)),
            (Flag::C, true) => self.set_8(Register8::F, (f | 0b00010000)),
            (Flag::Z, false) => self.set_8(Register8::F, (f & 0b01111111)),
            (Flag::N, false) => self.set_8(Register8::F, (f & 0b10111111)),
            (Flag::H, false) => self.set_8(Register8::F, (f & 0b11011111)),
            (Flag::C, false) => self.set_8(Register8::F, (f & 0b11101111)),
        }
    }

    /// Inc 8bit register by 1
    pub fn inc_8(&mut self, reg: Register8) {
        match reg {
            Register8::A => self.a += 1,
            Register8::F => self.f += 1,
            Register8::B => self.b += 1,
            Register8::C => self.c += 1,
            Register8::D => self.d += 1,
            Register8::E => self.e += 1,
            Register8::H => self.h += 1,
            Register8::L => self.l += 1,
        };
    }

    /// Inc 16bit register by 1
    pub fn inc_16(&mut self, reg: Register16) {
        let v: u16 = self.get_16(reg) + 1;
        match reg {
            Register16::AF => {
                self.a = high_byte!(v);
                self.f = low_byte!(v);
            }
            Register16::BC => {
                self.b = high_byte!(v);
                self.c = low_byte!(v);
            }
            Register16::DE => {
                self.d = high_byte!(v);
                self.e = low_byte!(v);
            }
            Register16::HL => {
                self.h = high_byte!(v);
                self.l = low_byte!(v);
            }
            Register16::SP => self.sp = v,
            Register16::PC => self.pc = v,
        }

    }

    /// Inc PC by x
    pub fn inc_pc(&mut self, inc: u8) {
        self.pc += inc as u16;
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "=== CPU DEBUG ===\n\
            > A        <{:#x}> ({0})\n\
            > F (flag) <{:#x}> ({1})\n\
            > B        <{:#x}> ({2})\n\
            > C        <{:#x}> ({3})\n\
            > D        <{:#x}> ({4})\n\
            > E        <{:#x}> ({5})\n\
            > H        <{:#x}> ({6})\n\
            > L        <{:#x}> ({7})\n\
            > SP       <{:#x}> ({8})\n\
            > PC       <{:#x}> ({9})",
               self.get_8(Register8::A),
               self.get_8(Register8::F),
               self.get_8(Register8::B),
               self.get_8(Register8::C),
               self.get_8(Register8::D),
               self.get_8(Register8::E),
               self.get_8(Register8::H),
               self.get_8(Register8::L),
               self.get_16(Register16::SP),
               self.get_16(Register16::PC))
    }
}

#[test]
fn set_get() {
    let mut cpu = Cpu::new();

    cpu.set_8(Register8::A, 50);
    cpu.set_8(Register8::F, 51);
    cpu.set_8(Register8::B, 52);
    cpu.set_8(Register8::C, 53);
    cpu.set_8(Register8::D, 54);
    cpu.set_8(Register8::E, 55);
    cpu.set_8(Register8::H, 56);
    cpu.set_8(Register8::L, 57);
    assert_eq!(cpu.get_8(Register8::A), 50);
    assert_eq!(cpu.get_8(Register8::F), 51);
    assert_eq!(cpu.get_8(Register8::B), 52);
    assert_eq!(cpu.get_8(Register8::C), 53);
    assert_eq!(cpu.get_8(Register8::D), 54);
    assert_eq!(cpu.get_8(Register8::E), 55);
    assert_eq!(cpu.get_8(Register8::H), 56);
    assert_eq!(cpu.get_8(Register8::L), 57);

    cpu.set_16(Register16::AF, 50_000);
    cpu.set_16(Register16::BC, 51_000);
    cpu.set_16(Register16::DE, 52_000);
    cpu.set_16(Register16::HL, 53_000);
    cpu.set_16(Register16::SP, 54_000);
    cpu.set_16(Register16::PC, 55_000);
    assert_eq!(cpu.get_16(Register16::AF), 50_000);
    assert_eq!(cpu.get_16(Register16::BC), 51_000);
    assert_eq!(cpu.get_16(Register16::DE), 52_000);
    assert_eq!(cpu.get_16(Register16::HL), 53_000);
    assert_eq!(cpu.get_16(Register16::SP), 54_000);
    assert_eq!(cpu.get_16(Register16::PC), 55_000);

    cpu.inc_16(Register16::AF);
    cpu.inc_16(Register16::BC);
    cpu.inc_16(Register16::DE);
    cpu.inc_16(Register16::HL);
    cpu.inc_16(Register16::SP);
    cpu.inc_16(Register16::PC);
    assert_eq!(cpu.get_16(Register16::AF), 50_001);
    assert_eq!(cpu.get_16(Register16::BC), 51_001);
    assert_eq!(cpu.get_16(Register16::DE), 52_001);
    assert_eq!(cpu.get_16(Register16::HL), 53_001);
    assert_eq!(cpu.get_16(Register16::SP), 54_001);
    assert_eq!(cpu.get_16(Register16::PC), 55_001);

}

#[test]
fn flags() {
    let mut cpu = Cpu::new();

    cpu.set_flag(Flag::Z, true);
    assert_eq!(cpu.get_8(Register8::F), 0b10000000);
    cpu.set_flag(Flag::N, true);
    assert_eq!(cpu.get_8(Register8::F), 0b11000000);
    cpu.set_flag(Flag::H, true);
    assert_eq!(cpu.get_8(Register8::F), 0b11100000);
    cpu.set_flag(Flag::C, true);
    assert_eq!(cpu.get_8(Register8::F), 0b11110000);

    cpu.set_flag(Flag::Z, false);
    assert_eq!(cpu.get_8(Register8::F), 0b01110000);
    cpu.set_flag(Flag::N, false);
    assert_eq!(cpu.get_8(Register8::F), 0b00110000);
    cpu.set_flag(Flag::H, false);
    assert_eq!(cpu.get_8(Register8::F), 0b00010000);
    cpu.set_flag(Flag::C, false);
    assert_eq!(cpu.get_8(Register8::F), 0b00000000);
}
<commit_msg>reset flags<commit_after>use std::fmt;
pub mod opcodes;

pub enum Register8 {
    A,
    F,
    B,
    C,
    D,
    E,
    H,
    L,
}

#[derive(Copy, Clone)]
pub enum Register16 {
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
}

pub enum Flag {
    Z,
    N,
    H,
    C,
}

pub struct Cpu {
    /// Accumulator register
    a: u8,
    /// Flags register
    f: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    timer: u8,
}

impl Cpu {
    /// Init a new Cpu instance
    pub fn new() -> Cpu {
        Cpu {
            a: 0x0,
            f: 0x0,
            b: 0x0,
            c: 0x0,
            d: 0x0,
            e: 0x0,
            h: 0x0,
            l: 0x0,
            sp: 0x00,
            pc: 0x00,
            timer: 0x0,
        }
    }

    /// Get a 8bit value from register
    pub fn get_8(&self, reg: Register8) -> u8 {
        match reg {
            Register8::A => self.a,
            Register8::F => self.f,
            Register8::B => self.b,
            Register8::C => self.c,
            Register8::D => self.d,
            Register8::E => self.e,
            Register8::H => self.h,
            Register8::L => self.l,
        }
    }

    /// Set a 8bit value to a register
    pub fn set_8(&mut self, reg: Register8, v: u8) {
        match reg {
            Register8::A => self.a = v,
            Register8::F => self.f = v,
            Register8::B => self.b = v,
            Register8::C => self.c = v,
            Register8::D => self.d = v,
            Register8::E => self.e = v,
            Register8::H => self.h = v,
            Register8::L => self.l = v,
        };
    }

    /// Get a 16bit value from a register
    pub fn get_16(&self, reg: Register16) -> u16 {
        match reg {
            Register16::AF => join_bytes!(self.a, self.f),
            Register16::BC => join_bytes!(self.b, self.c),
            Register16::DE => join_bytes!(self.d, self.e),
            Register16::HL => join_bytes!(self.h, self.l),
            Register16::SP => self.sp,
            Register16::PC => self.pc,
        }
    }

    /// Set a 16bit value to a register
    pub fn set_16(&mut self, reg: Register16, v: u16) {
        match reg {
            Register16::AF => {
                self.a = high_byte!(v);
                self.f = low_byte!(v);
            }
            Register16::BC => {
                self.b = high_byte!(v);
                self.c = low_byte!(v);
            }
            Register16::DE => {
                self.d = high_byte!(v);
                self.e = low_byte!(v);
            }
            Register16::HL => {
                self.h = high_byte!(v);
                self.l = low_byte!(v);
            }
            Register16::SP => self.sp = v,
            Register16::PC => self.pc = v,
        }
    }

    /// Set a flags
    pub fn set_flag(&mut self, flag: Flag, set: bool) {
        let f = self.get_8(Register8::F);
        match (flag, set) {
            (Flag::Z, true) => self.set_8(Register8::F, (f | 0b10000000)),
            (Flag::N, true) => self.set_8(Register8::F, (f | 0b01000000)),
            (Flag::H, true) => self.set_8(Register8::F, (f | 0b00100000)),
            (Flag::C, true) => self.set_8(Register8::F, (f | 0b00010000)),
            (Flag::Z, false) => self.set_8(Register8::F, (f & 0b01111111)),
            (Flag::N, false) => self.set_8(Register8::F, (f & 0b10111111)),
            (Flag::H, false) => self.set_8(Register8::F, (f & 0b11011111)),
            (Flag::C, false) => self.set_8(Register8::F, (f & 0b11101111)),
        }
    }

    /// Set all the flags return to false
    pub fn reset_flags(&mut self) {
        self.set_flag(Flag::Z, false);
        self.set_flag(Flag::N, false);
        self.set_flag(Flag::H, false);
        self.set_flag(Flag::C, false);
    }

    /// Inc 8bit register by 1
    pub fn inc_8(&mut self, reg: Register8) {
        match reg {
            Register8::A => self.a += 1,
            Register8::F => self.f += 1,
            Register8::B => self.b += 1,
            Register8::C => self.c += 1,
            Register8::D => self.d += 1,
            Register8::E => self.e += 1,
            Register8::H => self.h += 1,
            Register8::L => self.l += 1,
        };
    }

    /// Inc 16bit register by 1
    pub fn inc_16(&mut self, reg: Register16) {
        let v: u16 = self.get_16(reg) + 1;
        match reg {
            Register16::AF => {
                self.a = high_byte!(v);
                self.f = low_byte!(v);
            }
            Register16::BC => {
                self.b = high_byte!(v);
                self.c = low_byte!(v);
            }
            Register16::DE => {
                self.d = high_byte!(v);
                self.e = low_byte!(v);
            }
            Register16::HL => {
                self.h = high_byte!(v);
                self.l = low_byte!(v);
            }
            Register16::SP => self.sp = v,
            Register16::PC => self.pc = v,
        }

    }

    /// Inc PC by x
    pub fn inc_pc(&mut self, inc: u8) {
        self.pc += inc as u16;
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "=== CPU DEBUG ===\n\
            > A        <{:#x}> ({0})\n\
            > F (flag) <{:#x}> ({1})\n\
            > B        <{:#x}> ({2})\n\
            > C        <{:#x}> ({3})\n\
            > D        <{:#x}> ({4})\n\
            > E        <{:#x}> ({5})\n\
            > H        <{:#x}> ({6})\n\
            > L        <{:#x}> ({7})\n\
            > SP       <{:#x}> ({8})\n\
            > PC       <{:#x}> ({9})",
               self.get_8(Register8::A),
               self.get_8(Register8::F),
               self.get_8(Register8::B),
               self.get_8(Register8::C),
               self.get_8(Register8::D),
               self.get_8(Register8::E),
               self.get_8(Register8::H),
               self.get_8(Register8::L),
               self.get_16(Register16::SP),
               self.get_16(Register16::PC))
    }
}

#[test]
fn set_get() {
    let mut cpu = Cpu::new();

    cpu.set_8(Register8::A, 50);
    cpu.set_8(Register8::F, 51);
    cpu.set_8(Register8::B, 52);
    cpu.set_8(Register8::C, 53);
    cpu.set_8(Register8::D, 54);
    cpu.set_8(Register8::E, 55);
    cpu.set_8(Register8::H, 56);
    cpu.set_8(Register8::L, 57);
    assert_eq!(cpu.get_8(Register8::A), 50);
    assert_eq!(cpu.get_8(Register8::F), 51);
    assert_eq!(cpu.get_8(Register8::B), 52);
    assert_eq!(cpu.get_8(Register8::C), 53);
    assert_eq!(cpu.get_8(Register8::D), 54);
    assert_eq!(cpu.get_8(Register8::E), 55);
    assert_eq!(cpu.get_8(Register8::H), 56);
    assert_eq!(cpu.get_8(Register8::L), 57);

    cpu.set_16(Register16::AF, 50_000);
    cpu.set_16(Register16::BC, 51_000);
    cpu.set_16(Register16::DE, 52_000);
    cpu.set_16(Register16::HL, 53_000);
    cpu.set_16(Register16::SP, 54_000);
    cpu.set_16(Register16::PC, 55_000);
    assert_eq!(cpu.get_16(Register16::AF), 50_000);
    assert_eq!(cpu.get_16(Register16::BC), 51_000);
    assert_eq!(cpu.get_16(Register16::DE), 52_000);
    assert_eq!(cpu.get_16(Register16::HL), 53_000);
    assert_eq!(cpu.get_16(Register16::SP), 54_000);
    assert_eq!(cpu.get_16(Register16::PC), 55_000);

    cpu.inc_16(Register16::AF);
    cpu.inc_16(Register16::BC);
    cpu.inc_16(Register16::DE);
    cpu.inc_16(Register16::HL);
    cpu.inc_16(Register16::SP);
    cpu.inc_16(Register16::PC);
    assert_eq!(cpu.get_16(Register16::AF), 50_001);
    assert_eq!(cpu.get_16(Register16::BC), 51_001);
    assert_eq!(cpu.get_16(Register16::DE), 52_001);
    assert_eq!(cpu.get_16(Register16::HL), 53_001);
    assert_eq!(cpu.get_16(Register16::SP), 54_001);
    assert_eq!(cpu.get_16(Register16::PC), 55_001);

}

#[test]
fn flags() {
    let mut cpu = Cpu::new();

    cpu.set_flag(Flag::Z, true);
    assert_eq!(cpu.get_8(Register8::F), 0b10000000);
    cpu.set_flag(Flag::N, true);
    assert_eq!(cpu.get_8(Register8::F), 0b11000000);
    cpu.set_flag(Flag::H, true);
    assert_eq!(cpu.get_8(Register8::F), 0b11100000);
    cpu.set_flag(Flag::C, true);
    assert_eq!(cpu.get_8(Register8::F), 0b11110000);

    cpu.set_flag(Flag::Z, false);
    assert_eq!(cpu.get_8(Register8::F), 0b01110000);
    cpu.set_flag(Flag::N, false);
    assert_eq!(cpu.get_8(Register8::F), 0b00110000);
    cpu.set_flag(Flag::H, false);
    assert_eq!(cpu.get_8(Register8::F), 0b00010000);
    cpu.set_flag(Flag::C, false);
    assert_eq!(cpu.get_8(Register8::F), 0b00000000);
}
<|endoftext|>


<commit_before>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(())  => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn creates_project_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn errors_when_creating_project_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn create_copies_the_template_file() {
    assert!(false);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<commit_msg>don't assign a name var if I don't need it.<commit_after>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(())  => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn creates_project_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn errors_when_creating_project_file() {
    assert!(false);
}

#[test]
fn create_copies_the_template_file() {
    assert!(false);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<|endoftext|>


<commit_before>extern crate image;

use self::image::imageops::resize;

use braille::make_braille;

pub struct Display {
    image: image::GrayImage,
    pub char_width: u32,
    pub char_height: u32,
}

impl Display {
    pub fn new(img: image::GrayImage, width: u32, height: u32) -> Display {
        Display {
            image: resize(&img, width*2, height*4, image::Lanczos3),
            char_width: width,
            char_height: height,
        }
    }

    pub fn render(&self) -> String {
        let mut target = String::with_capacity(
            // The char_height is added to account for newlines
            (self.char_height*self.char_width + self.char_height) as usize
        );
        for y in 0..self.char_height {
            for x in 0..self.char_width {
                let mut dot_map = 0b0000_0000;
                for i in 0..8 {
                    let abs_x = (x*2) + (i % 2);
                    let abs_y = (y*4) + (i / 2);
                    dot_map |= if self.sample(abs_x, abs_y) {
                        0b1000_0000 >> i
                    } else {
                        0
                    };
                }
                target.push(make_braille(dot_map));
            }
            target.push('\n');
        }
        target
    }
    fn sample(&self, x: u32, y: u32) -> bool {
        self.image[(x, y)][0] < 128
    }
}
<commit_msg>Cleaned up display.rs<commit_after>extern crate image;

use self::image::imageops::resize;

use braille::make_braille;

pub struct Display {
    image: image::GrayImage,
    pub char_width: u32,
    pub char_height: u32,
}

impl Display {
    pub fn new(img: image::GrayImage, width: u32, height: u32) -> Display {
        Display {
            image: resize(&img, width*2, height*4, image::Lanczos3),
            char_width: width,
            char_height: height,
        }
    }

    pub fn render(&self) -> String {
        let mut target = String::with_capacity(
            // The char_height is added to account for newlines
            (self.char_height*self.char_width + self.char_height) as usize
        );
        for y in 0..self.char_height {
            for x in 0..self.char_width {
                target.push(self.braillify_block(x, y));
            }
            target.push('\n');
        }
        target
    }

    fn braillify_block(&self, x: u32, y: u32) -> char {
        let mut dot_map = 0b0000_0000;
        for i in 0..8 {
            let abs_x = (x*2) + (i % 2);
            let abs_y = (y*4) + (i / 2);

            dot_map |= if self.sample(abs_x, abs_y) {
                0b1000_0000 >> i
            } else {
                0
            };
        }
        make_braille(dot_map)
    }

    fn sample(&self, x: u32, y: u32) -> bool {
        self.image[(x, y)][0] < 128
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[cfg(target_os = "linux")]
extern crate i2cdev;
extern crate termion;

#[cfg(target_os = "linux")]
use self::i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use self::i2cdev::linux::LinuxI2CDevice;

use std;
use shared::*;

const MODE_REGISTER: u8 = 0x00;
const FRAME_REGISTER: u8 = 0x01;
const AUTOPLAY1_REGISTER: u8 = 0x02;
const AUTOPLAY2_REGISTER: u8 = 0x03;
const BLINK_REGISTER: u8 = 0x05;
const AUDIOSYNC_REGISTER: u8 = 0x06;
const BREATH1_REGISTER: u8 = 0x08;
const BREATH2_REGISTER: u8 = 0x09;
const SHUTDOWN_REGISTER: u8 = 0x0A;
const GAIN_REGISTER: u8 = 0x0B;
const ADC_REGISTER: u8 = 0x0C;

const CONFIG_BANK: u8 = 0x0B;
const BANK_ADDRESS: u8 = 0xFD;

const PICTURE_MODE: u8 = 0x00;
const AUTOPLAY_MODE: u8 = 0x08;
const AUDIOPLAY_MODE: u8 = 0x18;

const ENABLE_OFFSET: u8 = 0x00;
const BLINK_OFFSET: u8 = 0x12;
const COLOR_OFFSET: u8 = 0x24;

const ADDRESS: u16 = 0x74;

const LED_COLUMNS: usize = 17;
const LED_ROWS: usize = 7;

/// Represents a device capable of displaying a rectangular bitmap buffer.
pub trait Display {
    fn show(&mut self, buffer: &[Column]);
}

#[cfg(target_os = "linux")]
/// A Scroll pHAT HD device connected over I2C bus (e.g. on a Raspberry Pi).
pub struct I2CDisplay {
    device: LinuxI2CDevice,
    frame: u8,
}

#[cfg(target_os = "linux")]
impl I2CDisplay {
    /// Creates a new I2CDisplay device using the I2C device identified by the provided
    /// `device_id` (normally 1 or 2).
    pub fn new(device_id: u8) -> I2CDisplay {
        let device_path = format!("/dev/i2c-{}", device_id);
        let d = LinuxI2CDevice::new(device_path, ADDRESS).unwrap();
        let mut display = I2CDisplay {
            device: d,
            frame: 0,
        };

        display.init_display();

        display
    }

    fn bank(&mut self, bank: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.write_data(BANK_ADDRESS, &[bank])
    }

    fn register(
        &mut self,
        bank: u8,
        register: u8,
        value: u8,
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.bank(bank);
        self.write_data(register, &[value])
    }

    fn frame(&mut self, frame: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, FRAME_REGISTER, frame)
    }

    fn write_data(
        &mut self,
        base_address: u8,
        data: &[u8],
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        for i in 0..data.len() {
            self.device
                .smbus_write_byte_data(base_address + (i as u8), data[i])?;
        }
        Ok(())
    }

    fn reset_display(&mut self) {
        self.sleep(true);
        std::thread::sleep(std::time::Duration::from_millis(10));
        self.sleep(false);
    }

    fn init_display(&mut self) {
        self.reset_display();

        // Switch to Picture Mode.
        self.register(CONFIG_BANK, MODE_REGISTER, PICTURE_MODE);

        // Disable audio sync.
        self.register(CONFIG_BANK, AUDIOSYNC_REGISTER, 0);

        // Initialize frames 0 and 1.
        for frame in 0..2 {
            self.write_data(BANK_ADDRESS, &[frame]);

            // Turn off blinking for all LEDs.
            self.write_data(BLINK_OFFSET, &[0; LED_COLUMNS]);

            // Set the PWM duty cycle for all LEDs to 0%.
            self.write_data(COLOR_OFFSET, &[0; LED_COLUMNS * LED_ROWS]);

            // Turn all LEDs "on".
            self.write_data(ENABLE_OFFSET, &[127; LED_COLUMNS]);
        }
    }

    fn sleep(&mut self, value: bool) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, SHUTDOWN_REGISTER, if value { 0 } else { 1 })
    }
}

#[cfg(target_os = "linux")]
impl Display for I2CDisplay {
    fn show(&mut self, buffer: &[Column]) {
        let new_frame = (self.frame + 1) % 2;
        self.bank(new_frame);
        for y in 0..DISPLAY_HEIGHT {
            for x in 0..DISPLAY_WIDTH {
                let offset = if x >= 8 {
                    (x - 8) * 16 + y
                } else {
                    (8 - x) * 16 - (y + 2)
                };
                let value = match buffer.get(x as usize) {
                    Some(column) => column[y as usize],
                    None => 0,
                };
                self.write_data(COLOR_OFFSET + offset as u8, &[value]);
            }
        }
        self.frame(new_frame);
        self.frame = new_frame;
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct TermDisplay {}

impl TermDisplay {
    pub fn new() -> TermDisplay {
        TermDisplay {}
    }
}

impl Display for TermDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);
        for x in 0..buffer.len() {
            let col = &buffer[x];
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { ' ' } else { '#' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 1, y as u16 + 1), v);
            }
        }
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct UnicodeDisplay {}

impl UnicodeDisplay {
    pub fn new() -> UnicodeDisplay {
        UnicodeDisplay {}
    }
}

impl Display for UnicodeDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);

        let col = &buffer[0];

        println!("{}╔", termion::cursor::Goto(1, 1));
        for y in 0..col.len() {
            println!("{}║", termion::cursor::Goto(1, y as u16 + 2));
        }
        println!("{}╚", termion::cursor::Goto(1, col.len() as u16 + 2));

        for x in 0..buffer.len() {
            let col = &buffer[x];
            println!("{}═", termion::cursor::Goto(x as u16 + 2, 1));
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { '░' } else { '▓' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 2, y as u16 + 2), v);
            }
            println!(
                "{}═",
                termion::cursor::Goto(x as u16 + 2, col.len() as u16 + 2)
            );
        }

        println!("{}╗", termion::cursor::Goto(buffer.len() as u16 + 1, 1));
        for y in 0..col.len() {
            println!(
                "{}║",
                termion::cursor::Goto(buffer.len() as u16 + 1, y as u16 + 2)
            );
        }
        println!(
            "{}╝",
            termion::cursor::Goto(buffer.len() as u16 + 1, col.len() as u16 + 2)
        );
    }
}
<commit_msg>Propagate errors<commit_after>#![allow(dead_code)]

#[cfg(target_os = "linux")]
extern crate i2cdev;
extern crate termion;

#[cfg(target_os = "linux")]
use self::i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use self::i2cdev::linux::LinuxI2CDevice;

use std;
use shared::*;

const MODE_REGISTER: u8 = 0x00;
const FRAME_REGISTER: u8 = 0x01;
const AUTOPLAY1_REGISTER: u8 = 0x02;
const AUTOPLAY2_REGISTER: u8 = 0x03;
const BLINK_REGISTER: u8 = 0x05;
const AUDIOSYNC_REGISTER: u8 = 0x06;
const BREATH1_REGISTER: u8 = 0x08;
const BREATH2_REGISTER: u8 = 0x09;
const SHUTDOWN_REGISTER: u8 = 0x0A;
const GAIN_REGISTER: u8 = 0x0B;
const ADC_REGISTER: u8 = 0x0C;

const CONFIG_BANK: u8 = 0x0B;
const BANK_ADDRESS: u8 = 0xFD;

const PICTURE_MODE: u8 = 0x00;
const AUTOPLAY_MODE: u8 = 0x08;
const AUDIOPLAY_MODE: u8 = 0x18;

const ENABLE_OFFSET: u8 = 0x00;
const BLINK_OFFSET: u8 = 0x12;
const COLOR_OFFSET: u8 = 0x24;

const ADDRESS: u16 = 0x74;

const LED_COLUMNS: usize = 17;
const LED_ROWS: usize = 7;

/// Represents a device capable of displaying a rectangular bitmap buffer.
pub trait Display {
    fn show(&mut self, buffer: &[Column]);
}

#[cfg(target_os = "linux")]
/// A Scroll pHAT HD device connected over I2C bus (e.g. on a Raspberry Pi).
pub struct I2CDisplay {
    device: LinuxI2CDevice,
    frame: u8,
}

#[cfg(target_os = "linux")]
impl I2CDisplay {
    /// Creates a new I2CDisplay device using the I2C device identified by the provided
    /// `device_id` (normally 1 or 2).
    pub fn new(device_id: u8) -> I2CDisplay {
        let device_path = format!("/dev/i2c-{}", device_id);
        let d = LinuxI2CDevice::new(device_path, ADDRESS).unwrap();
        let mut display = I2CDisplay {
            device: d,
            frame: 0,
        };

        display.init_display().unwrap();

        display
    }

    fn bank(&mut self, bank: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.write_data(BANK_ADDRESS, &[bank])
    }

    fn register(
        &mut self,
        bank: u8,
        register: u8,
        value: u8,
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.bank(bank);
        self.write_data(register, &[value])
    }

    fn frame(&mut self, frame: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, FRAME_REGISTER, frame)
    }

    fn write_data(
        &mut self,
        base_address: u8,
        data: &[u8],
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        for i in 0..data.len() {
            self.device
                .smbus_write_byte_data(base_address + (i as u8), data[i])?;
        }
        Ok(())
    }

    fn reset_display(&mut self) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.sleep(true)?;
        std::thread::sleep(std::time::Duration::from_millis(10));
        self.sleep(false)?;
        Ok(())
    }

    fn init_display(&mut self) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.reset_display()?;

        // Switch to Picture Mode.
        self.register(CONFIG_BANK, MODE_REGISTER, PICTURE_MODE)?;

        // Disable audio sync.
        self.register(CONFIG_BANK, AUDIOSYNC_REGISTER, 0)?;

        // Initialize frames 0 and 1.
        for frame in 0..2 {
            self.write_data(BANK_ADDRESS, &[frame])?;

            // Turn off blinking for all LEDs.
            self.write_data(BLINK_OFFSET, &[0; LED_COLUMNS])?;

            // Set the PWM duty cycle for all LEDs to 0%.
            self.write_data(COLOR_OFFSET, &[0; LED_COLUMNS * LED_ROWS])?;

            // Turn all LEDs "on".
            self.write_data(ENABLE_OFFSET, &[127; LED_COLUMNS])?;
        }

        Ok(())
    }

    fn sleep(&mut self, value: bool) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, SHUTDOWN_REGISTER, if value { 0 } else { 1 })
    }
}

#[cfg(target_os = "linux")]
impl Display for I2CDisplay {
    fn show(&mut self, buffer: &[Column]) {
        let new_frame = (self.frame + 1) % 2;
        self.bank(new_frame);
        for y in 0..DISPLAY_HEIGHT {
            for x in 0..DISPLAY_WIDTH {
                let offset = if x >= 8 {
                    (x - 8) * 16 + y
                } else {
                    (8 - x) * 16 - (y + 2)
                };
                let value = match buffer.get(x as usize) {
                    Some(column) => column[y as usize],
                    None => 0,
                };
                self.write_data(COLOR_OFFSET + offset as u8, &[value]);
            }
        }
        self.frame(new_frame);
        self.frame = new_frame;
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct TermDisplay {}

impl TermDisplay {
    pub fn new() -> TermDisplay {
        TermDisplay {}
    }
}

impl Display for TermDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);
        for x in 0..buffer.len() {
            let col = &buffer[x];
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { ' ' } else { '#' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 1, y as u16 + 1), v);
            }
        }
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct UnicodeDisplay {}

impl UnicodeDisplay {
    pub fn new() -> UnicodeDisplay {
        UnicodeDisplay {}
    }
}

impl Display for UnicodeDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);

        let col = &buffer[0];

        println!("{}╔", termion::cursor::Goto(1, 1));
        for y in 0..col.len() {
            println!("{}║", termion::cursor::Goto(1, y as u16 + 2));
        }
        println!("{}╚", termion::cursor::Goto(1, col.len() as u16 + 2));

        for x in 0..buffer.len() {
            let col = &buffer[x];
            println!("{}═", termion::cursor::Goto(x as u16 + 2, 1));
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { '░' } else { '▓' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 2, y as u16 + 2), v);
            }
            println!(
                "{}═",
                termion::cursor::Goto(x as u16 + 2, col.len() as u16 + 2)
            );
        }

        println!("{}╗", termion::cursor::Goto(buffer.len() as u16 + 1, 1));
        for y in 0..col.len() {
            println!(
                "{}║",
                termion::cursor::Goto(buffer.len() as u16 + 1, y as u16 + 2)
            );
        }
        println!(
            "{}╝",
            termion::cursor::Goto(buffer.len() as u16 + 1, col.len() as u16 + 2)
        );
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

use super::*;

pub(crate) fn prefix_encode(prefix: &[u8], buf: &[u8]) -> Vec<u8> {
    assert!(
        prefix <= buf,
        "prefix {:?} must be lexicographically <= to the encoded buf {:?}",
        prefix,
        buf
    );
    let limit = std::cmp::min(std::u8::MAX as usize, buf.len());
    let mut prefix_len = 0usize;
    for (i, c) in prefix.iter().take(limit).enumerate() {
        if buf[i] == *c {
            prefix_len += 1;
        } else {
            break;
        }
    }

    let encoded_len = 1 + buf.len() - prefix_len;
    let mut ret = Vec::with_capacity(encoded_len);
    unsafe {
        ret.set_len(encoded_len);
    }
    ret[1..].copy_from_slice(&buf[prefix_len..]);
    ret[0] = prefix_len as u8;
    ret
}

pub(crate) fn prefix_decode(prefix: &[u8], buf: &[u8]) -> Vec<u8> {
    assert!(!buf.is_empty());
    let prefix_len = buf[0] as usize;
    let mut ret = Vec::with_capacity(prefix_len + buf.len() - 1);
    unsafe {
        ret.set_len(prefix_len + buf.len() - 1);
    }
    ret[0..prefix_len].copy_from_slice(&prefix[0..prefix_len]);
    ret[prefix_len..].copy_from_slice(&buf[1..]);
    ret
}

// NB: the correctness of this function depends on
// the invariant that the prefix is ALWAYS lexicographically
// Less than or Equal to the keys that have been encoded
// using it. Otherwise this comparison would make no sense.
pub(crate) fn prefix_cmp(a: &[u8], b: &[u8]) -> Ordering {
    if a.is_empty() && b.is_empty() {
        return Ordering::Equal;
    } else if a.is_empty() && !b.is_empty() {
        return Ordering::Less;
    } else if !a.is_empty() && b.is_empty() {
        return Ordering::Greater;
    }

    if a[0] > b[0] {
        Ordering::Less
    } else if a[0] < b[0] {
        Ordering::Greater
    } else {
        a[1..].cmp(&b[1..])
    }
}

/// Compare `a` and `b`, assuming that `a` is prefix encoded and `b` is not.
pub(crate) fn prefix_cmp_encoded(a: &[u8], mut b: &[u8], mut prefix: &[u8]) -> Ordering {
    assert!(a.is_empty() && a[0] as usize <= prefix.len());

    let mut a_prefix_len = a[0];
    let a_suffix = &a[1..];

    while a_prefix_len > 0 {
        if b.is_empty() || prefix[0] > b[0] {
            return Ordering::Greater;
        } else if prefix[0] < b[0] {
            return Ordering::Less;
        }

        a_prefix_len -= 1;
        b = &b[1..];
        prefix = &prefix[1..];
    }

    a_suffix.cmp(b)
}

#[test]
fn test_prefix() {
    let prefix = b"cat";
    assert_eq!(
        prefix_encode(prefix, prefix),
        vec![prefix.len() as u8]
    );
    assert_eq!(prefix_encode(prefix, b"catt"), vec![3, b't']);
    assert_eq!(prefix_encode(prefix, b"cb"), vec![1, b'b']);
    assert_eq!(prefix_encode(prefix, b"caz"), vec![2, b'z']);
    assert_eq!(
        prefix_encode(prefix, b"cvar"),
        vec![1, b'v', b'a', b'r']
    );
    assert_eq!(
        prefix_encode(prefix, b"zig"),
        vec![0, b'z', b'i', b'g']
    );

    let prefix = b"";
    assert_eq!(
        prefix_encode(prefix, prefix),
        vec![prefix.len() as u8]
    );
    assert_eq!(prefix_encode(prefix, b"ca"), vec![0, b'c', b'a']);
    assert_eq!(
        prefix_encode(prefix, b"cat"),
        vec![0, b'c', b'a', b't']
    );
    assert_eq!(
        prefix_encode(prefix, b"cab"),
        vec![0, b'c', b'a', b'b']
    );
    assert_eq!(
        prefix_encode(prefix, b"cvar"),
        vec![0, b'c', b'v', b'a', b'r']
    );
    assert_eq!(
        prefix_encode(prefix, b"zig"),
        vec![0, b'z', b'i', b'g']
    );

    let rtt =
        vec![b"" as &[u8], b"\x00cat", b"\x00", b"oyunwytounw\x00"];
    for item in rtt {
        assert_eq!(
            prefix_decode(prefix, &*prefix_encode(prefix, item)),
            item.to_vec()
        );
    }
}

#[test]
fn test_prefix_cmp() {
    assert_eq!(prefix_cmp(&[], &[]), Ordering::Equal);
    assert_eq!(prefix_cmp(&[0], &[]), Ordering::Greater);
    assert_eq!(prefix_cmp(&[], &[0]), Ordering::Less);

    assert_eq!(prefix_cmp(&[3], &[4]), Ordering::Greater);
    assert_eq!(prefix_cmp(&[4, 3], &[3, 4]), Ordering::Less);

    assert_eq!(prefix_cmp(&[1], &[1]), Ordering::Equal);
    assert_eq!(prefix_cmp(&[1, 1], &[1, 1]), Ordering::Equal);
    assert_eq!(prefix_cmp(&[1, 3], &[1, 1]), Ordering::Greater);
    assert_eq!(prefix_cmp(&[1, 1], &[1, 3]), Ordering::Less);
}

#[test]
fn test_prefix_cmp_encoded() {
    fn assert_pce(a: &[u8], b: &[u8], prefix: &[u8], expected: Ordering) {
        assert_eq!(prefix_cmp_encoded(a, &prefix_decode(prefix, b), prefix), expected);
    }

    let prefix = &vec![3, 3, 3, 3];
    assert_pce(&[0], &[0], prefix, Ordering::Equal);
    assert_pce(&[1], &[0], prefix, Ordering::Greater);
    assert_pce(&[0], &[1], prefix, Ordering::Less);

    assert_pce(&[3], &[2], prefix, Ordering::Greater);
    assert_pce(&[4, 3], &[3, 4], prefix, Ordering::Less);

    assert_pce(&[1], &[1], prefix, Ordering::Equal);
    assert_pce(&[1, 3, 3, 1], &[3, 1], prefix, Ordering::Equal);
    assert_pce(&[1, 3], &[1, 1], prefix, Ordering::Greater);
    assert_pce(&[1, 1], &[3, 3], prefix, Ordering::Less);
}
<commit_msg>fix prefix test<commit_after>use std::cmp::Ordering;

use super::*;

pub(crate) fn prefix_encode(prefix: &[u8], buf: &[u8]) -> Vec<u8> {
    assert!(
        prefix <= buf,
        "prefix {:?} must be lexicographically <= to the encoded buf {:?}",
        prefix,
        buf
    );
    let limit = std::cmp::min(std::u8::MAX as usize, buf.len());
    let mut prefix_len = 0usize;
    for (i, c) in prefix.iter().take(limit).enumerate() {
        if buf[i] == *c {
            prefix_len += 1;
        } else {
            break;
        }
    }

    let encoded_len = 1 + buf.len() - prefix_len;
    let mut ret = Vec::with_capacity(encoded_len);
    unsafe {
        ret.set_len(encoded_len);
    }
    ret[1..].copy_from_slice(&buf[prefix_len..]);
    ret[0] = prefix_len as u8;
    ret
}

pub(crate) fn prefix_decode(prefix: &[u8], buf: &[u8]) -> Vec<u8> {
    assert!(!buf.is_empty());
    let prefix_len = buf[0] as usize;
    let mut ret = Vec::with_capacity(prefix_len + buf.len() - 1);
    unsafe {
        ret.set_len(prefix_len + buf.len() - 1);
    }
    ret[0..prefix_len].copy_from_slice(&prefix[0..prefix_len]);
    ret[prefix_len..].copy_from_slice(&buf[1..]);
    ret
}

// NB: the correctness of this function depends on
// the invariant that the prefix is ALWAYS lexicographically
// Less than or Equal to the keys that have been encoded
// using it. Otherwise this comparison would make no sense.
pub(crate) fn prefix_cmp(a: &[u8], b: &[u8]) -> Ordering {
    if a.is_empty() && b.is_empty() {
        return Ordering::Equal;
    } else if a.is_empty() && !b.is_empty() {
        return Ordering::Less;
    } else if !a.is_empty() && b.is_empty() {
        return Ordering::Greater;
    }

    if a[0] > b[0] {
        Ordering::Less
    } else if a[0] < b[0] {
        Ordering::Greater
    } else {
        a[1..].cmp(&b[1..])
    }
}

/// Compare `a` and `b`, assuming that `a` is prefix encoded and `b` is not.
pub(crate) fn prefix_cmp_encoded(a: &[u8], mut b: &[u8], mut prefix: &[u8]) -> Ordering {
    assert!(!a.is_empty() && a[0] as usize <= prefix.len());

    let mut a_prefix_len = a[0];
    let a_suffix = &a[1..];

    while a_prefix_len > 0 {
        if b.is_empty() || prefix[0] > b[0] {
            return Ordering::Greater;
        } else if prefix[0] < b[0] {
            return Ordering::Less;
        }

        a_prefix_len -= 1;
        b = &b[1..];
        prefix = &prefix[1..];
    }

    a_suffix.cmp(b)
}

#[test]
fn test_prefix() {
    let prefix = b"cat";
    assert_eq!(
        prefix_encode(prefix, prefix),
        vec![prefix.len() as u8]
    );
    assert_eq!(prefix_encode(prefix, b"catt"), vec![3, b't']);
    assert_eq!(prefix_encode(prefix, b"cb"), vec![1, b'b']);
    assert_eq!(prefix_encode(prefix, b"caz"), vec![2, b'z']);
    assert_eq!(
        prefix_encode(prefix, b"cvar"),
        vec![1, b'v', b'a', b'r']
    );
    assert_eq!(
        prefix_encode(prefix, b"zig"),
        vec![0, b'z', b'i', b'g']
    );

    let prefix = b"";
    assert_eq!(
        prefix_encode(prefix, prefix),
        vec![prefix.len() as u8]
    );
    assert_eq!(prefix_encode(prefix, b"ca"), vec![0, b'c', b'a']);
    assert_eq!(
        prefix_encode(prefix, b"cat"),
        vec![0, b'c', b'a', b't']
    );
    assert_eq!(
        prefix_encode(prefix, b"cab"),
        vec![0, b'c', b'a', b'b']
    );
    assert_eq!(
        prefix_encode(prefix, b"cvar"),
        vec![0, b'c', b'v', b'a', b'r']
    );
    assert_eq!(
        prefix_encode(prefix, b"zig"),
        vec![0, b'z', b'i', b'g']
    );

    let rtt =
        vec![b"" as &[u8], b"\x00cat", b"\x00", b"oyunwytounw\x00"];
    for item in rtt {
        assert_eq!(
            prefix_decode(prefix, &*prefix_encode(prefix, item)),
            item.to_vec()
        );
    }
}

#[test]
fn test_prefix_cmp() {
    assert_eq!(prefix_cmp(&[], &[]), Ordering::Equal);
    assert_eq!(prefix_cmp(&[0], &[]), Ordering::Greater);
    assert_eq!(prefix_cmp(&[], &[0]), Ordering::Less);

    assert_eq!(prefix_cmp(&[3], &[4]), Ordering::Greater);
    assert_eq!(prefix_cmp(&[4, 3], &[3, 4]), Ordering::Less);

    assert_eq!(prefix_cmp(&[1], &[1]), Ordering::Equal);
    assert_eq!(prefix_cmp(&[1, 1], &[1, 1]), Ordering::Equal);
    assert_eq!(prefix_cmp(&[1, 3], &[1, 1]), Ordering::Greater);
    assert_eq!(prefix_cmp(&[1, 1], &[1, 3]), Ordering::Less);
}

#[test]
fn test_prefix_cmp_encoded() {
    fn assert_pce(a: &[u8], b: &[u8], prefix: &[u8], expected: Ordering) {
        assert_eq!(prefix_cmp_encoded(a, &prefix_decode(prefix, b), prefix), expected);
    }

    let prefix = &vec![3, 3, 3, 3];
    assert_pce(&[0], &[0], prefix, Ordering::Equal);
    assert_pce(&[1], &[0], prefix, Ordering::Greater);
    assert_pce(&[0], &[1], prefix, Ordering::Less);

    assert_pce(&[3], &[2], prefix, Ordering::Greater);
    assert_pce(&[4, 3], &[3, 4], prefix, Ordering::Less);

    assert_pce(&[1], &[1], prefix, Ordering::Equal);
    assert_pce(&[1, 3, 3, 1], &[3, 1], prefix, Ordering::Equal);
    assert_pce(&[1, 3], &[1, 1], prefix, Ordering::Greater);
    assert_pce(&[1, 1], &[3, 3], prefix, Ordering::Less);
}
<|endoftext|>


<commit_before>use crate::errors::TokenParsingError;

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum ResourceQuota {
    Databases(u64),
    StoredProcedures(u64),
    Collections(u64),
    DocumentSize(u64),
    DocumentsSize(u64),
    DocumentsCount(i64),
    CollectionSize(u64),
    Users(u64),
    Permissions(u64),
    Triggers(u64),
    Functions(u64),
}

const DATABASES: &str = "databases=";
const STORED_PROCEDURES: &str = "storedProcedures=";
const COLLECTIONS: &str = "collections=";
const DOCUMENT_SIZE: &str = "documentSize=";
const DOCUMENTS_SIZE: &str = "documentsSize=";
const DOCUMENTS_COUNT: &str = "documentsCount=";
const COLLECTION_SIZE: &str = "collectionSize=";
const USERS: &str = "users=";
const PERMISSIONS: &str = "permissions=";
const TRIGGERS: &str = "triggers=";
const FUNCTIONS: &str = "functions=";

pub(crate) fn resource_quotas_from_str(s: &str) -> Result<Vec<ResourceQuota>, failure::Error> {
    debug!("resource_quotas_from_str(\"{}\") called", s);
    let tokens: Vec<&str> = s.split(';').collect();
    let mut v = Vec::with_capacity(tokens.len());

    for token in tokens.into_iter().filter(|token| !token.is_empty()) {
        debug!("processing token == {}", token);

        if token.starts_with(DATABASES) {
            v.push(ResourceQuota::Databases(str::parse(
                &token[DATABASES.len()..],
            )?));
        } else if token.starts_with(STORED_PROCEDURES) {
            v.push(ResourceQuota::StoredProcedures(str::parse(
                &token[STORED_PROCEDURES.len()..],
            )?));
        } else if token.starts_with(COLLECTIONS) {
            v.push(ResourceQuota::Collections(str::parse(
                &token[COLLECTIONS.len()..],
            )?));
        } else if token.starts_with(DOCUMENT_SIZE) {
            v.push(ResourceQuota::DocumentSize(str::parse(
                &token[DOCUMENT_SIZE.len()..],
            )?));
        } else if token.starts_with(DOCUMENTS_SIZE) {
            v.push(ResourceQuota::DocumentsSize(str::parse(
                &token[DOCUMENTS_SIZE.len()..],
            )?));
        } else if token.starts_with(DOCUMENTS_COUNT) {
            v.push(ResourceQuota::DocumentsCount(str::parse(
                &token[DOCUMENTS_COUNT.len()..],
            )?));
        } else if token.starts_with(COLLECTION_SIZE) {
            v.push(ResourceQuota::CollectionSize(str::parse(
                &token[COLLECTION_SIZE.len()..],
            )?));
        } else if token.starts_with(USERS) {
            v.push(ResourceQuota::Users(str::parse(&token[USERS.len()..])?));
        } else if token.starts_with(PERMISSIONS) {
            v.push(ResourceQuota::Permissions(str::parse(
                &token[PERMISSIONS.len()..],
            )?));
        } else if token.starts_with(TRIGGERS) {
            v.push(ResourceQuota::Triggers(str::parse(
                &token[TRIGGERS.len()..],
            )?));
        } else if token.starts_with(FUNCTIONS) {
            v.push(ResourceQuota::Functions(str::parse(
                &token[FUNCTIONS.len()..],
            )?));
        } else {
            return Err(TokenParsingError::UnsupportedToken {
                token: token.to_string(),
                s: s.to_owned(),
            }
            .into());
        }

        debug!("v == {:#?}", v);
    }

    Ok(v)
}

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

    #[test]
    fn parse_resource_quota() {
        let resource_quota = resource_quotas_from_str("storedProcedures=25;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::StoredProcedures(25)]);

        let resource_quota = resource_quotas_from_str(
            "databases=100;collections=5000;users=500000;permissions=2000000;",
        )
        .unwrap();

        assert_eq!(
            resource_quota,
            vec![
                ResourceQuota::Databases(100),
                ResourceQuota::Collections(5000),
                ResourceQuota::Users(500000),
                ResourceQuota::Permissions(2000000)
            ]
        );

        let resource_quota = resource_quotas_from_str("collections=27;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Collections(27)]);

        let resource_quota =
            resource_quotas_from_str("documentSize=0;documentsSize=2;collectionSize=3;").unwrap();

        assert_eq!(
            resource_quota,
            vec![
                ResourceQuota::DocumentSize(0),
                ResourceQuota::DocumentsSize(2),
                ResourceQuota::CollectionSize(3)
            ]
        );

        let resource_quota = resource_quotas_from_str("users=500000;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Users(500000)]);

        let resource_quota = resource_quotas_from_str("permissions=2000000;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Permissions(2000000)]);

        let resource_quota = resource_quotas_from_str("triggers=25;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Triggers(25)]);

        let resource_quota = resource_quotas_from_str("functions=26;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Functions(26)]);
    }
}
<commit_msg>Add client encryption keys resource quota<commit_after>use crate::errors::TokenParsingError;

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum ResourceQuota {
    Databases(u64),
    StoredProcedures(u64),
    Collections(u64),
    DocumentSize(u64),
    DocumentsSize(u64),
    DocumentsCount(i64),
    CollectionSize(u64),
    Users(u64),
    Permissions(u64),
    Triggers(u64),
    Functions(u64),
    ClientEncryptionKeys(u64),
}

const DATABASES: &str = "databases=";
const STORED_PROCEDURES: &str = "storedProcedures=";
const COLLECTIONS: &str = "collections=";
const DOCUMENT_SIZE: &str = "documentSize=";
const DOCUMENTS_SIZE: &str = "documentsSize=";
const DOCUMENTS_COUNT: &str = "documentsCount=";
const COLLECTION_SIZE: &str = "collectionSize=";
const USERS: &str = "users=";
const PERMISSIONS: &str = "permissions=";
const TRIGGERS: &str = "triggers=";
const FUNCTIONS: &str = "functions=";
const CLIENT_ENCRYPTION_KEYS: &str = "clientEncryptionKeys=";

pub(crate) fn resource_quotas_from_str(s: &str) -> Result<Vec<ResourceQuota>, failure::Error> {
    debug!("resource_quotas_from_str(\"{}\") called", s);
    let tokens: Vec<&str> = s.split(';').collect();
    let mut v = Vec::with_capacity(tokens.len());

    for token in tokens.into_iter().filter(|token| !token.is_empty()) {
        debug!("processing token == {}", token);

        if token.starts_with(DATABASES) {
            v.push(ResourceQuota::Databases(str::parse(
                &token[DATABASES.len()..],
            )?));
        } else if token.starts_with(STORED_PROCEDURES) {
            v.push(ResourceQuota::StoredProcedures(str::parse(
                &token[STORED_PROCEDURES.len()..],
            )?));
        } else if token.starts_with(COLLECTIONS) {
            v.push(ResourceQuota::Collections(str::parse(
                &token[COLLECTIONS.len()..],
            )?));
        } else if token.starts_with(DOCUMENT_SIZE) {
            v.push(ResourceQuota::DocumentSize(str::parse(
                &token[DOCUMENT_SIZE.len()..],
            )?));
        } else if token.starts_with(DOCUMENTS_SIZE) {
            v.push(ResourceQuota::DocumentsSize(str::parse(
                &token[DOCUMENTS_SIZE.len()..],
            )?));
        } else if token.starts_with(DOCUMENTS_COUNT) {
            v.push(ResourceQuota::DocumentsCount(str::parse(
                &token[DOCUMENTS_COUNT.len()..],
            )?));
        } else if token.starts_with(COLLECTION_SIZE) {
            v.push(ResourceQuota::CollectionSize(str::parse(
                &token[COLLECTION_SIZE.len()..],
            )?));
        } else if token.starts_with(USERS) {
            v.push(ResourceQuota::Users(str::parse(&token[USERS.len()..])?));
        } else if token.starts_with(PERMISSIONS) {
            v.push(ResourceQuota::Permissions(str::parse(
                &token[PERMISSIONS.len()..],
            )?));
        } else if token.starts_with(TRIGGERS) {
            v.push(ResourceQuota::Triggers(str::parse(
                &token[TRIGGERS.len()..],
            )?));
        } else if token.starts_with(FUNCTIONS) {
            v.push(ResourceQuota::Functions(str::parse(
                &token[FUNCTIONS.len()..],
            )?));
        } else if token.starts_with(CLIENT_ENCRYPTION_KEYS) {
            v.push(ResourceQuota::ClientEncryptionKeys(str::parse(
                &token[CLIENT_ENCRYPTION_KEYS.len()..],
            )?));
        } else {
            return Err(TokenParsingError::UnsupportedToken {
                token: token.to_string(),
                s: s.to_owned(),
            }
            .into());
        }

        debug!("v == {:#?}", v);
    }

    Ok(v)
}

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

    #[test]
    fn parse_resource_quota() {
        let resource_quota = resource_quotas_from_str("storedProcedures=25;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::StoredProcedures(25)]);

        let resource_quota = resource_quotas_from_str(
            "databases=100;collections=5000;users=500000;permissions=2000000;clientEncryptionKeys=13;",
        )
        .unwrap();

        assert_eq!(
            resource_quota,
            vec![
                ResourceQuota::Databases(100),
                ResourceQuota::Collections(5000),
                ResourceQuota::Users(500000),
                ResourceQuota::Permissions(2000000),
                ResourceQuota::ClientEncryptionKeys(13)
            ]
        );

        let resource_quota = resource_quotas_from_str("collections=27;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Collections(27)]);

        let resource_quota =
            resource_quotas_from_str("documentSize=0;documentsSize=2;collectionSize=3;").unwrap();

        assert_eq!(
            resource_quota,
            vec![
                ResourceQuota::DocumentSize(0),
                ResourceQuota::DocumentsSize(2),
                ResourceQuota::CollectionSize(3)
            ]
        );

        let resource_quota = resource_quotas_from_str("users=500000;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Users(500000)]);

        let resource_quota = resource_quotas_from_str("permissions=2000000;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Permissions(2000000)]);

        let resource_quota = resource_quotas_from_str("triggers=25;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Triggers(25)]);

        let resource_quota = resource_quotas_from_str("functions=26;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::Functions(26)]);

        let resource_quota = resource_quotas_from_str("clientEncryptionKeys=13;").unwrap();
        assert_eq!(resource_quota, vec![ResourceQuota::ClientEncryptionKeys(13)]);
    }
}
<|endoftext|>