<commit_before>//! Rust entry point
//!
//! Boot is split into two parts
//!
//! + Early boot where we walk hardware data structures and setup initial
//!   machine state before
//! + Late boot where we are operating in the final kernel window and can
//!   setup the initial user environment
//!
//! Early boot is extremely architecture specific, late boot is mostly
//! generic.

use plat::*;
use vspace::*;
use panic::*;
use ::config::BootConfig;
use ::core::fmt::Write;
use ::core::marker::PhantomData;
use ::core::default::Default;
use super::halt::halt;
use super::vspace::*;
extern crate multiboot;

/// Package of state that is passed to the early boot fun
struct EarlyBootState<'h, 'l> {
    high_window : &'h BootHighWindow<'h>,
    low_window : &'l BootLowWindow<'l>,
    mbi_magic: usize,
    mbi: *const usize,
}

struct PostEarlyBootState<'a> {
    plat: PlatInterfaceType,
    /* currently just PhantomData as don't have anything
     * to return with a lifetime */
    phantom: PhantomData<&'a usize>,
}

fn display_multiboot<'a>(plat: &mut PlatInterfaceType, mbi: &'a multiboot::Multiboot<'a>) {
    write!(plat, "Multiboot information:\n").unwrap();
    if let Some(low) = mbi.lower_memory_bound() {
        write!(plat,"\t{}kb of low memory\n", low).unwrap();
    }
    if let Some(high) = mbi.upper_memory_bound() {
        write!(plat,"\t{}mb of high memory\nn", high / 1024).unwrap();
    }
    if let Some(boot) = mbi.boot_device() {
        write!(plat,"\tBoot device {:?}\n", boot).unwrap();
    }
    if let Some(line) = mbi.command_line() {
        write!(plat,"\tCommand line \"{}\"\n", line).unwrap();
    }
    if let Some(modules) = mbi.modules() {
        write!(plat,"Multiboot modules:\n").unwrap();
        for m in modules {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
    if let Some(memory) = mbi.memory_regions() {
        write!(plat,"Memory regions:\n").unwrap();
        for m in memory {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
}

/* We create a wrapper struct because I don't know how else
 * to get the lifetime of the return value of callback function
 * to line up with the multiboot lifetime */
struct MbiWrapper<'a> {
    mbi: Option<multiboot::Multiboot<'a>>,
    callback: &'a Fn(u64, usize) -> Option<&'a [u8]>,
}

/* Try and boot the system, potentially returning an error.
 * Since if we fail there is no way to display or do anything
 * with the error we do do not bother to have an error type
 * This is specifically the 'early' boot as it happens before
 * we switch to the final kernel address space
 */
fn try_early_boot_system<'h, 'l>(init: EarlyBootState<'h, 'l>) -> Result<PostEarlyBootState<'h>, PlatInterfaceType> {
    /* Initial the serial output of our platform first so that
     * we can get debugging output. */
    let mut plat = unsafe {get_platform(&BootConfig)};
    plat.init_serial();
    write!(plat, "R4: In early setup\n").unwrap();
    /* Initialize the panic function so we can see anything
     * really bad that happens */
    panic_set_plat(&mut plat);
    /* Now we can continue with the rest of init */
    if init.mbi_magic as u64 != multiboot::SIGNATURE_RAX {
        write!(plat,"Invalid multiboot signature!\nExpected {} got {} with pointer {:?}\n", multiboot::SIGNATURE_RAX, init.mbi_magic, init.mbi).unwrap();
        return Err(plat);
    }
    let mut mbi = MbiWrapper{mbi: None, callback: &|p, s| unsafe {
        Some(init.low_window.make_slice(p as usize, s))
        }};
    unsafe {
        /* Thanks to the stupidy in this function interface of requiring
         * an unsafe function we cannot pass a lambda expression. Since
         * a lambda cannot be made unsafe and we have no other way of
         * passing our state we just transmute the lambda. Unfortunately
         * this removes all type checking on our function :( */
        mbi.mbi = match multiboot::Multiboot::new(init.mbi as multiboot::PAddr, mbi.callback) {
            Some(mbi) => Some(mbi),
            None => {
                write!(plat,"Failed to create multiboot!\n").unwrap();
                return Err(plat)
                }
            };
        if let &Some(ref mbi) = &mbi.mbi {
            display_multiboot(&mut plat, &mbi);
        }
    }
    Ok(PostEarlyBootState{ plat: plat, phantom: PhantomData })
}

/* Represent the multiboot info pointer as a pointer to
 * a usize for the moment. This will allow us to get the
 * lifetimes correct, and we will fill in the correct
 * type later */
#[no_mangle]
pub extern fn boot_system(magic: usize, mbi: *const usize) {
    /* This *will* be our final kernel window, but it is not our window
     * yet. We create it here so that our temporary high kernel window,
     * which is a subset of the final kernel window, can be constructed
     * from it as having the same lifetime. This allows any references
     * created from the boot high kernel window being able to live on
     * into the final kernel window */
    let final_window = unsafe{KernelWindow::default()};
    /* this variable will hold our system state as returned by early boot */
    let mut boot;
    {
        /* Construct our system state for boot */
        let boot_high_window;
        unsafe {
            boot_high_window = final_window.subwindow(BootHighWindow::default());
        }
        /* whilst doing early boot we can also access things in low memory */
        let boot_low_window = unsafe {BootLowWindow::default()};
        let boot_state = EarlyBootState {
            high_window: &boot_high_window,
            low_window: &boot_low_window,
            mbi_magic: magic,
            mbi: mbi,
        };
        boot = match try_early_boot_system(boot_state) {
            Err(mut plat) => {
                    write!(plat, "Failed early init. hlt'ing\n").unwrap();
                    halt();
                },
            Ok(b) => b,
        };
        /* The 'plat' definition got moved into boot. Reset the panic location */
        panic_set_plat(&mut boot.plat);
    }
    unimplemented!()
}
<commit_msg>more docs<commit_after>//! Rust entry point
//!
//! Boot is split into two parts
//!
//! + Early boot where we walk hardware data structures and setup initial
//!   machine state before
//! + Late boot where we are operating in the final kernel window and can
//!   setup the initial user environment
//!
//! Early boot is extremely architecture specific, late boot is mostly
//! generic.

use plat::*;
use vspace::*;
use panic::*;
use ::config::BootConfig;
use ::core::fmt::Write;
use ::core::marker::PhantomData;
use ::core::default::Default;
use super::halt::halt;
use super::vspace::*;
extern crate multiboot;

/// Package of state that is passed to the early boot function
struct EarlyBootState<'h, 'l> {
    /// Referenece to the high window. Objects created from here can
    /// persist forever, and as such references to them can be returned
    /// in `PostEarlyBootState`
    high_window : &'h BootHighWindow<'h>,
    /// Reference to the low window. References to objects from here
    /// cannot be returned in `PostEarlyBootState`
    low_window : &'l BootLowWindow<'l>,
    /// The value of EAX passed from the assembly entry. This is checked
    /// to ensure we were multiboot loaded
    mbi_magic: usize,
    /// Raw physical pointer that should point to the multiboot structure
    mbi: *const usize,
}

/// Package of state that is returned as a result of early boot
struct PostEarlyBootState<'a> {
    /// An initialized platform interface
    plat: PlatInterfaceType,
    /// Currently the lifetime 'a is unused, so have some `PhantomData` to get
    /// around that
    phantom: PhantomData<&'a usize>,
}

/// Debug function to print out the contents of the multiboot information
fn display_multiboot<'a>(plat: &mut PlatInterfaceType, mbi: &'a multiboot::Multiboot<'a>) {
    write!(plat, "Multiboot information:\n").unwrap();
    if let Some(low) = mbi.lower_memory_bound() {
        write!(plat,"\t{}kb of low memory\n", low).unwrap();
    }
    if let Some(high) = mbi.upper_memory_bound() {
        write!(plat,"\t{}mb of high memory\nn", high / 1024).unwrap();
    }
    if let Some(boot) = mbi.boot_device() {
        write!(plat,"\tBoot device {:?}\n", boot).unwrap();
    }
    if let Some(line) = mbi.command_line() {
        write!(plat,"\tCommand line \"{}\"\n", line).unwrap();
    }
    if let Some(modules) = mbi.modules() {
        write!(plat,"Multiboot modules:\n").unwrap();
        for m in modules {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
    if let Some(memory) = mbi.memory_regions() {
        write!(plat,"Memory regions:\n").unwrap();
        for m in memory {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
}

/// We create a wrapper struct because I don't know how else
/// to get the lifetime of the return value of callback function
/// to line up with the multiboot lifetime
struct MbiWrapper<'a> {
    mbi: Option<multiboot::Multiboot<'a>>,
    callback: &'a Fn(u64, usize) -> Option<&'a [u8]>,
}

/// Try and boot the system, potentially returning an error.
/// Since if we fail there is no way to display or do anything
/// with the error we do do not bother to have an error type
/// This is specifically the 'early' boot as it happens before
/// we switch to the final kernel address space
fn try_early_boot_system<'h, 'l>(init: EarlyBootState<'h, 'l>) -> Result<PostEarlyBootState<'h>, PlatInterfaceType> {
    /* Initial the serial output of our platform first so that
     * we can get debugging output. */
    let mut plat = unsafe {get_platform(&BootConfig)};
    plat.init_serial();
    write!(plat, "R4: In early setup\n").unwrap();
    /* Initialize the panic function so we can see anything
     * really bad that happens */
    panic_set_plat(&mut plat);
    /* Now we can continue with the rest of init */
    if init.mbi_magic as u64 != multiboot::SIGNATURE_RAX {
        write!(plat,"Invalid multiboot signature!\nExpected {} got {} with pointer {:?}\n", multiboot::SIGNATURE_RAX, init.mbi_magic, init.mbi).unwrap();
        return Err(plat);
    }
    let mut mbi = MbiWrapper{mbi: None, callback: &|p, s| unsafe {
        Some(init.low_window.make_slice(p as usize, s))
        }};
    unsafe {
        /* Thanks to the stupidy in this function interface of requiring
         * an unsafe function we cannot pass a lambda expression. Since
         * a lambda cannot be made unsafe and we have no other way of
         * passing our state we just transmute the lambda. Unfortunately
         * this removes all type checking on our function :( */
        mbi.mbi = match multiboot::Multiboot::new(init.mbi as multiboot::PAddr, mbi.callback) {
            Some(mbi) => Some(mbi),
            None => {
                write!(plat,"Failed to create multiboot!\n").unwrap();
                return Err(plat)
                }
            };
        if let &Some(ref mbi) = &mbi.mbi {
            display_multiboot(&mut plat, &mbi);
        }
    }
    Ok(PostEarlyBootState{ plat: plat, phantom: PhantomData })
}

/// Rust entry point for the kernel. This expects two parameters, one the
/// boot info magic, and the other a raw pointer to the boot info structure.
/// Additionally it expects that both the boot kernel windows are configured
/// correctly in the active address space root
#[no_mangle]
pub extern fn boot_system(magic: usize, mbi: *const usize) -> ! {
    /* This *will* be our final kernel window, but it is not our window
     * yet. We create it here so that our temporary high kernel window,
     * which is a subset of the final kernel window, can be constructed
     * from it as having the same lifetime. This allows any references
     * created from the boot high kernel window being able to live on
     * into the final kernel window */
    let final_window = unsafe{KernelWindow::default()};
    /* this variable will hold our system state as returned by early boot */
    let mut boot;
    {
        /* Construct our system state for boot */
        let boot_high_window;
        unsafe {
            boot_high_window = final_window.subwindow(BootHighWindow::default());
        }
        /* whilst doing early boot we can also access things in low memory */
        let boot_low_window = unsafe {BootLowWindow::default()};
        let boot_state = EarlyBootState {
            high_window: &boot_high_window,
            low_window: &boot_low_window,
            mbi_magic: magic,
            mbi: mbi,
        };
        boot = match try_early_boot_system(boot_state) {
            Err(mut plat) => {
                    write!(plat, "Failed early init. hlt'ing\n").unwrap();
                    halt();
                },
            Ok(b) => b,
        };
        /* The 'plat' definition got moved into boot. Reset the panic location */
        panic_set_plat(&mut boot.plat);
    }
    unimplemented!()
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use mouros_rust_bindings::mailbox;

#[allow(non_snake_case)]
pub mod BoardLed {
    pub const LED1: i32 = 0;
    pub const LED2: i32 = 1;
    pub const LED3: i32 = 2;
    pub const LED4: i32 = 3;
}

extern "C" {
    pub static mut bsp_rx_buffer: mailbox::Mailbox<u8>;
    pub static mut bsp_tx_buffer: mailbox::Mailbox<u8>;
}

extern "C" {
    fn bsp_led_get_state(led: i32) -> u8;
    fn bsp_led_on(led: i32);
    fn bsp_led_off(led: i32);
    fn bsp_led_toggle(led: i32);
}

pub fn led_get_state(led: i32) -> bool {
    unsafe { bsp_led_get_state(led) != 0 }
}

pub fn led_on(led: i32) {
    unsafe { bsp_led_on(led) }
}

pub fn led_off(led: i32) {
    unsafe { bsp_led_off(led) }
}

pub fn led_toggle(led: i32) {
    unsafe { bsp_led_toggle(led) }
}
<commit_msg>Removed RX and TX comm mailboxes from BSP<commit_after>#![allow(dead_code)]

use mouros_rust_bindings::mailbox;

#[allow(non_snake_case)]
pub mod BoardLed {
    pub const LED1: i32 = 0;
    pub const LED2: i32 = 1;
    pub const LED3: i32 = 2;
    pub const LED4: i32 = 3;
}

extern "C" {
    fn bsp_led_get_state(led: i32) -> u8;
    fn bsp_led_on(led: i32);
    fn bsp_led_off(led: i32);
    fn bsp_led_toggle(led: i32);
}

pub fn led_get_state(led: i32) -> bool {
    unsafe { bsp_led_get_state(led) != 0 }
}

pub fn led_on(led: i32) {
    unsafe { bsp_led_on(led) }
}

pub fn led_off(led: i32) {
    unsafe { bsp_led_off(led) }
}

pub fn led_toggle(led: i32) {
    unsafe { bsp_led_toggle(led) }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate glib;

use std::str::FromStr;

use self::glib::translate::*;

use error::*;
use length::*;
use parsers::ParseError;

pub enum RsvgPropertyBag {}

extern "C" {
    fn rsvg_property_bag_size (pbag: *const RsvgPropertyBag) -> libc::c_uint;
    fn rsvg_property_bag_lookup (pbag: *const RsvgPropertyBag, key: *const libc::c_char) -> *const libc::c_char;
    fn rsvg_property_bag_dup (pbag: *const RsvgPropertyBag) -> *mut RsvgPropertyBag;
    fn rsvg_property_bag_free (pbag: *mut RsvgPropertyBag);
}

pub fn get_size (pbag: *const RsvgPropertyBag) -> usize {
    unsafe { rsvg_property_bag_size (pbag) as usize }
}

pub fn lookup (pbag: *const RsvgPropertyBag, key: &str) -> Option<String> {
    unsafe {
        let c_value = rsvg_property_bag_lookup (pbag, key.to_glib_none ().0);
        from_glib_none (c_value)
    }
}

pub fn dup (pbag: *const RsvgPropertyBag) -> *mut RsvgPropertyBag {
    unsafe {
        rsvg_property_bag_dup (pbag)
    }
}

pub fn free (pbag: *mut RsvgPropertyBag) {
    unsafe {
        rsvg_property_bag_free (pbag);
    }
}

pub fn length_or_none (pbag: *const RsvgPropertyBag, key: &'static str, length_dir: LengthDir) -> Result <Option<RsvgLength>, NodeError> {
    let value = lookup (pbag, key);

    if let Some (v) = value {
        RsvgLength::parse (&v, length_dir).map (|l| Some (l))
            .map_err (|e| NodeError::attribute_error (key, e))
    } else {
        Ok (None)
    }
}

pub fn length_or_default (pbag: *const RsvgPropertyBag, key: &'static str, length_dir: LengthDir) -> Result <RsvgLength, NodeError> {
    let r = length_or_none (pbag, key, length_dir);

    match r {
        Ok (Some (v)) => Ok (v),
        Ok (None)     => Ok (RsvgLength::default ()),
        Err (e)       => Err (e)
    }
}

pub fn length_or_value (pbag: *const RsvgPropertyBag, key: &'static str, length_dir: LengthDir, length_str: &str) -> Result <RsvgLength, NodeError> {
    let r = length_or_none (pbag, key, length_dir);

    match r {
        Ok (Some (v)) => Ok (v),
        Ok (None)     => Ok (RsvgLength::parse (length_str, length_dir).unwrap ()),
        Err (e)       => Err (e)
    }
}

pub fn parse_or_none<T> (pbag: *const RsvgPropertyBag, key: &'static str) -> Result <Option<T>, NodeError>
    where T: Default + FromStr<Err = AttributeError>
{
    let value = lookup (pbag, key);

    match value {
        Some (v) => {
            T::from_str (&v).map (|v| Some (v))
                .map_err (|e| NodeError::attribute_error (key, e))
        },

        None => Ok (None)
    }
}

pub fn parse_or_default<T> (pbag: *const RsvgPropertyBag, key: &'static str) -> Result <T, NodeError>
    where T: Default + FromStr<Err = AttributeError>
{
    let r = parse_or_none::<T> (pbag, key);

    match r {
        Ok (Some (v)) => Ok (v),
        Ok (None)     => Ok (T::default ()),
        Err (e)       => Err (e)
    }
}

pub fn parse_or_value<T> (pbag: *const RsvgPropertyBag, key: &'static str, value: T) -> Result <T, NodeError>
    where T: Default + FromStr<Err = AttributeError> + Copy
{
    let r = parse_or_none::<T> (pbag, key);

    match r {
        Ok (Some (v)) => Ok (v),
        Ok (None)     => Ok (value),
        Err (e)       => Err (e)
    }
}
<commit_msg>property_bag.rs: Remove unused function<commit_after>extern crate libc;
extern crate glib;

use std::str::FromStr;

use self::glib::translate::*;

use error::*;
use length::*;
use parsers::ParseError;

pub enum RsvgPropertyBag {}

extern "C" {
    fn rsvg_property_bag_lookup (pbag: *const RsvgPropertyBag, key: *const libc::c_char) -> *const libc::c_char;
    fn rsvg_property_bag_dup (pbag: *const RsvgPropertyBag) -> *mut RsvgPropertyBag;
    fn rsvg_property_bag_free (pbag: *mut RsvgPropertyBag);
}

pub fn lookup (pbag: *const RsvgPropertyBag, key: &str) -> Option<String> {
    unsafe {
        let c_value = rsvg_property_bag_lookup (pbag, key.to_glib_none ().0);
        from_glib_none (c_value)
    }
}

pub fn dup (pbag: *const RsvgPropertyBag) -> *mut RsvgPropertyBag {
    unsafe {
        rsvg_property_bag_dup (pbag)
    }
}

pub fn free (pbag: *mut RsvgPropertyBag) {
    unsafe {
        rsvg_property_bag_free (pbag);
    }
}

pub fn length_or_none (pbag: *const RsvgPropertyBag, key: &'static str, length_dir: LengthDir) -> Result <Option<RsvgLength>, NodeError> {
    let value = lookup (pbag, key);

    if let Some (v) = value {
        RsvgLength::parse (&v, length_dir).map (|l| Some (l))
            .map_err (|e| NodeError::attribute_error (key, e))
    } else {
        Ok (None)
    }
}

pub fn length_or_default (pbag: *const RsvgPropertyBag, key: &'static str, length_dir: LengthDir) -> Result <RsvgLength, NodeError> {
    let r = length_or_none (pbag, key, length_dir);

    match r {
        Ok (Some (v)) => Ok (v),
        Ok (None)     => Ok (RsvgLength::default ()),
        Err (e)       => Err (e)
    }
}

pub fn length_or_value (pbag: *const RsvgPropertyBag, key: &'static str, length_dir: LengthDir, length_str: &str) -> Result <RsvgLength, NodeError> {
    let r = length_or_none (pbag, key, length_dir);

    match r {
        Ok (Some (v)) => Ok (v),
        Ok (None)     => Ok (RsvgLength::parse (length_str, length_dir).unwrap ()),
        Err (e)       => Err (e)
    }
}

pub fn parse_or_none<T> (pbag: *const RsvgPropertyBag, key: &'static str) -> Result <Option<T>, NodeError>
    where T: Default + FromStr<Err = AttributeError>
{
    let value = lookup (pbag, key);

    match value {
        Some (v) => {
            T::from_str (&v).map (|v| Some (v))
                .map_err (|e| NodeError::attribute_error (key, e))
        },

        None => Ok (None)
    }
}

pub fn parse_or_default<T> (pbag: *const RsvgPropertyBag, key: &'static str) -> Result <T, NodeError>
    where T: Default + FromStr<Err = AttributeError>
{
    let r = parse_or_none::<T> (pbag, key);

    match r {
        Ok (Some (v)) => Ok (v),
        Ok (None)     => Ok (T::default ()),
        Err (e)       => Err (e)
    }
}

pub fn parse_or_value<T> (pbag: *const RsvgPropertyBag, key: &'static str, value: T) -> Result <T, NodeError>
    where T: Default + FromStr<Err = AttributeError> + Copy
{
    let r = parse_or_none::<T> (pbag, key);

    match r {
        Ok (Some (v)) => Ok (v),
        Ok (None)     => Ok (value),
        Err (e)       => Err (e)
    }
}
<|endoftext|>


<commit_before>use fnv::FnvHashMap;

use lang::*;
use script::*;
use trigrams::*;
use info::Info;
use options::{Options, List};

const MAX_TRIGRAM_DISTANCE : u32 = 300;

// 300 * 300 = 90_000
const MAX_TOTAL_DISTANCE : u32 = 90_000;

/// Detect a language and a script by a given text.
///
/// # Example
/// ```
/// use whatlang::{detect, Lang, Script};
///
/// let info = detect("Ĉu vi ne volas eklerni Esperanton? Bonvolu!").unwrap();
/// assert_eq!(info.lang, Lang::Epo);
/// assert_eq!(info.script, Script::Latin);
/// ```
pub fn detect(text: &str) -> Option<Info> {
    detect_with_options(text, &Options::default())
}

/// Detect only a language by a given text.
///
/// # Example
/// ```
/// use whatlang::{detect_lang, Lang};
/// let lang = detect_lang("There is no reason not to learn Esperanto.").unwrap();
/// assert_eq!(lang, Lang::Eng);
/// ```
pub fn detect_lang(text: &str) -> Option<Lang> {
    detect(text).map(|info| info.lang)
}

pub fn detect_lang_with_options(text: &str, options: &Options) -> Option<Lang> {
    detect_with_options(text, options).map(|info| info.lang)
}

pub fn detect_with_options(text: &str, options: &Options) -> Option<Info> {
    if let Some(script) = detect_script(text) {
        detect_lang_based_on_script(text, options, script).map( |(lang, is_reliable)| {
            Info { lang, script, is_reliable }
        })
    } else {
        None
    }
}

fn detect_lang_based_on_script(text: &str, options: &Options, script : Script) -> Option<(Lang, bool)> {
    match script {
        Script::Latin      => detect_lang_in_profiles(text, options, LATIN_LANGS),
        Script::Cyrillic   => detect_lang_in_profiles(text, options, CYRILLIC_LANGS),
        Script::Devanagari => detect_lang_in_profiles(text, options, DEVANAGARI_LANGS),
        Script::Hebrew     => detect_lang_in_profiles(text, options, HEBREW_LANGS),
        Script::Ethiopic   => detect_lang_in_profiles(text, options, ETHIOPIC_LANGS),
        Script::Arabic     => detect_lang_in_profiles(text, options, ARABIC_LANGS),
        Script::Mandarin  => Some((Lang::Cmn, true)),
        Script::Bengali   => Some((Lang::Ben, true)),
        Script::Hangul    => Some((Lang::Kor, true)),
        Script::Georgian  => Some((Lang::Kat, true)),
        Script::Greek     => Some((Lang::Ell, true)),
        Script::Kannada   => Some((Lang::Kan, true)),
        Script::Tamil     => Some((Lang::Tam, true)),
        Script::Thai      => Some((Lang::Tha, true)),
        Script::Gujarati  => Some((Lang::Guj, true)),
        Script::Gurmukhi  => Some((Lang::Pan, true)),
        Script::Telugu    => Some((Lang::Tel, true)),
        Script::Malayalam => Some((Lang::Mal, true)),
        Script::Oriya     => Some((Lang::Ori, true)),
        Script::Myanmar   => Some((Lang::Mya, true)),
        Script::Sinhala   => Some((Lang::Sin, true)),
        Script::Khmer     => Some((Lang::Khm, true)),
        Script::Katakana | Script::Hiragana  => Some((Lang::Jpn, true))
    }
}

fn detect_lang_in_profiles(text: &str, options: &Options, lang_profile_list : LangProfileList) -> Option<(Lang, bool)> {
    let mut lang_distances : Vec<(Lang, u32)> = vec![];
    let trigrams = get_trigrams_with_positions(text);

    for &(ref lang, lang_trigrams) in lang_profile_list {
        match options.list {
            // Skip non-whitelisted languages
            Some(List::White(ref whitelist)) if !whitelist.contains(lang) => continue,
            // Skip blacklisted languages
            Some(List::Black(ref blacklist)) if blacklist.contains(lang) => continue,
            _ => {},
        }

        //match options {
        //    Options::Whitelist(whitelist) if !whitelist.contains(lang) => continue,
        //    Options::Blacklist(blacklist) if blacklist.contains(lang) => continue,
        //    _ => {},
        //}
        let dist = calculate_distance(lang_trigrams, &trigrams);
        lang_distances.push(((*lang), dist));
    }

    // Sort languages by distance
    lang_distances.sort_by_key(|key| key.1 );

    // Return None if lang_distances is empty
    // Return the only language with is_reliable=true if there is only 1 item
    if lang_distances.len() < 2 {
        return lang_distances.first().map(|pair| (pair.0, true));
    }

    // Calculate is_reliable based on:
    // - number of unique trigrams in the text
    // - rate (diff between score of the first and second languages)
    //
    // Threshold rate function is the following hyperbola:
    // y = (10 / x) + 0.03
    //
    let lang_dist1 = lang_distances[0];
    let lang_dist2 = lang_distances[1];
    let score1 = MAX_TOTAL_DISTANCE - lang_dist1.1;
    let score2 = MAX_TOTAL_DISTANCE - lang_dist2.1;
    let rate = (score1 - score2) as f64 / (score2 as f64);

    let min_reliable_rate = (10.0 / trigrams.len() as f64) + 0.03;
    let is_reliable = rate > min_reliable_rate;

    Some((lang_dist1.0, is_reliable))
}

fn calculate_distance(lang_trigrams: LangProfile,  text_trigrams: &FnvHashMap<String, u32>) -> u32 {
    let mut total_dist = 0u32;

    for (i, &trigram) in lang_trigrams.iter().enumerate() {
        let dist = match text_trigrams.get(trigram) {
            Some(&n) => (n as i32 - i as i32).abs() as u32,
            None => MAX_TRIGRAM_DISTANCE
        };
        total_dist += dist;
    }
    total_dist
}

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

    #[test]
    fn test_detect_spanish() {
        let text = "Además de todo lo anteriormente dicho, también encontramos...";
        let output = detect(text);
        assert_eq!(output.is_some(), true);

        let info = output.unwrap();
        assert_eq!(info.lang, Lang::Spa);
        assert_eq!(info.script, Script::Latin);
    }

    #[test]
    fn test_detect_lang_ukrainian() {
        let text = "Та нічого, все нормально. А в тебе як?";
        assert_eq!(detect_lang(text), Some(Lang::Ukr));
    }

    #[test]
    fn test_detect_with_options_with_blacklist() {
        let text = "I am begging pardon";
        // without blacklist
        let output = detect_with_options(text, &Options::default());
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang, Lang::Tgl);

        // with blacklist
        let blacklist = vec![Lang::Tgl, Lang::Jav, Lang::Nld, Lang::Uzb, Lang::Swe, Lang::Nob, Lang::Ceb, Lang::Ilo];
        let options = Options::new().set_blacklist(blacklist);
        let output = detect_with_options(text, &options);
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang, Lang::Eng);
    }

    #[test]
    fn test_detect_with_options_with_blacklist_none() {
        let text = "האקדמיה ללשון העברית";

        // All languages with Hebrew script are in blacklist, so result must be None
        let blacklist = vec![Lang::Heb, Lang::Ydd];
        let options = Options::new().set_blacklist(blacklist);
        let output = detect_with_options(text, &options);
        assert_eq!(output, None);
    }

    #[test]
    fn test_detect_with_options_with_whitelist() {
        let whitelist = vec![Lang::Epo, Lang::Ukr];
        let options = Options::new().set_whitelist(whitelist);

        let text = "Mi ne scias!";
        let output = detect_with_options(text, &options);
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang, Lang::Epo);
    }
}
<commit_msg>Cleanup detect.rs a little bit<commit_after>use fnv::FnvHashMap;

use lang::*;
use script::*;
use trigrams::*;
use info::Info;
use options::{Options, List};

const MAX_TRIGRAM_DISTANCE : u32 = 300;

// 300 * 300 = 90_000
const MAX_TOTAL_DISTANCE : u32 = 90_000;

/// Detect a language and a script by a given text.
///
/// # Example
/// ```
/// use whatlang::{detect, Lang, Script};
///
/// let info = detect("Ĉu vi ne volas eklerni Esperanton? Bonvolu!").unwrap();
/// assert_eq!(info.lang, Lang::Epo);
/// assert_eq!(info.script, Script::Latin);
/// ```
pub fn detect(text: &str) -> Option<Info> {
    detect_with_options(text, &Options::default())
}

/// Detect only a language by a given text.
///
/// # Example
/// ```
/// use whatlang::{detect_lang, Lang};
/// let lang = detect_lang("There is no reason not to learn Esperanto.").unwrap();
/// assert_eq!(lang, Lang::Eng);
/// ```
pub fn detect_lang(text: &str) -> Option<Lang> {
    detect(text).map(|info| info.lang)
}

pub fn detect_lang_with_options(text: &str, options: &Options) -> Option<Lang> {
    detect_with_options(text, options).map(|info| info.lang)
}

pub fn detect_with_options(text: &str, options: &Options) -> Option<Info> {
    detect_script(text).and_then(|script| {
        detect_lang_based_on_script(text, options, script).map( |(lang, is_reliable)| {
            Info { lang, script, is_reliable }
        })
    })
}

fn detect_lang_based_on_script(text: &str, options: &Options, script : Script) -> Option<(Lang, bool)> {
    match script {
        Script::Latin      => detect_lang_in_profiles(text, options, LATIN_LANGS),
        Script::Cyrillic   => detect_lang_in_profiles(text, options, CYRILLIC_LANGS),
        Script::Devanagari => detect_lang_in_profiles(text, options, DEVANAGARI_LANGS),
        Script::Hebrew     => detect_lang_in_profiles(text, options, HEBREW_LANGS),
        Script::Ethiopic   => detect_lang_in_profiles(text, options, ETHIOPIC_LANGS),
        Script::Arabic     => detect_lang_in_profiles(text, options, ARABIC_LANGS),
        Script::Mandarin  => Some((Lang::Cmn, true)),
        Script::Bengali   => Some((Lang::Ben, true)),
        Script::Hangul    => Some((Lang::Kor, true)),
        Script::Georgian  => Some((Lang::Kat, true)),
        Script::Greek     => Some((Lang::Ell, true)),
        Script::Kannada   => Some((Lang::Kan, true)),
        Script::Tamil     => Some((Lang::Tam, true)),
        Script::Thai      => Some((Lang::Tha, true)),
        Script::Gujarati  => Some((Lang::Guj, true)),
        Script::Gurmukhi  => Some((Lang::Pan, true)),
        Script::Telugu    => Some((Lang::Tel, true)),
        Script::Malayalam => Some((Lang::Mal, true)),
        Script::Oriya     => Some((Lang::Ori, true)),
        Script::Myanmar   => Some((Lang::Mya, true)),
        Script::Sinhala   => Some((Lang::Sin, true)),
        Script::Khmer     => Some((Lang::Khm, true)),
        Script::Katakana | Script::Hiragana  => Some((Lang::Jpn, true))
    }
}

fn detect_lang_in_profiles(text: &str, options: &Options, lang_profile_list : LangProfileList) -> Option<(Lang, bool)> {
    let mut lang_distances : Vec<(Lang, u32)> = vec![];
    let trigrams = get_trigrams_with_positions(text);

    for &(ref lang, lang_trigrams) in lang_profile_list {
        match options.list {
            // Skip non-whitelisted languages
            Some(List::White(ref whitelist)) if !whitelist.contains(lang) => continue,
            // Skip blacklisted languages
            Some(List::Black(ref blacklist)) if blacklist.contains(lang) => continue,
            _ => {},
        }
        let dist = calculate_distance(lang_trigrams, &trigrams);
        lang_distances.push(((*lang), dist));
    }

    // Sort languages by distance
    lang_distances.sort_by_key(|key| key.1 );

    // Return None if lang_distances is empty
    // Return the only language with is_reliable=true if there is only 1 item
    if lang_distances.len() < 2 {
        return lang_distances.first().map(|pair| (pair.0, true));
    }

    // Calculate is_reliable based on:
    // - number of unique trigrams in the text
    // - rate (diff between score of the first and second languages)
    //
    // Threshold rate function is the following hyperbola:
    // y = (10 / x) + 0.03
    //
    let lang_dist1 = lang_distances[0];
    let lang_dist2 = lang_distances[1];
    let score1 = MAX_TOTAL_DISTANCE - lang_dist1.1;
    let score2 = MAX_TOTAL_DISTANCE - lang_dist2.1;
    let rate = (score1 - score2) as f64 / (score2 as f64);

    let min_reliable_rate = (10.0 / trigrams.len() as f64) + 0.03;
    let is_reliable = rate > min_reliable_rate;

    Some((lang_dist1.0, is_reliable))
}

fn calculate_distance(lang_trigrams: LangProfile,  text_trigrams: &FnvHashMap<String, u32>) -> u32 {
    let mut total_dist = 0u32;

    for (i, &trigram) in lang_trigrams.iter().enumerate() {
        let dist = match text_trigrams.get(trigram) {
            Some(&n) => (n as i32 - i as i32).abs() as u32,
            None => MAX_TRIGRAM_DISTANCE
        };
        total_dist += dist;
    }
    total_dist
}

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

    #[test]
    fn test_detect_spanish() {
        let text = "Además de todo lo anteriormente dicho, también encontramos...";
        let output = detect(text);
        assert_eq!(output.is_some(), true);

        let info = output.unwrap();
        assert_eq!(info.lang, Lang::Spa);
        assert_eq!(info.script, Script::Latin);
    }

    #[test]
    fn test_detect_lang_ukrainian() {
        let text = "Та нічого, все нормально. А в тебе як?";
        assert_eq!(detect_lang(text), Some(Lang::Ukr));
    }

    #[test]
    fn test_detect_with_options_with_blacklist() {
        let text = "I am begging pardon";
        // without blacklist
        let output = detect_with_options(text, &Options::default());
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang, Lang::Tgl);

        // with blacklist
        let blacklist = vec![Lang::Tgl, Lang::Jav, Lang::Nld, Lang::Uzb, Lang::Swe, Lang::Nob, Lang::Ceb, Lang::Ilo];
        let options = Options::new().set_blacklist(blacklist);
        let output = detect_with_options(text, &options);
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang, Lang::Eng);
    }

    #[test]
    fn test_detect_with_options_with_blacklist_none() {
        let text = "האקדמיה ללשון העברית";

        // All languages with Hebrew script are in blacklist, so result must be None
        let blacklist = vec![Lang::Heb, Lang::Ydd];
        let options = Options::new().set_blacklist(blacklist);
        let output = detect_with_options(text, &options);
        assert_eq!(output, None);
    }

    #[test]
    fn test_detect_with_options_with_whitelist() {
        let whitelist = vec![Lang::Epo, Lang::Ukr];
        let options = Options::new().set_whitelist(whitelist);

        let text = "Mi ne scias!";
        let output = detect_with_options(text, &options);
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang, Lang::Epo);
    }
}
<|endoftext|>


<commit_before>//! Search engine: Where the fuzzy matching magic happens
//!
//! This task will collect all the input from STDIN and search over them on new queries.
//! Once a search is done all the results will be sent to the screen.

use crate::common::{Prompt, Result, Text, TextBuilder};
use crate::events::Event;
use crate::fuzzy;
use async_std::prelude::*;
use async_std::sync::{Receiver, Sender};
use async_std::task::{Context, Poll};
use futures_timer::Delay;
use std::collections::VecDeque;
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;

const BUFFER_LIMIT: usize = 5000;
const POOL_LIMIT: usize = 50000;

/// Run the search engine task
pub async fn task(input_recv: Receiver<Event>, output_sender: Sender<Event>) -> Result<()> {
    log::trace!("starting search engine");

    let mut pool: VecDeque<Text> = VecDeque::new();
    let mut count = 0;
    let mut query = String::from("");
    let mut incoming = debounce(input_recv);

    while let Some(event) = incoming.next().await {
        match event {
            Event::NewLine(s) => {
                log::trace!("line: {:?}", s);

                // Push the new line into the main pool
                pool.push_back(TextBuilder::build(&s));
                count += 1;

                // The pool might be full (too many lines in memory)
                // so we drop the first line
                if pool.len() > POOL_LIMIT {
                    log::trace!(
                        "pool limit ({:?}) exceeded, dropping first line",
                        POOL_LIMIT
                    );
                    let _f = pool.pop_front();
                }

                // We've got enough lines to refresh the search and send it
                // to the screen
                if count > BUFFER_LIMIT {
                    count = 0;
                    let matches = fuzzy::search(&query, &pool);
                    output_sender
                        .send(Event::Flush((matches, pool.len())))
                        .await;
                }
            }
            Event::EOF => {
                log::trace!("all input data done");
                let matches = fuzzy::search(&query, &pool);
                output_sender
                    .send(Event::Flush((matches, pool.len())))
                    .await;
            }
            Event::Search(prompt) => {
                query = prompt.as_string();
                log::trace!("performing new search: '{}'", query);

                let matches = fuzzy::search(&query, &pool);
                let results = Event::SearchDone((matches, pool.len(), prompt.timestamp()));

                output_sender.send(results).await;
            }
            Event::Done | Event::Exit => break,
            _ => (),
        };
    }

    log::trace!("search engine done");

    Ok(())
}

/// Sometimes we type two or three characters in the prompt very fast. In that case we don't expect
/// the program to search over each one of the characters but only over all of them.
/// This function tries to prevent that scenario where each character performs a search.
///
/// Whenever a new character is added to the search query, this stream awaits a little bit to see
/// if a new character arrives. If a character arrives before the time limit, it will added to the
/// search query ignoring the previous incomplete search request. Once the time limit ends the
/// final search query will be sent.
///
/// Note that given this is time based, and async, it's not exact and some intermediate search will
/// go through. It really depends on how fast you type. Let's say it's good enough.
fn debounce(stream: impl Stream<Item = Event> + Unpin) -> impl Stream<Item = Event> + Unpin {
    struct Debounce<S> {
        stream: S,
        delay: Delay,
        is_delayed: bool,
        last: Option<Prompt>,
    };

    impl<S: Stream<Item = Event> + Unpin> Stream for Debounce<S> {
        type Item = S::Item;

        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            // If we reached the time limit, try to send the accumulated search request
            if Pin::new(&mut self.delay).poll(cx).is_ready() {
                self.is_delayed = false;
                if let Some(prompt) = self.last.take() {
                    return Poll::Ready(Some(Event::Search(prompt)));
                }
            };

            match Pin::new(&mut self.stream).poll_next(cx) {
                Poll::Ready(Some(event)) => {
                    match event {
                        Event::Search(prompt) => {
                            self.last = Some(prompt);
                            if !self.is_delayed {
                                // Only reset the delay if it wasn't delayed
                                // before. If it was delayed (a new search query started)
                                // then wait for the delay to finish before resetting it
                                self.delay.reset(Duration::from_millis(150));
                                self.is_delayed = true;
                            }

                            // We have to return Ready if we want to collect all
                            // the events from the original stream
                            Poll::Ready(Some(Event::Ignore))
                        }
                        _ => Poll::Ready(Some(event)),
                    }
                }
                Poll::Ready(None) => Poll::Ready(None),
                Poll::Pending => Poll::Pending,
            }
        }
    }

    Debounce {
        stream,
        delay: Delay::new(Duration::from_secs(0)),
        is_delayed: false,
        last: Default::default(),
    }
}
<commit_msg>Remove debouncing from search engine<commit_after>//! Search engine: Where the fuzzy matching magic happens
//!
//! This task will collect all the input from STDIN and search over them on new queries.
//! Once a search is done all the results will be sent to the screen.

use crate::common::{Result, Text, TextBuilder};
use crate::events::Event;
use crate::fuzzy;
use async_std::prelude::*;
use async_std::sync::{Receiver, Sender};
use std::collections::VecDeque;

const BUFFER_LIMIT: usize = 5000;
const POOL_LIMIT: usize = 50000;

/// Run the search engine task
pub async fn task(mut input_recv: Receiver<Event>, output_sender: Sender<Event>) -> Result<()> {
    log::trace!("starting search engine");

    let mut pool: VecDeque<Text> = VecDeque::new();
    let mut count = 0;
    let mut query = String::from("");

    while let Some(event) = input_recv.next().await {
        match event {
            Event::NewLine(s) => {
                log::trace!("line: {:?}", s);

                // Push the new line into the main pool
                pool.push_back(TextBuilder::build(&s));
                count += 1;

                // The pool might be full (too many lines in memory)
                // so we drop the first line
                if pool.len() > POOL_LIMIT {
                    log::trace!(
                        "pool limit ({:?}) exceeded, dropping first line",
                        POOL_LIMIT
                    );
                    let _f = pool.pop_front();
                }

                // We've got enough lines to refresh the search and send it
                // to the screen
                if count > BUFFER_LIMIT {
                    count = 0;
                    let matches = fuzzy::search(&query, &pool);
                    output_sender
                        .send(Event::Flush((matches, pool.len())))
                        .await;
                }
            }
            Event::EOF => {
                log::trace!("all input data done");
                let matches = fuzzy::search(&query, &pool);
                output_sender
                    .send(Event::Flush((matches, pool.len())))
                    .await;
            }
            Event::Search(prompt) => {
                query = prompt.as_string();
                log::trace!("performing new search: '{}'", query);

                let matches = fuzzy::search(&query, &pool);
                let results = Event::SearchDone((matches, pool.len(), prompt.timestamp()));

                output_sender.send(results).await;
            }
            Event::Done | Event::Exit => break,
            _ => (),
        };
    }

    log::trace!("search engine done");

    Ok(())
}
<|endoftext|>


<commit_before>use std::iter::Peekable;

use ::opcodes::{AddressingMode, OpCode};
use assembler::token::{LexerToken, ParserToken};

#[derive(Debug, PartialEq)]
pub struct ParserError {
    pub message: String,
}

impl ParserError {
    fn expected_instruction(line: u32) -> ParserError {
        ParserError::from(format!("Instruction expected. Line {}", line))
    }

    fn invalid_opcode_addressing_mode_combination(line: u32) -> ParserError {
        ParserError::from(format!("Invalid addressing mode for opcode. Line {}", line))
    }

    fn unexpected_eol(line: u32) -> ParserError {
        ParserError::from(format!("Unexpected end of line. Line {}", line))
    }

    fn expected_eol(line: u32) -> ParserError {
        ParserError::from(format!("Expected end of line. Line {}", line))
    }

    fn cannot_parse_address(line: u32) -> ParserError {
        ParserError::from(format!("Unable to parse address. Line {}", line))
    }

    fn unexpected_token(line: u32) -> ParserError {
        ParserError::from(format!("Unexpected token. Line {}", line))
    }
}

impl From<String> for ParserError {
    fn from(error: String) -> ParserError {
        ParserError { message: error }
    }
}

impl<'a> From<&'a str> for ParserError {
    fn from(error: &str) -> ParserError {
        ParserError { message: error.into() }
    }
}

pub struct Parser {
    line: u32,
}

/// Parser processes a list of 6502 Assembly tokens
impl Parser {
    pub fn new() -> Parser {
        Parser { line: 0 }
    }

    pub fn parse(&mut self, tokens: Vec<Vec<LexerToken>>) -> Result<Vec<ParserToken>, ParserError> {
        let mut result = Vec::new();

        for line in &tokens {
            self.line += 1;

            let mut peeker = line.iter().peekable();

            // Skip blank lines
            if let None = peeker.peek() {
                continue;
            }

            let next = *peeker.peek().unwrap();

            if let &LexerToken::Ident(ref ident) = next {
                // Check if this is an opcode
                if Self::is_opcode(ident.clone()) {
                    // Yep its an opcode, lets figure out its addressing mode
                    peeker.next();
                    let mut opcode = self.consume_opcode(&mut peeker, ident.clone())?;
                    result.append(&mut opcode);
                } else {
                    // Skip the ident and we'll check what is next
                    let original_ident = peeker.next().unwrap();
                    // if there is nothing else - lets mark this as a Label and move on
                    if let None = peeker.peek() {
                        result.push(ParserToken::Label(ident.clone()));
                        continue;
                    }

                    // A colon after the ident also indicates a label
                    let next = *peeker.peek().unwrap();
                    if let &LexerToken::Colon = next {
                        result.push(ParserToken::Label(ident.clone()));
                        continue;
                    }

                    // Is the next one a label as well? Thats an error:
                    if let &LexerToken::Ident(ref ident) = next {
                        // Lets add the original as a label
                        if let &LexerToken::Ident(ref original_ident) = original_ident {
                            result.push(ParserToken::Label(original_ident.clone()));
                        }

                        if !Self::is_opcode(ident.clone()) {
                            return Err(ParserError::expected_instruction(self.line));
                        } else {
                            // Oh it is an opcode after the label - consume it
                            let mut opcode = self.consume_opcode(&mut peeker, ident.clone())?;
                            result.append(&mut opcode);
                        }
                    }
                }
            }
        }

        Ok(result)
    }

    fn is_opcode<S>(mnemonic: S) -> bool
        where S: Into<String>
    {
        if let Some(opcode) = OpCode::from_mnemonic(mnemonic) {
            true
        } else {
            false
        }
    }

    fn consume_opcode<'a, I, S>(&mut self,
                                mut peeker: &mut Peekable<I>,
                                ident: S)
                                -> Result<Vec<ParserToken>, ParserError>
        where I: Iterator<Item = &'a LexerToken>,
              S: Into<String>
    {
        // If there is nothing else after this opcode.. lets check if there is
        // a matching opcode with an implied addressing mode
        if let None = peeker.peek() {
            if let Some(opcode) =
                   OpCode::from_mnemonic_and_addressing_mode(ident, AddressingMode::Implied) {
                return Ok(vec![ParserToken::OpCode(opcode)]);
            } else {
                return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
            }
        } else {
            // TODO: Complete this
            // Jump over the opcode
            peeker.next();

            // Check the next token, is it an address?
            let next = *peeker.peek().unwrap();
            if let &LexerToken::Address(ref address) = next {
                // Its an address. What sort of address?
                if address.len() == 2 || address.len() == 4 {
                    // Its zero-page or absolute.. lets try and convert it to a raw byte
                    let (bytes, addressing_mode) = if address.len() == 2 {
                        // Its a 1 byte address
                        if let Ok(raw_byte) = u8::from_str_radix(&address[..], 16) {
                            (vec![raw_byte], AddressingMode::ZeroPage)
                        } else {
                            return Err(ParserError::cannot_parse_address(self.line));
                        }
                    } else {
                        // Its a 2 byte address
                        if let Ok(low_byte) = u8::from_str_radix(&address[2..], 16) {
                            if let Ok(high_byte) = u8::from_str_radix(&address[0..2], 16) {
                                (vec![low_byte, high_byte], AddressingMode::Absolute)
                            } else {
                                return Err(ParserError::cannot_parse_address(self.line));
                            }
                        } else {
                            return Err(ParserError::cannot_parse_address(self.line));
                        }
                    };
                    // consume the address and peek what is next:
                    peeker.next();
                    if let None = peeker.peek() {
                        // Nothing else.. find an opcode with this ident and addressing mode
                        if let Some(opcode) =
                               OpCode::from_mnemonic_and_addressing_mode(ident, addressing_mode) {
                            // We found one..
                            let mut final_vec = vec![ParserToken::OpCode(opcode)];
                            // Push the address bytes into the result
                            for b in bytes {
                                final_vec.push(ParserToken::RawByte(b));
                            }
                            return Ok(final_vec);
                        } else {
                            return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
                        }
                    }

                    // There is something after this zero page address - if its
                    // a comma, then we're peachy. If its something else.. Thats
                    // an error.
                    let next = *peeker.peek().unwrap();
                    if let &LexerToken::Comma = next {
                        // Yes, its a comma. Consume it and check what is next
                        peeker.next();
                        // If theres nothing after the comma thats an error
                        if let None = peeker.peek() {
                            return Err(ParserError::unexpected_eol(self.line));
                        }

                        let next = *peeker.peek().unwrap();
                        if let &LexerToken::Ident(ref register) = next {
                            let register = register.to_uppercase();
                            if register != "X" && register != "Y" {
                                return Err(ParserError::unexpected_token(self.line));
                            }
                            let addressing_mode = if register == "X" {
                                if addressing_mode == AddressingMode::ZeroPage {
                                    AddressingMode::ZeroPageX
                                } else {
                                    AddressingMode::AbsoluteX
                                }
                            } else {
                                if addressing_mode == AddressingMode::ZeroPage {
                                    AddressingMode::ZeroPageY
                                } else {
                                    AddressingMode::AbsoluteY
                                }
                            };
                            if let Some(opcode) =
                                   OpCode::from_mnemonic_and_addressing_mode(ident, addressing_mode) {
                                // We found one..
                                let mut final_vec = vec![ParserToken::OpCode(opcode)];
                                // Push the address bytes into the result
                                for b in bytes {
                                    final_vec.push(ParserToken::RawByte(b));
                                }
                            } else {
                                return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
                            }
                        } else {
                            return Err(ParserError::unexpected_token(self.line));
                        }
                    } else {
                        return Err(ParserError::unexpected_token(self.line));
                    }
                    let next = *peeker.peek().unwrap();

                } else {
                    return Err(ParserError::cannot_parse_address(self.line));
                }
            }
            Ok(vec![ParserToken::Label("BLAH".into())])
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ::assembler::token::{ImmediateBase, LexerToken, ParserToken};
    use ::opcodes::{AddressingMode, OpCode};

    #[test]
    fn can_parse_labels_via_lonely_label() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into())],
                          vec![LexerToken::Ident("START".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()), ParserToken::Label("START".into())],
                   &result[..]);
    }

    #[test]
    fn can_parse_labels_via_colon_terminator() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into())], vec![LexerToken::Colon]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into())], &result[..]);
    }

    #[test]
    fn can_parse_opcodes_after_labels_on_one_line() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("LDA".into()),
                               LexerToken::Address("4400".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()),
                     ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("LDA", AddressingMode::Absolute).unwrap()),
                     ParserToken::RawByte(0),
                     ParserToken::RawByte(68)],
                   &result[..]);
    }

    #[test]
    fn can_detect_double_labels_on_one_line() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("START".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens);

        assert_eq!(Err(ParserError::expected_instruction(1)), result);
    }

    #[test]
    fn can_detect_opcode_with_implied_addressing_mode() {
        let tokens = vec![vec![LexerToken::Ident("CLC".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("CLC", AddressingMode::Implied).unwrap())], &result[..]);
    }
}<commit_msg>Add a test for AbsoluteX addressing<commit_after>use std::iter::Peekable;

use ::opcodes::{AddressingMode, OpCode};
use assembler::token::{LexerToken, ParserToken};

#[derive(Debug, PartialEq)]
pub struct ParserError {
    pub message: String,
}

impl ParserError {
    fn expected_instruction(line: u32) -> ParserError {
        ParserError::from(format!("Instruction expected. Line {}", line))
    }

    fn invalid_opcode_addressing_mode_combination(line: u32) -> ParserError {
        ParserError::from(format!("Invalid addressing mode for opcode. Line {}", line))
    }

    fn unexpected_eol(line: u32) -> ParserError {
        ParserError::from(format!("Unexpected end of line. Line {}", line))
    }

    fn expected_eol(line: u32) -> ParserError {
        ParserError::from(format!("Expected end of line. Line {}", line))
    }

    fn cannot_parse_address(line: u32) -> ParserError {
        ParserError::from(format!("Unable to parse address. Line {}", line))
    }

    fn unexpected_token(line: u32) -> ParserError {
        ParserError::from(format!("Unexpected token. Line {}", line))
    }
}

impl From<String> for ParserError {
    fn from(error: String) -> ParserError {
        ParserError { message: error }
    }
}

impl<'a> From<&'a str> for ParserError {
    fn from(error: &str) -> ParserError {
        ParserError { message: error.into() }
    }
}

pub struct Parser {
    line: u32,
}

/// Parser processes a list of 6502 Assembly tokens
impl Parser {
    pub fn new() -> Parser {
        Parser { line: 0 }
    }

    pub fn parse(&mut self, tokens: Vec<Vec<LexerToken>>) -> Result<Vec<ParserToken>, ParserError> {
        let mut result = Vec::new();

        for line in &tokens {
            self.line += 1;

            let mut peeker = line.iter().peekable();

            // Skip blank lines
            if let None = peeker.peek() {
                continue;
            }

            let next = *peeker.peek().unwrap();

            if let &LexerToken::Ident(ref ident) = next {
                // Check if this is an opcode
                if Self::is_opcode(ident.clone()) {
                    // Yep its an opcode, lets figure out its addressing mode
                    peeker.next();
                    let mut opcode = self.consume_opcode(&mut peeker, ident.clone())?;
                    result.append(&mut opcode);
                } else {
                    // Skip the ident and we'll check what is next
                    let original_ident = peeker.next().unwrap();
                    // if there is nothing else - lets mark this as a Label and move on
                    if let None = peeker.peek() {
                        result.push(ParserToken::Label(ident.clone()));
                        continue;
                    }

                    // A colon after the ident also indicates a label
                    let next = *peeker.peek().unwrap();
                    if let &LexerToken::Colon = next {
                        result.push(ParserToken::Label(ident.clone()));
                        continue;
                    }

                    // Is the next one a label as well? Thats an error:
                    if let &LexerToken::Ident(ref ident) = next {
                        // Lets add the original as a label
                        if let &LexerToken::Ident(ref original_ident) = original_ident {
                            result.push(ParserToken::Label(original_ident.clone()));
                        }

                        if !Self::is_opcode(ident.clone()) {
                            return Err(ParserError::expected_instruction(self.line));
                        } else {
                            // Oh it is an opcode after the label - consume it
                            let mut opcode = self.consume_opcode(&mut peeker, ident.clone())?;
                            result.append(&mut opcode);
                        }
                    }
                }
            }
        }

        Ok(result)
    }

    fn is_opcode<S>(mnemonic: S) -> bool
        where S: Into<String>
    {
        if let Some(opcode) = OpCode::from_mnemonic(mnemonic) {
            true
        } else {
            false
        }
    }

    fn consume_opcode<'a, I, S>(&mut self,
                                mut peeker: &mut Peekable<I>,
                                ident: S)
                                -> Result<Vec<ParserToken>, ParserError>
        where I: Iterator<Item = &'a LexerToken>,
              S: Into<String>
    {
        // If there is nothing else after this opcode.. lets check if there is
        // a matching opcode with an implied addressing mode
        if let None = peeker.peek() {
            if let Some(opcode) =
                   OpCode::from_mnemonic_and_addressing_mode(ident, AddressingMode::Implied) {
                return Ok(vec![ParserToken::OpCode(opcode)]);
            } else {
                return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
            }
        } else {
            // TODO: Complete this
            // Jump over the opcode
            peeker.next();

            // Check the next token, is it an address?
            let next = *peeker.peek().unwrap();
            if let &LexerToken::Address(ref address) = next {
                // Its an address. What sort of address?
                if address.len() == 2 || address.len() == 4 {
                    // Its zero-page or absolute.. lets try and convert it to a raw byte
                    let (bytes, addressing_mode) = if address.len() == 2 {
                        // Its a 1 byte address
                        if let Ok(raw_byte) = u8::from_str_radix(&address[..], 16) {
                            (vec![raw_byte], AddressingMode::ZeroPage)
                        } else {
                            return Err(ParserError::cannot_parse_address(self.line));
                        }
                    } else {
                        // Its a 2 byte address
                        if let Ok(low_byte) = u8::from_str_radix(&address[2..], 16) {
                            if let Ok(high_byte) = u8::from_str_radix(&address[0..2], 16) {
                                (vec![low_byte, high_byte], AddressingMode::Absolute)
                            } else {
                                return Err(ParserError::cannot_parse_address(self.line));
                            }
                        } else {
                            return Err(ParserError::cannot_parse_address(self.line));
                        }
                    };
                    // consume the address and peek what is next:
                    peeker.next();
                    if let None = peeker.peek() {
                        // Nothing else.. find an opcode with this ident and addressing mode
                        if let Some(opcode) =
                               OpCode::from_mnemonic_and_addressing_mode(ident, addressing_mode) {
                            // We found one..
                            let mut final_vec = vec![ParserToken::OpCode(opcode)];
                            // Push the address bytes into the result
                            for b in bytes {
                                final_vec.push(ParserToken::RawByte(b));
                            }
                            return Ok(final_vec);
                        } else {
                            return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
                        }
                    }

                    // There is something after this address - if its
                    // a comma, then we're peachy. If its something else.. Thats
                    // an error.
                    let next = *peeker.peek().unwrap();
                    if let &LexerToken::Comma = next {
                        // Yes, its a comma. Consume it and check what is next
                        peeker.next();
                        // If theres nothing after the comma thats an error
                        if let None = peeker.peek() {
                            return Err(ParserError::unexpected_eol(self.line));
                        }

                        let next = *peeker.peek().unwrap();
                        if let &LexerToken::Ident(ref register) = next {
                            let register = register.to_uppercase();
                            if register != "X" && register != "Y" {
                                return Err(ParserError::unexpected_token(self.line));
                            }
                            let addressing_mode = if register == "X" {
                                if addressing_mode == AddressingMode::ZeroPage {
                                    AddressingMode::ZeroPageX
                                } else {
                                    AddressingMode::AbsoluteX
                                }
                            } else {
                                if addressing_mode == AddressingMode::ZeroPage {
                                    AddressingMode::ZeroPageY
                                } else {
                                    AddressingMode::AbsoluteY
                                }
                            };
                            if let Some(opcode) =
                                   OpCode::from_mnemonic_and_addressing_mode(ident, addressing_mode) {
                                // We found one..
                                let mut final_vec = vec![ParserToken::OpCode(opcode)];
                                // Push the address bytes into the result
                                for b in bytes {
                                    final_vec.push(ParserToken::RawByte(b));
                                }
                                return Ok(final_vec);
                            } else {
                                return Err(ParserError::invalid_opcode_addressing_mode_combination(self.line));
                            }
                        } else {
                            return Err(ParserError::unexpected_token(self.line));
                        }
                    } else {
                        return Err(ParserError::unexpected_token(self.line));
                    }
                    let next = *peeker.peek().unwrap();

                } else {
                    return Err(ParserError::cannot_parse_address(self.line));
                }
            }
            Ok(vec![ParserToken::Label("BLAH".into())])
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ::assembler::token::{ImmediateBase, LexerToken, ParserToken};
    use ::opcodes::{AddressingMode, OpCode};

    #[test]
    fn can_parse_labels_via_lonely_label() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into())],
                          vec![LexerToken::Ident("START".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()), ParserToken::Label("START".into())],
                   &result[..]);
    }

    #[test]
    fn can_parse_labels_via_colon_terminator() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into())], vec![LexerToken::Colon]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into())], &result[..]);
    }

    #[test]
    fn can_parse_opcodes_after_labels_on_one_line() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("LDA".into()),
                               LexerToken::Address("4400".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()),
                     ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("LDA", AddressingMode::Absolute).unwrap()),
                     ParserToken::RawByte(0),
                     ParserToken::RawByte(68)],
                   &result[..]);
    }

    #[test]
    fn can_detect_double_labels_on_one_line() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("START".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens);

        assert_eq!(Err(ParserError::expected_instruction(1)), result);
    }

    #[test]
    fn can_detect_opcode_with_implied_addressing_mode() {
        let tokens = vec![vec![LexerToken::Ident("CLC".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("CLC", AddressingMode::Implied).unwrap())], &result[..]);
    }

    #[test]
    fn can_detect_opcode_with_correct_absolute_x_addressing_mode() {
        let tokens = vec![vec![LexerToken::Ident("MAIN".into()),
                               LexerToken::Ident("LDA".into()),
                               LexerToken::Address("4400".into()),
                               LexerToken::Comma,
                               LexerToken::Ident("X".into())]];

        let mut parser = Parser::new();
        let result = parser.parse(tokens).unwrap();

        assert_eq!(&[ParserToken::Label("MAIN".into()),
                     ParserToken::OpCode(OpCode::from_mnemonic_and_addressing_mode("LDA", AddressingMode::AbsoluteX).unwrap()),
                     ParserToken::RawByte(0),
                     ParserToken::RawByte(68)],
                   &result[..]);
    }
}<|endoftext|>


<commit_before>use hyper;
use std::convert::From;
use serde_json;
use std::num::ParseIntError;

impl From<::json::Error> for HueError {
    fn from(e: ::json::Error) -> HueError {
        HueErrorKind::BridgeError {
            address:e.address,
            description:e.description,
            error:From::from(e.code)
        }.into()
    }
}

error_chain! {

    types {
        HueError, HueErrorKind, ResultExt, Result;
    }

    errors {
        /// this does not happen in practice
        MalformedResponse { }
        /// An error that occured in the bridge
        BridgeError { address:String, description:String, error:BridgeError} {
            description("bridge error")
            display("Bridge error: {} {} {:?}", address, description, error)
        }
    }

    foreign_links {
        JsonError(serde_json::Error);
        HyperError(hyper::Error);
        ParseIntError(ParseIntError);
    }

}

macro_rules! error_enum {
    (
        $(#[$meta:meta])*
        pub enum $name:ident{
            $($err:ident = $n:expr),+;
            $other:ident
        }
    ) => (
        $(#[$meta])*
        pub enum $name{
            $($err = $n,)+
            $other
        }
        impl From<u16> for $name{
            fn from(n: u16) -> Self{
                match n {
                    $($n => $name::$err,)+
                    _ => $name::$other
                }
            }
        }
    );
}

error_enum!{
    /// All errors defined in http://www.developers.meethue.com/documentation/error-messages
    #[repr(u16)]
    #[allow(missing_docs)]
    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    pub enum BridgeError {
        // Generic Errors
        UnauthorizedUser = 1,
        BodyContainsInvalidJson = 2,
        ResourceNotAvailable = 3,
        MethodNotAvailableForResource = 4,
        MissingParametersInBody = 5,
        ParameterNotAvailable = 6,
        InvalidValueForParameter = 7,
        ParameterIsNotModifiable = 8,
        TooManyItemsInList = 11,
        ProtalConnectionRequired = 12,
        InternalError = 901,

        // Command Specific Errors
        LinkButtonNotPressed = 101,
        DHCPCannotBeDisabled = 110,
        InvalidUpdateState = 111,
        DeviceIsSetToOff = 201,
        GroupCouldNotBeCreatedGroupFull = 301,
        DeviceCouldNotBeAddedGroupFull = 302,
        DeviceIsUnreachable = 304,
        UpdateOrDeleteGroupOfThisTypeNotAllowed = 305,
        LightAlreadyUsed = 306,
        SceneCouldNotBeCreated = 401,
        SceneCouldNotBeCreatedBufferFull = 402,
        SceneCouldNotBeRemoved = 403,
        NotAllowedToCreateSensorType = 501,
        SensorListIsFull = 502,
        RuleEngineFull = 601,
        ConditionError = 607,
        ActionError = 608,
        UnableToActivae = 609,
        ScheduleListIsFull = 701,
        ScheduleTimezoneNotValid = 702,
        ScheduleCannotSetTimeAndLocalTime = 703,
        CannotCreateSchedule = 704,
        CannotEnableScheduleTimeInPast = 705,
        CommandError = 706,
        SourceModelInvalid = 801,
        SourceFactoryNew = 802,
        InvalidState = 803;
        Other
    }
}

#[test]
fn bridge_errors() {
    use self::BridgeError::*;

    assert_eq!(BridgeError::from(101), LinkButtonNotPressed);
    assert_eq!(BridgeError::from(0), Other);
    assert_eq!(BridgeError::from(51234), Other);
    assert_eq!(BridgeError::from(4), MethodNotAvailableForResource);
    assert_eq!(SceneCouldNotBeRemoved as u16, 403);
    assert_eq!(InternalError as u16, 901);
}
<commit_msg>clean up display of bridge error<commit_after>use hyper;
use std::convert::From;
use serde_json;
use std::num::ParseIntError;

impl From<::json::Error> for HueError {
    fn from(e: ::json::Error) -> HueError {
        HueErrorKind::BridgeError {
            address:e.address,
            description:e.description,
            error:From::from(e.code)
        }.into()
    }
}

error_chain! {

    types {
        HueError, HueErrorKind, ResultExt, Result;
    }

    errors {
        /// this does not happen in practice
        MalformedResponse { }
        /// An error that occured in the bridge
        BridgeError { address:String, description:String, error:BridgeError} {
            description("bridge error")
            display("Bridge error: {:?} address: {} description: {}", error, address, description)
        }
    }

    foreign_links {
        JsonError(serde_json::Error);
        HyperError(hyper::Error);
        ParseIntError(ParseIntError);
    }

}

macro_rules! error_enum {
    (
        $(#[$meta:meta])*
        pub enum $name:ident{
            $($err:ident = $n:expr),+;
            $other:ident
        }
    ) => (
        $(#[$meta])*
        pub enum $name{
            $($err = $n,)+
            $other
        }
        impl From<u16> for $name{
            fn from(n: u16) -> Self{
                match n {
                    $($n => $name::$err,)+
                    _ => $name::$other
                }
            }
        }
    );
}

error_enum!{
    /// All errors defined in http://www.developers.meethue.com/documentation/error-messages
    #[repr(u16)]
    #[allow(missing_docs)]
    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
    pub enum BridgeError {
        // Generic Errors
        UnauthorizedUser = 1,
        BodyContainsInvalidJson = 2,
        ResourceNotAvailable = 3,
        MethodNotAvailableForResource = 4,
        MissingParametersInBody = 5,
        ParameterNotAvailable = 6,
        InvalidValueForParameter = 7,
        ParameterIsNotModifiable = 8,
        TooManyItemsInList = 11,
        ProtalConnectionRequired = 12,
        InternalError = 901,

        // Command Specific Errors
        LinkButtonNotPressed = 101,
        DHCPCannotBeDisabled = 110,
        InvalidUpdateState = 111,
        DeviceIsSetToOff = 201,
        GroupCouldNotBeCreatedGroupFull = 301,
        DeviceCouldNotBeAddedGroupFull = 302,
        DeviceIsUnreachable = 304,
        UpdateOrDeleteGroupOfThisTypeNotAllowed = 305,
        LightAlreadyUsed = 306,
        SceneCouldNotBeCreated = 401,
        SceneCouldNotBeCreatedBufferFull = 402,
        SceneCouldNotBeRemoved = 403,
        NotAllowedToCreateSensorType = 501,
        SensorListIsFull = 502,
        RuleEngineFull = 601,
        ConditionError = 607,
        ActionError = 608,
        UnableToActivae = 609,
        ScheduleListIsFull = 701,
        ScheduleTimezoneNotValid = 702,
        ScheduleCannotSetTimeAndLocalTime = 703,
        CannotCreateSchedule = 704,
        CannotEnableScheduleTimeInPast = 705,
        CommandError = 706,
        SourceModelInvalid = 801,
        SourceFactoryNew = 802,
        InvalidState = 803;
        Other
    }
}

#[test]
fn bridge_errors() {
    use self::BridgeError::*;

    assert_eq!(BridgeError::from(101), LinkButtonNotPressed);
    assert_eq!(BridgeError::from(0), Other);
    assert_eq!(BridgeError::from(51234), Other);
    assert_eq!(BridgeError::from(4), MethodNotAvailableForResource);
    assert_eq!(SceneCouldNotBeRemoved as u16, 403);
    assert_eq!(InternalError as u16, 901);
}
<|endoftext|>


<commit_before>use bincode;
use std;
use std::path::PathBuf;

static ISSUE_TEMPLATE: &'static str = r#"
=> If this is a bug please file an issue at: https://git.io/v96U6"#;

error_chain! {
    errors {
        BookmarkNotFound(name: String) {
            description("Bookmark not found.")
            display("The bookmark \"{}\" was not found", name)
        }

        DBOpenError(path: PathBuf) {
            description("Failed to open database.")
            display("Failed to open db file: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        DBCloseError(path: PathBuf) {
            description("Failed to close database.")
            display("Failed to close db file: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        ResolveError(path: PathBuf) {
            description("Failed to resolve path.")
            display("Failed to resolve {:?}.{}", path, ISSUE_TEMPLATE)
        }

        PathDoesNotExistError(path: PathBuf) {
            description("Path does not exist.")
            display("Path does not exist {:?}.{}", path, ISSUE_TEMPLATE)
        }

        CurrentDirectoryError(path: PathBuf) {
            description("Failed to derive current directory.")
            display("Failed to get current dir when resolving {:?}.{}", path, ISSUE_TEMPLATE)
        }

        ConfigError {
            description("Unable to derive config")
            display("{}", ISSUE_TEMPLATE)
        }

        BasenameError(path: PathBuf) {
            description("Failed to derive basename")
            display("Could not derive basename from {:?}.{}", path, ISSUE_TEMPLATE)
        }

        CreateDirError(path: PathBuf) {
            description("Failed to create dir")
            display("Failed to create {:?}.{}", path, ISSUE_TEMPLATE)
        }
    }

    foreign_links {
        IOError(std::io::Error) #[doc = "Error during IO"];
        BincodeError(std::boxed::Box<bincode::ErrorKind>);
    }
}

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

    #[test]
    fn bookmark_not_found() {
        let name = String::from("nope");
        let err = ErrorKind::BookmarkNotFound(name);
        assert_eq!(err.description(), "Bookmark not found.");
        assert_eq!(err.to_string(), "The bookmark \"nope\" was not found");
    }

    #[test]
    fn database_open_failure() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::DBOpenError(path);
        assert_eq!(err.description(), "Failed to open database.");
        assert_eq!(err.to_string(), format!("Failed to open db file: {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }

    #[test]
    fn database_close_failure() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::DBCloseError(path);
        assert_eq!(err.description(), "Failed to close database.");
        assert_eq!(err.to_string(), format!("Failed to close db file: {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }
}
<commit_msg>Adds more error tests.<commit_after>use bincode;
use std;
use std::path::PathBuf;

static ISSUE_TEMPLATE: &'static str = r#"
=> If this is a bug please file an issue at: https://git.io/v96U6"#;

error_chain! {
    errors {
        BookmarkNotFound(name: String) {
            description("Bookmark not found.")
            display("The bookmark \"{}\" was not found", name)
        }

        DBOpenError(path: PathBuf) {
            description("Failed to open database.")
            display("Failed to open db file: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        DBCloseError(path: PathBuf) {
            description("Failed to close database.")
            display("Failed to close db file: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        ResolveError(path: PathBuf) {
            description("Failed to resolve path.")
            display("Failed to resolve: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        PathDoesNotExistError(path: PathBuf) {
            description("Path does not exist.")
            display("Path does not exist: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        CurrentDirectoryError(path: PathBuf) {
            description("Failed to derive current directory.")
            display("Failed to get current dir when resolving: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        ConfigError {
            description("Unable to derive config")
            display("{}", ISSUE_TEMPLATE)
        }

        BasenameError(path: PathBuf) {
            description("Failed to derive basename")
            display("Could not derive basename from: {:?}.{}", path, ISSUE_TEMPLATE)
        }

        CreateDirError(path: PathBuf) {
            description("Failed to create dir")
            display("Failed to create {:?}.{}", path, ISSUE_TEMPLATE)
        }
    }

    foreign_links {
        IOError(std::io::Error) #[doc = "Error during IO"];
        BincodeError(std::boxed::Box<bincode::ErrorKind>);
    }
}

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

    #[test]
    fn bookmark_not_found() {
        let name = String::from("nope");
        let err = ErrorKind::BookmarkNotFound(name);
        assert_eq!(err.description(), "Bookmark not found.");
        assert_eq!(err.to_string(), "The bookmark \"nope\" was not found");
    }

    #[test]
    fn database_open_failure() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::DBOpenError(path);
        assert_eq!(err.description(), "Failed to open database.");
        assert_eq!(err.to_string(), format!("Failed to open db file: {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }

    #[test]
    fn database_close_failure() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::DBCloseError(path);
        assert_eq!(err.description(), "Failed to close database.");
        assert_eq!(err.to_string(), format!("Failed to close db file: {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }

    #[test]
    fn path_resolve_error() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::ResolveError(path);
        assert_eq!(err.description(), "Failed to resolve path.");
        assert_eq!(err.to_string(), format!("Failed to resolve: {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }

    #[test]
    fn path_does_not_exist_error() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::PathDoesNotExistError(path);
        assert_eq!(err.description(), "Path does not exist.");
        assert_eq!(err.to_string(), format!("Path does not exist: {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }

    #[test]
    fn cwd_error() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::CurrentDirectoryError(path);
        assert_eq!(err.description(), "Failed to derive current directory.");
        assert_eq!(err.to_string(), format!("Failed to get current dir when resolving: {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }

    #[test]
    fn config_error() {
        let err = ErrorKind::ConfigError;
        assert_eq!(err.description(), "Unable to derive config");
        assert_eq!(err.to_string(), format!("{}", ISSUE_TEMPLATE));
    }

    #[test]
    fn basename_error() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::BasenameError(path);
        assert_eq!(err.description(), "Failed to derive basename");
        assert_eq!(err.to_string(), format!("Could not derive basename from: {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }

    #[test]
    fn create_dir_error() {
        let path = PathBuf::from("nope");
        let err = ErrorKind::CreateDirError(path);
        assert_eq!(err.description(), "Failed to create dir");
        assert_eq!(err.to_string(), format!("Failed to create {:?}.{}", PathBuf::from("nope"), ISSUE_TEMPLATE));
    }
}
<|endoftext|>


<commit_before>//! Error module
//! y u do this???
//!
//! This should make errors useable! Yay!
use std::fmt;
use std::error::Error as StdError;

use interface::*;

#[derive(Debug)]
pub enum MemError {
    TooBig { given: Addr, max: Addr },
    TooSmall { given: Addr, min: Addr },
    InvalidAddr { addr: Addr },
    ReadOnly { at: Addr, globally: bool },
    WriteOnly { at: Addr, globally: bool },
    UnalignedAccess { at: Addr, alignment: Addr },
    NoData { at: Addr },
    InvalidData { at: Addr },
    HardwareFault { at: Addr, reason: String },
    Uninitialized { at: Addr },
    NotApplicable { at: Addr },
    NotImplemented,
}

impl fmt::Display for MemError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MemError::TooBig { given, max } => {
                write!(f, "MemoryBlock Error: {:#X} is too big, {:#X} is the maximum", given, max)
            }
            MemError::TooSmall { given, min } => {
                write!(f, "MemoryBlock Error: {:#X} is too small, {:#X} is the minimum", given, min)
            }
            MemError::InvalidAddr { addr } => {
                write!(f, "MemoryBlock Error: Invalid address: {:#X}", addr)
            }
            MemError::ReadOnly { at, globally: g } => {
                let errtext = if g {
                    "Globally read only"
                } else {
                    "Section read only"
                };
                write!(f, "MemoryBlock Error: {} @ {:#X} ", errtext, at)
            }
            MemError::WriteOnly { at, globally: g } => {
                let errtext = if g {
                    "Globally write only"
                } else {
                    "Section write only"
                };
                write!(f, "MemoryBlock Error: {} @ {:#X} ", errtext, at)
            }
            MemError::UnalignedAccess { at, alignment: a } => {
                write!(f, "MemoryBlock Error: {:#X}: Unaligned access, needs {} byte alignment", at, a)
            }
            MemError::NoData { at } => write!(f, "MemoryBlock Error: {:#X}: No data", at),
            MemError::InvalidData { at } => write!(f, "MemoryBlock Error: {:#X}: Invalid data", at),
            MemError::HardwareFault { at, ref reason } => {
                write!(f, "MemoryBlock Error: Hardware fault occured @ {:#X}: {}", at, reason)
            }
            MemError::Uninitialized { at } => {
                write!(f, "MemoryBlock Error: {:#X} is uninitialized", at)
            }
            MemError::NotImplemented => {
                write!(f, "MemoryBlock Error: not implemented")
            }
            MemError::NotApplicable { at } => {
                write!(f, "MemoryBlock Error: action not applicable @ {:#X}", at)
            }
        }
    }
}

impl StdError for MemError {
    fn description(&self) -> &str {
        match *self {
            MemError::TooBig { given: _, max: _ } => "too big",
            MemError::TooSmall { given: _, min: _ } => "too small",
            MemError::InvalidAddr { addr: _ } => "invalid address",
            MemError::ReadOnly { at: _, globally: _ } => "memory read only",
            MemError::WriteOnly { at: _, globally: _ } => "memory write only",
            MemError::UnalignedAccess { at: _, alignment: _ } => "unaligned access to memory",
            MemError::NoData { at: _ } => "no data",
            MemError::InvalidData { at: _ } => "invalid data",
            MemError::HardwareFault { at: _, reason: _ } => "hardware fault",
            MemError::Uninitialized { at: _ } => "uninitialized",
            MemError::NotImplemented => "not implemented",
            MemError::NotApplicable { at: _ } => "not applicable",
        }
    }
}
<commit_msg>Woops, wrong string.<commit_after>//! Error module
//! y u do this???
//!
//! This should make errors useable! Yay!
use std::fmt;
use std::error::Error as StdError;

use interface::*;

#[derive(Debug)]
pub enum MemError {
    TooBig { given: Addr, max: Addr },
    TooSmall { given: Addr, min: Addr },
    InvalidAddr { addr: Addr },
    ReadOnly { at: Addr, globally: bool },
    WriteOnly { at: Addr, globally: bool },
    UnalignedAccess { at: Addr, alignment: Addr },
    NoData { at: Addr },
    InvalidData { at: Addr },
    HardwareFault { at: Addr, reason: &'static str },
    Uninitialized { at: Addr },
    NotApplicable { at: Addr },
    NotImplemented,
}

impl fmt::Display for MemError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MemError::TooBig { given, max } => {
                write!(f, "MemoryBlock Error: {:#X} is too big, {:#X} is the maximum", given, max)
            }
            MemError::TooSmall { given, min } => {
                write!(f, "MemoryBlock Error: {:#X} is too small, {:#X} is the minimum", given, min)
            }
            MemError::InvalidAddr { addr } => {
                write!(f, "MemoryBlock Error: Invalid address: {:#X}", addr)
            }
            MemError::ReadOnly { at, globally: g } => {
                let errtext = if g {
                    "Globally read only"
                } else {
                    "Section read only"
                };
                write!(f, "MemoryBlock Error: {} @ {:#X} ", errtext, at)
            }
            MemError::WriteOnly { at, globally: g } => {
                let errtext = if g {
                    "Globally write only"
                } else {
                    "Section write only"
                };
                write!(f, "MemoryBlock Error: {} @ {:#X} ", errtext, at)
            }
            MemError::UnalignedAccess { at, alignment: a } => {
                write!(f, "MemoryBlock Error: {:#X}: Unaligned access, needs {} byte alignment", at, a)
            }
            MemError::NoData { at } => write!(f, "MemoryBlock Error: {:#X}: No data", at),
            MemError::InvalidData { at } => write!(f, "MemoryBlock Error: {:#X}: Invalid data", at),
            MemError::HardwareFault { at, ref reason } => {
                write!(f, "MemoryBlock Error: Hardware fault occured @ {:#X}: {}", at, reason)
            }
            MemError::Uninitialized { at } => {
                write!(f, "MemoryBlock Error: {:#X} is uninitialized", at)
            }
            MemError::NotImplemented => {
                write!(f, "MemoryBlock Error: not implemented")
            }
            MemError::NotApplicable { at } => {
                write!(f, "MemoryBlock Error: action not applicable @ {:#X}", at)
            }
        }
    }
}

impl StdError for MemError {
    fn description(&self) -> &str {
        match *self {
            MemError::TooBig { given: _, max: _ } => "too big",
            MemError::TooSmall { given: _, min: _ } => "too small",
            MemError::InvalidAddr { addr: _ } => "invalid address",
            MemError::ReadOnly { at: _, globally: _ } => "memory read only",
            MemError::WriteOnly { at: _, globally: _ } => "memory write only",
            MemError::UnalignedAccess { at: _, alignment: _ } => "unaligned access to memory",
            MemError::NoData { at: _ } => "no data",
            MemError::InvalidData { at: _ } => "invalid data",
            MemError::HardwareFault { at: _, reason: _ } => "hardware fault",
            MemError::Uninitialized { at: _ } => "uninitialized",
            MemError::NotImplemented => "not implemented",
            MemError::NotApplicable { at: _ } => "not applicable",
        }
    }
}
<|endoftext|>


<commit_before>
use common::{parse_args, FileReader};
use std::collections::HashSet;

const USAGE: &str = "
Usage:
  breakfast filter [options] <sv_path>

Options:
  --min-reads=N     Minimum number of supporting reads [default: 0]
  --blacklist=PATH  File containing blacklisted breakpoint signatures
";

pub fn main() {
	let args = parse_args(USAGE);
	let sv_path = args.get_str("<sv_path>");
	let min_reads: usize = args.get_str("--min-reads").parse().unwrap();
	let blacklist_path = args.get_str("--blacklist");

	let mut line = String::new();

	let mut blacklist = HashSet::new();
	if !blacklist_path.is_empty() {
		let mut bl = FileReader::new(&blacklist_path);
		while bl.read_line(&mut line) { blacklist.insert(line.clone()); }
	}

	let mut sv_file = FileReader::new(&sv_path);

	// Print the header
	sv_file.read_line(&mut line);
	print!("{}", line);

	while sv_file.read_line(&mut line) {
		let num_reads = line.split('\t').nth(8).unwrap().split(';').count();
		if num_reads < min_reads { continue; }

		let signature = line.split('\t').nth(9).unwrap();
		if blacklist.contains(signature) { continue; }

		println!("{}", line);
	}
}
<commit_msg>Fixed a bug in blacklist filtering.<commit_after>
use common::{parse_args, FileReader};
use std::collections::HashSet;

const USAGE: &str = "
Usage:
  breakfast filter [options] <sv_path>

Options:
  --min-reads=N     Minimum number of supporting reads [default: 0]
  --blacklist=PATH  File containing blacklisted breakpoint signatures
";

pub fn main() {
	let args = parse_args(USAGE);
	let sv_path = args.get_str("<sv_path>");
	let min_reads: usize = args.get_str("--min-reads").parse().unwrap();
	let blacklist_path = args.get_str("--blacklist");

	let mut line = String::new();

	let mut blacklist = HashSet::new();
	if !blacklist_path.is_empty() {
		let mut bl = FileReader::new(&blacklist_path);
		while bl.read_line(&mut line) {
			blacklist.insert(line.trim().to_string());
		}
	}

	let mut sv_file = FileReader::new(&sv_path);

	// Print the header
	sv_file.read_line(&mut line);
	print!("{}", line);

	while sv_file.read_line(&mut line) {
		let num_reads = line.split('\t').nth(8).unwrap().split(';').count();
		if num_reads < min_reads { continue; }

		let signature = line.split('\t').nth(9).unwrap();
		if blacklist.contains(signature) { continue; }

		println!("{}", line);
	}
}
<|endoftext|>