<commit_before>extern crate env_logger;
extern crate nix;
extern crate regex;
extern crate termion;
extern crate unicode_width;
#[macro_use]
extern crate log;
extern crate clap;

#[macro_use]
extern crate lazy_static;
mod ansi;
mod curses;
mod event;
mod field;
mod input;
mod item;
mod matcher;
mod model;
mod options;
mod orderedvec;
mod output;
mod query;
mod reader;
mod score;
mod sender;
mod util;
mod previewer;

use curses::Curses;
use event::Event::*;
use event::{EventReceiver, EventSender};
use item::Item;
use nix::libc;
use nix::sys::signal::{pthread_sigmask, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal};
pub use options::SkimOptions;
pub use output::SkimOutput;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::sync::mpsc::{channel, sync_channel, Receiver, Sender};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

const REFRESH_DURATION: u64 = 200;

pub struct Skim {}

extern "C" fn handle_sigwiwnch(_: i32) {}

impl Skim {
    pub fn run_with(options: &SkimOptions, source: Option<Box<BufRead + Send>>) -> Option<SkimOutput> {
        let (tx_input, rx_input): (EventSender, EventReceiver) = channel();
        //------------------------------------------------------------------------------
        // register terminal resize event, `pthread_sigmask` should be run before any thread.

        let mut sigset = SigSet::empty();
        sigset.add(Signal::SIGWINCH);
        let _ = pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(&sigset), None);

        // SIGWINCH is ignored by mac by default, thus we need to register an empty handler
        let action = SigAction::new(SigHandler::Handler(handle_sigwiwnch), SaFlags::empty(), SigSet::empty());
        unsafe {
            let _ = sigaction(Signal::SIGWINCH, &action);
        }

        let tx_input_clone = tx_input.clone();
        thread::spawn(move || {
            // listen to the resize event;
            loop {
                let _errno = sigset.wait();
                if tx_input_clone.send((EvActRedraw, Box::new(true))).is_err() {
                    break;
                }
            }
        });

        //------------------------------------------------------------------------------
        // curses

        // termion require the stdin to be terminal file
        // see: https://github.com/ticki/termion/issues/64
        // Here is a workaround. But reader will need to know the real stdin.
        let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

        let source = source.or_else(|| {
            if !istty {
                unsafe {
                    let stdin = File::from_raw_fd(libc::dup(libc::STDIN_FILENO));
                    let tty = File::open("/dev/tty").expect("main: failed to open /dev/tty");
                    libc::dup2(tty.into_raw_fd(), libc::STDIN_FILENO);
                    Some(Box::new(BufReader::new(stdin)))
                }
            } else {
                None
            }
        });

        let curses = Curses::new(&options);

        //------------------------------------------------------------------------------
        // query
        let default_command = match env::var("SKIM_DEFAULT_COMMAND").as_ref().map(String::as_ref) {
            Ok("") | Err(_) => "find .".to_owned(),
            Ok(val) => val.to_owned(),
        };
        let mut query = query::Query::builder().base_cmd(&default_command).build();
        query.parse_options(&options);

        //------------------------------------------------------------------------------
        // reader -- read items from stdin or output of comment

        debug!("reader start");
        let (tx_reader, rx_reader) = channel();
        let (tx_item, rx_item) = sync_channel(128);
        let mut reader = reader::Reader::new(rx_reader, tx_item.clone(), source);
        reader.parse_options(&options);
        thread::spawn(move || {
            reader.run();
        });

        //------------------------------------------------------------------------------
        // input
        let tx_input_clone = tx_input.clone();
        let mut input = input::Input::new(tx_input_clone);

        input.parse_keymaps(&options.bind);

        input.parse_expect_keys(options.expect.as_ref().map(|x| &**x));
        thread::spawn(move || {
            input.run();
        });

        //------------------------------------------------------------------------------
        // model + previewer
        let (tx_model, rx_model) = channel();
        let mut model = model::Model::new(rx_model);

        model.parse_options(&options);

        if options.preview.is_some(){
            let (tx_preview, rx_preview) = channel();
            model.set_previewer(tx_preview);
            // previewer
            let tx_model_clone = tx_model.clone();
            std::thread::spawn(move ||{
                previewer::run(rx_preview, tx_model_clone);
            });
        }

        thread::spawn(move || {
            model.run(curses);
        });

        //------------------------------------------------------------------------------
        // matcher
        let tx_model_clone = tx_model.clone();
        let mut matcher = matcher::Matcher::new(tx_model_clone);
        matcher.parse_options(&options);

        thread::spawn(move || {
            matcher.run(rx_item);
        });

        //------------------------------------------------------------------------------
        // start a timer for notifying refresh
        let tx_model_clone = tx_model.clone();
        thread::spawn(move || loop {
            thread::sleep(Duration::from_millis(REFRESH_DURATION));
            let _ = tx_model_clone.send((EvModelDrawInfo, Box::new(true)));
        });

        //------------------------------------------------------------------------------
        // Helper functions

        // light up the fire
        let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), false))));

        let redraw_query = |query: &query::Query| {
            let _ = tx_model.send((EvModelDrawQuery, Box::new(query.get_print_func())));
        };

        let on_query_change = |query: &query::Query| {
            // restart the reader with new parameter
            // send redraw event
            redraw_query(query);
            let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), false))));
        };

        let on_query_force_update = |query: &query::Query| {
            // restart the reader with new parameter
            let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), true))));
            // send redraw event
            redraw_query(query);
        };

        //------------------------------------------------------------------------------
        // main loop, listen for user input
        // now we can use
        // tx_reader: send message to reader
        // tx_model:  send message to model
        // rx_input:  receive keystroke events

        let mut ret = None;

        let _ = tx_input.send((EvActRedraw, Box::new(true))); // trigger draw
        while let Ok((ev, arg)) = rx_input.recv() {
            debug!("main: got event {:?}", ev);
            match ev {
                EvActAddChar => {
                    let ch: char = *arg.downcast().expect("EvActAddChar: failed to get argument");
                    query.act_add_char(ch);
                    on_query_change(&query);
                }

                EvActBackwardDeleteChar => {
                    query.act_backward_delete_char();
                    on_query_change(&query);
                }

                EvActDeleteCharEOF | EvActDeleteChar => {
                    query.act_delete_char();
                    on_query_change(&query);
                }

                EvActBackwardChar => {
                    query.act_backward_char();
                    redraw_query(&query);
                }

                EvActForwardChar => {
                    query.act_forward_char();
                    redraw_query(&query);
                }

                EvActBackwardKillWord => {
                    query.act_backward_kill_word();
                    on_query_change(&query);
                }

                EvActUnixWordRubout => {
                    query.act_unix_word_rubout();
                    on_query_change(&query);
                }

                EvActBackwardWord => {
                    query.act_backward_word();
                    redraw_query(&query);
                }

                EvActForwardWord => {
                    query.act_forward_word();
                    redraw_query(&query);
                }

                EvActBeginningOfLine => {
                    query.act_beginning_of_line();
                    redraw_query(&query);
                }

                EvActEndOfLine => {
                    query.act_end_of_line();
                    redraw_query(&query);
                }

                EvActKillLine => {
                    query.act_kill_line();
                    on_query_change(&query);
                }

                EvActUnixLineDiscard => {
                    query.act_line_discard();
                    on_query_change(&query);
                }

                EvActKillWord => {
                    query.act_kill_word();
                    on_query_change(&query);
                }

                EvActYank => {
                    query.act_yank();
                    on_query_change(&query);
                }

                EvActToggleInteractive => {
                    query.act_query_toggle_interactive();
                    redraw_query(&query);
                }

                EvActRotateMode => {
                    // tell the matcher to switch mode
                    let _ = tx_item.send((EvActRotateMode, Box::new(false)));
                    on_query_force_update(&query);
                }

                EvActAccept => {
                    // kill reader
                    let (tx, rx): (Sender<usize>, Receiver<usize>) = channel();
                    let _ = tx_reader.send((EvActAccept, Box::new(tx)));
                    let _ = rx.recv();

                    // sync with model to quit
                    let accept_key = *arg.downcast::<Option<String>>().unwrap_or_else(|_| Box::new(None));

                    let (tx, rx): (Sender<Vec<Arc<Item>>>, Receiver<Vec<Arc<Item>>>) = channel();
                    let _ = tx_model.send((EvActAccept, Box::new(tx)));
                    let selected = rx.recv().expect("receiving selected item failure on accept");

                    ret = Some(SkimOutput {
                        accept_key,
                        query: query.get_query(),
                        cmd: query.get_cmd_query(),
                        selected_items: selected,
                    });

                    break;
                }

                EvActClearScreen | EvActRedraw => {
                    let _ = tx_model.send((EvActRedraw, Box::new(query.get_print_func())));
                }

                EvActAbort => {
                    // kill reader
                    let (tx, rx): (Sender<usize>, Receiver<usize>) = channel();
                    let _ = tx_reader.send((EvActAbort, Box::new(tx)));
                    let _ = rx.recv();

                    // kill model
                    let (tx, rx): (Sender<bool>, Receiver<bool>) = channel();
                    let _ = tx_model.send((EvActAbort, Box::new(tx)));
                    let _ = rx.recv();
                    break;
                }

                EvActUp | EvActDown | EvActToggle | EvActToggleDown | EvActToggleUp | EvActToggleAll
                | EvActSelectAll | EvActDeselectAll | EvActPageDown | EvActPageUp | EvActScrollLeft
                | EvActScrollRight => {
                    let _ = tx_model.send((ev, arg));
                }

                EvActTogglePreview => {
                    let _ = tx_model.send((ev, arg));
                    let _ = tx_model.send((EvActRedraw, Box::new(query.get_print_func())));
                }

                EvReportCursorPos => {
                    let (y, x): (u16, u16) = *arg.downcast().expect("EvReportCursorPos: failed to get arguments");
                    debug!("main:EvReportCursorPos: {}/{}", y, x);
                }
                _ => {}
            }
        }

        ret
    }
}
<commit_msg>fix #121 implement delete-charEOF<commit_after>extern crate env_logger;
extern crate nix;
extern crate regex;
extern crate termion;
extern crate unicode_width;
#[macro_use]
extern crate log;
extern crate clap;

#[macro_use]
extern crate lazy_static;
mod ansi;
mod curses;
mod event;
mod field;
mod input;
mod item;
mod matcher;
mod model;
mod options;
mod orderedvec;
mod output;
mod query;
mod reader;
mod score;
mod sender;
mod util;
mod previewer;

use curses::Curses;
use event::Event::*;
use event::{EventReceiver, EventSender};
use item::Item;
use nix::libc;
use nix::sys::signal::{pthread_sigmask, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal};
pub use options::SkimOptions;
pub use output::SkimOutput;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::sync::mpsc::{channel, sync_channel, Receiver, Sender};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

const REFRESH_DURATION: u64 = 200;

pub struct Skim {}

extern "C" fn handle_sigwiwnch(_: i32) {}

impl Skim {
    pub fn run_with(options: &SkimOptions, source: Option<Box<BufRead + Send>>) -> Option<SkimOutput> {
        let (tx_input, rx_input): (EventSender, EventReceiver) = channel();
        //------------------------------------------------------------------------------
        // register terminal resize event, `pthread_sigmask` should be run before any thread.

        let mut sigset = SigSet::empty();
        sigset.add(Signal::SIGWINCH);
        let _ = pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(&sigset), None);

        // SIGWINCH is ignored by mac by default, thus we need to register an empty handler
        let action = SigAction::new(SigHandler::Handler(handle_sigwiwnch), SaFlags::empty(), SigSet::empty());
        unsafe {
            let _ = sigaction(Signal::SIGWINCH, &action);
        }

        let tx_input_clone = tx_input.clone();
        thread::spawn(move || {
            // listen to the resize event;
            loop {
                let _errno = sigset.wait();
                if tx_input_clone.send((EvActRedraw, Box::new(true))).is_err() {
                    break;
                }
            }
        });

        //------------------------------------------------------------------------------
        // curses

        // termion require the stdin to be terminal file
        // see: https://github.com/ticki/termion/issues/64
        // Here is a workaround. But reader will need to know the real stdin.
        let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

        let source = source.or_else(|| {
            if !istty {
                unsafe {
                    let stdin = File::from_raw_fd(libc::dup(libc::STDIN_FILENO));
                    let tty = File::open("/dev/tty").expect("main: failed to open /dev/tty");
                    libc::dup2(tty.into_raw_fd(), libc::STDIN_FILENO);
                    Some(Box::new(BufReader::new(stdin)))
                }
            } else {
                None
            }
        });

        let curses = Curses::new(&options);

        //------------------------------------------------------------------------------
        // query
        let default_command = match env::var("SKIM_DEFAULT_COMMAND").as_ref().map(String::as_ref) {
            Ok("") | Err(_) => "find .".to_owned(),
            Ok(val) => val.to_owned(),
        };
        let mut query = query::Query::builder().base_cmd(&default_command).build();
        query.parse_options(&options);

        //------------------------------------------------------------------------------
        // reader -- read items from stdin or output of comment

        debug!("reader start");
        let (tx_reader, rx_reader) = channel();
        let (tx_item, rx_item) = sync_channel(128);
        let mut reader = reader::Reader::new(rx_reader, tx_item.clone(), source);
        reader.parse_options(&options);
        thread::spawn(move || {
            reader.run();
        });

        //------------------------------------------------------------------------------
        // input
        let tx_input_clone = tx_input.clone();
        let mut input = input::Input::new(tx_input_clone);

        input.parse_keymaps(&options.bind);

        input.parse_expect_keys(options.expect.as_ref().map(|x| &**x));
        thread::spawn(move || {
            input.run();
        });

        //------------------------------------------------------------------------------
        // model + previewer
        let (tx_model, rx_model) = channel();
        let mut model = model::Model::new(rx_model);

        model.parse_options(&options);

        if options.preview.is_some(){
            let (tx_preview, rx_preview) = channel();
            model.set_previewer(tx_preview);
            // previewer
            let tx_model_clone = tx_model.clone();
            std::thread::spawn(move ||{
                previewer::run(rx_preview, tx_model_clone);
            });
        }

        thread::spawn(move || {
            model.run(curses);
        });

        //------------------------------------------------------------------------------
        // matcher
        let tx_model_clone = tx_model.clone();
        let mut matcher = matcher::Matcher::new(tx_model_clone);
        matcher.parse_options(&options);

        thread::spawn(move || {
            matcher.run(rx_item);
        });

        //------------------------------------------------------------------------------
        // start a timer for notifying refresh
        let tx_model_clone = tx_model.clone();
        thread::spawn(move || loop {
            thread::sleep(Duration::from_millis(REFRESH_DURATION));
            let _ = tx_model_clone.send((EvModelDrawInfo, Box::new(true)));
        });

        //------------------------------------------------------------------------------
        // Helper functions

        // light up the fire
        let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), false))));

        let redraw_query = |query: &query::Query| {
            let _ = tx_model.send((EvModelDrawQuery, Box::new(query.get_print_func())));
        };

        let on_query_change = |query: &query::Query| {
            // restart the reader with new parameter
            // send redraw event
            redraw_query(query);
            let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), false))));
        };

        let on_query_force_update = |query: &query::Query| {
            // restart the reader with new parameter
            let _ = tx_reader.send((EvReaderRestart, Box::new((query.get_cmd(), query.get_query(), true))));
            // send redraw event
            redraw_query(query);
        };

        //------------------------------------------------------------------------------
        // main loop, listen for user input
        // now we can use
        // tx_reader: send message to reader
        // tx_model:  send message to model
        // rx_input:  receive keystroke events

        let mut ret = None;

        let _ = tx_input.send((EvActRedraw, Box::new(true))); // trigger draw
        while let Ok((ev, arg)) = rx_input.recv() {
            debug!("main: got event {:?}", ev);
            match ev {
                EvActAddChar => {
                    let ch: char = *arg.downcast().expect("EvActAddChar: failed to get argument");
                    query.act_add_char(ch);
                    on_query_change(&query);
                }

                EvActBackwardDeleteChar => {
                    query.act_backward_delete_char();
                    on_query_change(&query);
                }

                EvActDeleteChar => {
                    query.act_delete_char();
                    on_query_change(&query);
                }

                EvActDeleteCharEOF => {
                    if query.get_query() == "" {
                        let _ = tx_input.send((EvActAbort, Box::new(true))); // trigger draw
                    } else {
                        let _ = tx_input.send((EvActDeleteChar, Box::new(true))); // trigger draw
                    }
                }

                EvActBackwardChar => {
                    query.act_backward_char();
                    redraw_query(&query);
                }

                EvActForwardChar => {
                    query.act_forward_char();
                    redraw_query(&query);
                }

                EvActBackwardKillWord => {
                    query.act_backward_kill_word();
                    on_query_change(&query);
                }

                EvActUnixWordRubout => {
                    query.act_unix_word_rubout();
                    on_query_change(&query);
                }

                EvActBackwardWord => {
                    query.act_backward_word();
                    redraw_query(&query);
                }

                EvActForwardWord => {
                    query.act_forward_word();
                    redraw_query(&query);
                }

                EvActBeginningOfLine => {
                    query.act_beginning_of_line();
                    redraw_query(&query);
                }

                EvActEndOfLine => {
                    query.act_end_of_line();
                    redraw_query(&query);
                }

                EvActKillLine => {
                    query.act_kill_line();
                    on_query_change(&query);
                }

                EvActUnixLineDiscard => {
                    query.act_line_discard();
                    on_query_change(&query);
                }

                EvActKillWord => {
                    query.act_kill_word();
                    on_query_change(&query);
                }

                EvActYank => {
                    query.act_yank();
                    on_query_change(&query);
                }

                EvActToggleInteractive => {
                    query.act_query_toggle_interactive();
                    redraw_query(&query);
                }

                EvActRotateMode => {
                    // tell the matcher to switch mode
                    let _ = tx_item.send((EvActRotateMode, Box::new(false)));
                    on_query_force_update(&query);
                }

                EvActAccept => {
                    // kill reader
                    let (tx, rx): (Sender<usize>, Receiver<usize>) = channel();
                    let _ = tx_reader.send((EvActAccept, Box::new(tx)));
                    let _ = rx.recv();

                    // sync with model to quit
                    let accept_key = *arg.downcast::<Option<String>>().unwrap_or_else(|_| Box::new(None));

                    let (tx, rx): (Sender<Vec<Arc<Item>>>, Receiver<Vec<Arc<Item>>>) = channel();
                    let _ = tx_model.send((EvActAccept, Box::new(tx)));
                    let selected = rx.recv().expect("receiving selected item failure on accept");

                    ret = Some(SkimOutput {
                        accept_key,
                        query: query.get_query(),
                        cmd: query.get_cmd_query(),
                        selected_items: selected,
                    });

                    break;
                }

                EvActClearScreen | EvActRedraw => {
                    let _ = tx_model.send((EvActRedraw, Box::new(query.get_print_func())));
                }

                EvActAbort => {
                    // kill reader
                    let (tx, rx): (Sender<usize>, Receiver<usize>) = channel();
                    let _ = tx_reader.send((EvActAbort, Box::new(tx)));
                    let _ = rx.recv();

                    // kill model
                    let (tx, rx): (Sender<bool>, Receiver<bool>) = channel();
                    let _ = tx_model.send((EvActAbort, Box::new(tx)));
                    let _ = rx.recv();
                    break;
                }

                EvActUp | EvActDown | EvActToggle | EvActToggleDown | EvActToggleUp | EvActToggleAll
                | EvActSelectAll | EvActDeselectAll | EvActPageDown | EvActPageUp | EvActScrollLeft
                | EvActScrollRight => {
                    let _ = tx_model.send((ev, arg));
                }

                EvActTogglePreview => {
                    let _ = tx_model.send((ev, arg));
                    let _ = tx_model.send((EvActRedraw, Box::new(query.get_print_func())));
                }

                EvReportCursorPos => {
                    let (y, x): (u16, u16) = *arg.downcast().expect("EvReportCursorPos: failed to get arguments");
                    debug!("main:EvReportCursorPos: {}/{}", y, x);
                }
                _ => {}
            }
        }

        ret
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![feature(unsafe_destructor)]

//! A library for setting current values for stack scope,
//! such as application structure.

pub use current::{ Current, CurrentGuard };

use std::cell::RefCell;

mod current;

impl<F: 'static, T: Modifier<F>> Modifier<Current<F>> for T {
    #[inline(always)]
    fn modify(self, obj: &mut Current<F>) {
        self.modify((*obj).deref_mut());
    }
}

impl<T: 'static + Get<U>, U> Get<U> for Current<T> {
    #[inline(always)]
    fn get(&self) -> U {
        (*self).deref().get()
    }
}

impl<'a, T: Get<U>, U> Get<U> for &'a RefCell<T> {
    #[inline(always)]
    fn get(&self) -> U {
        self.borrow().deref().get()
    }
}

impl<'a, F, T: Modifier<F>> Modifier<&'a RefCell<F>> for T {
    #[inline(always)]
    fn modify(self, obj: &mut &'a RefCell<F>) {
        self.modify(obj.borrow_mut().deref_mut())
    }
}

/// Allows use of the implemented type as an argument to Set::set.
///
/// This allows types to be used for ad-hoc overloading of Set::set
/// to perform complex updates to the parameter of Modifier.
pub trait Modifier<F> {
    /// Modify `F` with self.
    fn modify(self, &mut F);
}

/// A blanket trait providing the set and set_mut methods for all types.
pub trait Set<M> {
    /// Modify self using the provided modifier.
    fn set(mut self, modifier: M) -> Self;

    /// Modify self through a mutable reference with the provided modifier.
    fn set_mut(&mut self, modifier: M) -> &mut Self;
}

impl<T, U: Modifier<T>> Set<U> for T {
    #[inline(always)]
    fn set(mut self, modifier: U) -> T {
        modifier.modify(&mut self);
        self
    }

    #[inline(always)]
    fn set_mut(&mut self, modifier: U) -> &mut T {
        modifier.modify(self);
        self
    }
}

/// Implemented by types that can be constructed from another value.
pub trait Get<T> {
    /// Returns new value.
    fn get(&self) -> T;
}
<commit_msg>Added `DANGER`<commit_after>#![deny(missing_docs)]
#![feature(unsafe_destructor)]

//! A library for setting current values for stack scope,
//! such as application structure.

pub use current::{ Current, CurrentGuard };

use std::cell::RefCell;

mod current;

/// Used as warning sign for functions
/// that under normal circumstances works with safe code,
/// but in some edge cases are unsafe.
///
/// 1. The function MUST take `DANGER` as first argument.
///
/// 2. The function MUST take ownership of the value.
///
/// 3. The function docs MUST include a notice `### DANGER`
/// describing the edge case.
///
/// It can not be copied, so an unsafe block is required
/// whenever it is used.
#[allow(missing_copy_implementations)]
pub struct DANGER(());

impl DANGER {
    /// Creates a new warning sign for functions
    /// that normally works with safe code
    pub unsafe fn new() -> DANGER { DANGER(()) }
}

impl<F: 'static, T: Modifier<F>> Modifier<Current<F>> for T {
    #[inline(always)]
    fn modify(self, obj: &mut Current<F>) {
        self.modify((*obj).deref_mut());
    }
}

impl<T: 'static + Get<U>, U> Get<U> for Current<T> {
    #[inline(always)]
    fn get(&self) -> U {
        (*self).deref().get()
    }
}

impl<'a, T: Get<U>, U> Get<U> for &'a RefCell<T> {
    #[inline(always)]
    fn get(&self) -> U {
        self.borrow().deref().get()
    }
}

impl<'a, F, T: Modifier<F>> Modifier<&'a RefCell<F>> for T {
    #[inline(always)]
    fn modify(self, obj: &mut &'a RefCell<F>) {
        self.modify(obj.borrow_mut().deref_mut())
    }
}

/// Allows use of the implemented type as an argument to Set::set.
///
/// This allows types to be used for ad-hoc overloading of Set::set
/// to perform complex updates to the parameter of Modifier.
pub trait Modifier<F> {
    /// Modify `F` with self.
    fn modify(self, &mut F);
}

/// A blanket trait providing the set and set_mut methods for all types.
pub trait Set<M> {
    /// Modify self using the provided modifier.
    fn set(mut self, modifier: M) -> Self;

    /// Modify self through a mutable reference with the provided modifier.
    fn set_mut(&mut self, modifier: M) -> &mut Self;
}

impl<T, U: Modifier<T>> Set<U> for T {
    #[inline(always)]
    fn set(mut self, modifier: U) -> T {
        modifier.modify(&mut self);
        self
    }

    #[inline(always)]
    fn set_mut(&mut self, modifier: U) -> &mut T {
        modifier.modify(self);
        self
    }
}

/// Implemented by types that can be constructed from another value.
pub trait Get<T> {
    /// Returns new value.
    fn get(&self) -> T;
}
<|endoftext|>


<commit_before>//! A simple `io::stdoud` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

extern crate log;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let msg = format!("{}: {}",
                              level_style(record.level()).paint(record.location().module_path()),
                              record.args());
            if record.level() <= LogLevel::Warn {
                writeln!(&mut io::stderr(), "{}", msg);
            } else {
                println!("{}", msg);
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger { log_level: log_level })
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        //error!("error log");
        //warn!("warn log");
        //info!("info log");
        //debug!("debug log");
        //trace!("trace log");
    }
}
<commit_msg>Update lib.rs<commit_after>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

extern crate log;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

struct VLogger {
    log_level: LogLevel,
}

fn level_style(l: LogLevel) -> Colour {
    match l {
        LogLevel::Error => Colour::Fixed(9), // bright red
        LogLevel::Warn => Colour::Fixed(11), // bright yellow
        LogLevel::Info => Colour::Fixed(10), // bright green
        LogLevel::Debug => Colour::Fixed(7), // light grey
        LogLevel::Trace => Colour::Fixed(8), // grey
    }
}

impl Log for VLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.log_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let msg = format!("{}: {}",
                              level_style(record.level()).paint(record.location().module_path()),
                              record.args());
            if record.level() <= LogLevel::Warn {
                writeln!(&mut io::stderr(), "{}", msg);
            } else {
                println!("{}", msg);
            }
        }
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(log_level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        Box::new(VLogger { log_level: log_level })
    })
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    init_with_level(match verbosity {
        0 => LogLevel::Warn,  // default
        1 => LogLevel::Info,  // -v
        2 => LogLevel::Debug, // -vv
        _ => LogLevel::Trace, // -vvv and above
    })
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        //error!("error log");
        //warn!("warn log");
        //info!("info log");
        //debug!("debug log");
        //trace!("trace log");
    }
}
<|endoftext|>


<commit_before>//! # Fixerio API Wrapper
//!
//! http://fixer.io
//!
//! ## Usage
//! Add the following to `Cargo.toml`:
//!
//! ```rust,ignore
//! [dependencies]
//! fixerio = "0.1.2"
//! ```
//!
//! Synchronous example:
//!
//! ```rust,no_run
//!
//! extern crate fixerio;
//!
//! use fixerio::{Config, Currency, SyncApi};
//!
//! fn main() {
//!     let api = SyncApi::new().expect("Error creating API");
//!
//!     let config = Config::new(Currency::USD);
//!     let rates = api.get(&config).expect("Error retrieving rates");
//!
//!     println!("{:?}", rates);
//! }
//! ```
//!
//! Asynchronous example:
//!
//! ```rust,no_run
//!
//! extern crate fixerio;
//! extern crate tokio_core;
//!
//! use fixerio::{Config, Currency, AsyncApi};
//! use tokio_core::reactor::Core;
//!
//! fn main() {
//!     let mut core = Core::new().expect("Error creating core");
//!     let handle = core.handle();
//!
//!     let api = AsyncApi::new(&handle);
//!
//!     let config = Config::new(Currency::USD);
//!     let work = api.get(&config);
//!
//!     println!("{:?}", core.run(work).expect("Error retrieving rates"));
//! }
//! ```

#[macro_use]
extern crate serde_derive;
extern crate hyper;
extern crate tokio_core;
extern crate futures;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate error_chain;

mod client;
mod exchange;
mod future;
mod errors;

pub use self::client::{AsyncApi, SyncApi, Config};
pub use self::exchange::{Currency, Exchange, Rates};
pub use self::future::FixerioFuture;<commit_msg>Export errors.<commit_after>//! # Fixerio API Wrapper
//!
//! http://fixer.io
//!
//! ## Usage
//! Add the following to `Cargo.toml`:
//!
//! ```rust,ignore
//! [dependencies]
//! fixerio = "0.1.2"
//! ```
//!
//! Synchronous example:
//!
//! ```rust,no_run
//!
//! extern crate fixerio;
//!
//! use fixerio::{Config, Currency, SyncApi};
//!
//! fn main() {
//!     let api = SyncApi::new().expect("Error creating API");
//!
//!     let config = Config::new(Currency::USD);
//!     let rates = api.get(&config).expect("Error retrieving rates");
//!
//!     println!("{:?}", rates);
//! }
//! ```
//!
//! Asynchronous example:
//!
//! ```rust,no_run
//!
//! extern crate fixerio;
//! extern crate tokio_core;
//!
//! use fixerio::{Config, Currency, AsyncApi};
//! use tokio_core::reactor::Core;
//!
//! fn main() {
//!     let mut core = Core::new().expect("Error creating core");
//!     let handle = core.handle();
//!
//!     let api = AsyncApi::new(&handle);
//!
//!     let config = Config::new(Currency::USD);
//!     let work = api.get(&config);
//!
//!     println!("{:?}", core.run(work).expect("Error retrieving rates"));
//! }
//! ```

#[macro_use]
extern crate serde_derive;
extern crate hyper;
extern crate tokio_core;
extern crate futures;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate error_chain;

mod client;
mod exchange;
mod future;
mod errors;

pub use self::client::{AsyncApi, SyncApi, Config};
pub use self::exchange::{Currency, Exchange, Rates};
pub use self::future::FixerioFuture;
pub use self::errors::{Error, ErrorKind};<|endoftext|>


<commit_before>#![recursion_limit = "1024"]
#[macro_use]
extern crate error_chain;

extern crate rustc_serialize;

use std::net::TcpStream;
use std::io::prelude::*;
use std::collections::HashMap;
use rustc_serialize::json;

pub mod errors;
use errors::*;

pub struct WhoIs<'a> {
    server: &'a str,
    follow: isize,
    new_whois: String,
    query: String,
}

impl<'a> WhoIs<'a> {
    pub fn new(x: &'a str) -> WhoIs<'a> {
        WhoIs {
            server: x,
            follow: 0,
            new_whois: String::new(),
            query: String::new(),
        }
    }
    ///  This function will get whois server from the `get_server` function, decide the appropriate
    ///  query for the server and parse the whois data into JSON by calling `parse_data()`.
    ///
    ///  If there is another whois server in the whois data then it calls `parse_whois`,
    ///  so it can get the whois data from that.
    pub fn lookup(&mut self) -> Result<String> {
        let mut result = String::new();
        let mut server = self.new_whois.to_owned();
        let target = self.server.to_owned();
        let tld = match target.split(".").last() {
            Some(tld) => tld,
            None => return Err("Invalid URL?".into()),
        };
        if self.follow == 0 {
            self.query = match tld {
                "com" | "net" => "DOMAIN ".into(),
                _ => "".into(),
            };
            server = self.get_server(&tld).expect(&format!("Failed to get server for {}", tld));
        }
        let mut client = try!(TcpStream::connect((&*server, 43u16))
                                  .chain_err(|| "Could not connect to server!!"));

        try!(client.write_all(format!("{}{}\n", self.query, target).as_bytes())
                   .chain_err(|| "Could not write to client {}"));

        try!(client.read_to_string(&mut result)
                   .chain_err(|| "Failed to read to string"));

        if result.contains("Whois Server:") {
            self.query = "".into();
            self.follow += 1; // If there is another Whois Server, take that server and pass it to.
            Ok(self.parse_whois(&*result)) // Pass it to parse_whois.
        } else {
            let clean = result.replace("http:", "").replace("https:", ""); // I'm splitting via ':' so the urls' protocols needs to be omitted.
            self.parse_data(clean)
        }
    }
    fn parse_data(&self, result: String) -> Result<String> {
        let mut data = HashMap::new();
        for c in result.lines() {
            let mut line = c.split(':');
            let key = line.next().expect("Failed to get key");
            let value = match line.next() {
                Some(value) => value,
                None => continue,
            };
            data.insert(key, value.trim());
        }
        json::encode(&data).chain_err(|| "Could not encode data as json")
    }

    /// This function calls `lookup()` again if there is a another whois server.
    fn parse_whois(&mut self, result: &str) -> String {
        let line = &result.lines()
                          .find(|i| i.contains("Whois Server:"))
                          .expect("Could not find wh");
        let target = line.split_whitespace().last().unwrap().to_owned();
        self.new_whois = target;
        self.lookup().expect("Failed lookup in parse_whois")
    }

    fn get_server(&self, target: &str) -> Result<String> {
        let mut result = String::new();
        let mut client = try!(TcpStream::connect("whois.iana.org:43")
                                  .chain_err(|| "Could not connect to server!"));

        try!(client.write_all(format!("{}\n", target).as_bytes())
                   .chain_err(|| "Could not write to client"));

        try!(client.read_to_string(&mut result).chain_err(|| "Failed to read result to string"));
        let line = &result.lines().find(|i| i.starts_with("whois:")).expect("Couldnt get wh");
        let foo = line.split_whitespace().last().unwrap().to_owned();
        Ok(foo)
    }
}
<commit_msg>Refactor try! to ?<commit_after>#![recursion_limit = "1024"]
#[macro_use]
extern crate error_chain;

extern crate rustc_serialize;

use std::net::TcpStream;
use std::io::prelude::*;
use std::collections::HashMap;
use rustc_serialize::json;

pub mod errors;
use errors::*;

pub struct WhoIs<'a> {
    server: &'a str,
    follow: isize,
    new_whois: String,
    query: String,
}

impl<'a> WhoIs<'a> {
    pub fn new(x: &'a str) -> WhoIs<'a> {
        WhoIs {
            server: x,
            follow: 0,
            new_whois: String::new(),
            query: String::new(),
        }
    }
    ///  This function will get whois server from the `get_server` function, decide the appropriate
    ///  query for the server and parse the whois data into JSON by calling `parse_data()`.
    ///
    ///  If there is another whois server in the whois data then it calls `parse_whois`,
    ///  so it can get the whois data from that.
    pub fn lookup(&mut self) -> Result<String> {
        let mut result = String::new();
        let mut server = self.new_whois.to_owned();
        let target = self.server.to_owned();
        let tld = match target.split(".").last() {
            Some(tld) => tld,
            None => return Err("Invalid URL?".into()),
        };
        if self.follow == 0 {
            self.query = match tld {
                "com" | "net" => "DOMAIN ".into(),
                _ => "".into(),
            };
            server = self.get_server(&tld).expect(&format!("Failed to get server for {}", tld));
        }
        let mut client = TcpStream::connect((&*server, 43u16))
                            .chain_err(|| "Could not connect to server!!")?;

        client.write_all(format!("{}{}\n", self.query, target).as_bytes())
            .chain_err(|| "Could not write to client {}")?;

        client.read_to_string(&mut result)
            .chain_err(|| "Failed to read to string")?;

        if result.contains("Whois Server:") {
            self.query = "".into();
            self.follow += 1; // If there is another Whois Server, take that server and pass it to.
            Ok(self.parse_whois(&*result)) // Pass it to parse_whois.
        } else {
            let clean = result.replace("http:", "").replace("https:", ""); // I'm splitting via ':' so the urls' protocols needs to be omitted.
            self.parse_data(clean)
        }
    }
    fn parse_data(&self, result: String) -> Result<String> {
        let mut data = HashMap::new();
        for c in result.lines() {
            let mut line = c.split(':');
            let key = line.next().expect("Failed to get key");
            let value = match line.next() {
                Some(value) => value,
                None => continue,
            };
            data.insert(key, value.trim());
        }
        json::encode(&data).chain_err(|| "Could not encode data as json")
    }

    /// This function calls `lookup()` again if there is a another whois server.
    fn parse_whois(&mut self, result: &str) -> String {
        let line = &result.lines()
                          .find(|i| i.contains("Whois Server:"))
                          .expect("Could not find wh");
        let target = line.split_whitespace().last().unwrap().to_owned();
        self.new_whois = target;
        self.lookup().expect("Failed lookup in parse_whois")
    }

    fn get_server(&self, target: &str) -> Result<String> {
        let mut result = String::new();
        let mut client = TcpStream::connect("whois.iana.org:43")
                                .chain_err(|| "Could not connect to server!")?;

        client.write_all(format!("{}\n", target).as_bytes())
            .chain_err(|| "Could not write to client")?;

        client.read_to_string(&mut result).chain_err(|| "Failed to read result to string")?;
        let line = &result.lines().find(|i| i.starts_with("whois:")).expect("Couldnt get wh");
        let foo = line.split_whitespace().last().unwrap().to_owned();
        Ok(foo)
    }
}
<|endoftext|>


<commit_before>//   Copyright 2015 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate atom;
extern crate time;

use std::sync::atomic::{AtomicUsize};
use std::thread;
use std::mem;
use std::fmt;
use std::ops::Deref;
use std::sync::atomic::Ordering;
use std::cell::RefCell;

use atom::*;
use time::precise_time_s;

pub use select::{Select, SelectMap};
pub use barrier::Barrier;
mod select;
mod barrier;

/// Drop rules
/// This may be freed iff state is Signald | Dropped
/// and Waiting is Dropped
struct Inner {
    state: AtomicUsize,
    waiting: Atom<Box<Waiting>>
}

// TODO 64bit sized, probably does not matter now
const PULSED: usize = 0x8000_0000;
const TX_DROP: usize = 0x4000_0000;
const TX_FLAGS: usize = PULSED | TX_DROP;
const REF_COUNT: usize = !TX_FLAGS;

struct Waiting {
    next: Option<Box<Waiting>>,
    wake: Wake
}

impl GetNextMut for Box<Waiting> {
    type NextPtr = Option<Box<Waiting>>;

    fn get_next(&mut self) -> &mut Option<Box<Waiting>> {
        &mut self.next
    }
}

enum Wake {
    Thread(thread::Thread),
    Select(select::Handle),
    Barrier(barrier::Handle)
}

impl Waiting {
    fn wake(s: Box<Self>, id: usize) {
        let mut next = Some(s);
        while let Some(s) = next {
            // There must be a better way to do this...
            let s = *s;
            let Waiting { next: n, wake } = s;
            next = n;
            match wake {
                Wake::Thread(thread) => thread.unpark(),
                Wake::Select(select) => {
                    let trigger = {
                        let mut guard = select.0.lock().unwrap();
                        guard.ready.push(id);
                        guard.trigger.take()
                    };
                    trigger.map(|x| x.pulse());
                }
                Wake::Barrier(barrier) => {
                    let count = barrier.0.count.fetch_sub(1, Ordering::Relaxed);
                    if count == 1 {
                        let mut guard = barrier.0.trigger.lock().unwrap();
                        if let Some(t) = guard.take() {
                            t.pulse();
                        }
                    }
                }
            }
        }
    }

    fn id(&self) -> usize {
        unsafe { mem::transmute(self) }
    }

    fn thread() -> Box<Waiting> {
        Box::new(Waiting {
            next: None,
            wake: Wake::Thread(thread::current())
        })
    }

    fn select(handle: select::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Select(handle)
        })
    }

    fn barrier(handle: barrier::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Barrier(handle)
        })
    }
}

unsafe impl Send for Pulse {}

/// A `Pulse` is represents an unfired signal. It is the tx side of Signal
/// A `Pulse` can only purpose it to be fired, and then it will be moved
/// as to never allow it to fire again. `Dropping` a pulse will `pulse`
/// The signal, but the signal will enter an error state.
pub struct Pulse {
    inner: *mut Inner
}

impl fmt::Debug for Pulse {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let id: usize = unsafe { mem::transmute(self.inner) };
        write!(f, "Pulse({:?})", id)
    }
}

fn delete_inner(state: usize, inner: *mut Inner) {
    if state & REF_COUNT == 1 {
        let inner: Box<Inner> = unsafe {
            mem::transmute(inner)
        };
        drop(inner);
    }
}

impl Drop for Pulse {
    fn drop(&mut self) {
        self.set(TX_DROP);
        self.wake();
        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner)
    }
}

impl Pulse {
    /// Create a Pulse from a usize. This is naturally unsafe.
    pub unsafe fn cast_from_usize(ptr: usize) -> Pulse {
        Pulse {
            inner: mem::transmute(ptr)
        }
    }

    /// Convert a trigger to a `usize`, This is unsafe
    /// and it will kill your kittens if you are not careful
    pub unsafe fn cast_to_usize(self) -> usize {
        let us = mem::transmute(self.inner);
        mem::forget(self);
        us
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    fn set(&self, state: usize) -> usize {
        self.inner().state.fetch_or(state, Ordering::Relaxed)
    }

    fn wake(&self) {
        let id = unsafe { mem::transmute(self.inner) };
        match self.inner().waiting.take() {
            None => (),
            Some(v) => Waiting::wake(v, id)
        }
    }

    /// Pulse the `pulse` which will transition the `Signal` out from pending
    /// to ready. This moves the pulse so that it can only be fired once.
    pub fn pulse(self) {
        self.set(PULSED);
        self.wake();

        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner);
        unsafe { mem::forget(self) }
    }
}

unsafe impl Send for Signal {}

/// A `Signal` represents listens for a `pulse` to occur in the system. A
/// `Signal` has one of three states. Pending, Pulsed, or Errored. Pending
/// means the pulse has not fired, but still exists. Pulsed meaning the
/// pulse has fired, and no longer exists. Errored means the pulse was dropped
/// without firing. This normally means a programming error of some sort.
pub struct Signal {
    inner: *mut Inner
}

impl fmt::Debug for Signal {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "Signal(id={:?}, pending={:?})", self.id(), self.is_pending())
    }
}

impl Clone for Signal {
    fn clone(&self) -> Signal {
        self.inner().state.fetch_add(1, Ordering::Relaxed);
        Signal { inner: self.inner }
    }
}

impl Drop for Signal {
    #[inline]
    fn drop(&mut self) {
        let flag = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(flag, self.inner);
    }
}

impl Signal {
    /// Create a Signal and a Pulse that are associated.
    pub fn new() -> (Signal, Pulse) {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(2),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        (Signal {
            inner: inner
         },
         Pulse {
            inner: inner,
        })
    }

    /// Create a signal that is already pulsed
    pub fn pulsed() -> Signal {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(1 | PULSED),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        Signal { inner: inner }
    }

    #[inline]
    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    /// Read out the state of the Signal
    #[inline]
    fn state(&self) -> usize {
        self.inner().state.load(Ordering::Relaxed)
    }

    /// Check to see if the signal is pending. A signal
    #[inline]
    pub fn is_pending(&self) -> bool {
        self.state() & TX_FLAGS == 0
    }

    /// Add a waiter to a waitlist
    fn add_to_waitlist(&self, waiter: Box<Waiting>) -> usize {
        let id = waiter.id();

        self.inner().waiting.replace_and_set_next(waiter);

        // if armed fire now
        if !self.is_pending() {
            if let Some(t) = self.inner().waiting.take() {
                Waiting::wake(t, self.id());
            }
        }
        id
    }

    /// Remove Waiter with `id` from the waitlist
    fn remove_from_waitlist(&self, id: usize) {
        let mut wl = self.inner().waiting.take();
        while let Some(mut w) = wl {
            let next = w.next.take();
            if w.id() != id {
                self.add_to_waitlist(w);
            }
            wl = next;
        }
    }

    /// Arm a pulse to wake
    fn arm(self, waiter: Box<Waiting>) -> ArmedSignal {
        let id = self.add_to_waitlist(waiter);
        ArmedSignal {
            id: id,
            pulse: self
        }
    }

    /// This is a unique id that can be used to identify the signal from others
    /// See `Select` for how this api is useful.
    pub fn id(&self) -> usize {
        unsafe { mem::transmute_copy(&self.inner) }
    }

    /// Block the current thread until a `pulse` is ready.
    /// This will block indefinably if the pulse never fires.
    #[inline]
    pub fn wait(self) -> Result<(), WaitError> {
        if !self.is_pending() {
            let state = self.state();
            return if (state & PULSED) == PULSED {
                Ok(())
            } else {
                Err(WaitError::Dropped)
            };
        } else {
            SCHED.with(|sched| {
                sched.borrow().wait(self)
            })
        }
    }

    /// Block until either the pulse is sent, or the timeout is reached
    pub fn wait_timeout_ms(self, ms: u32) -> Result<(), TimeoutError> {
        SCHED.with(|sched| {
            sched.borrow().wait_timeout_ms(self, ms)
        })
    }
}

impl IntoRawPtr for Pulse {
    unsafe fn into_raw(self) -> *mut () {
        let inner = self.inner;
        mem::forget(self);
        mem::transmute(inner)
    }
}

impl FromRawPtr for Pulse {
    unsafe fn from_raw(ptr: *mut ()) -> Pulse {
        Pulse { inner: mem::transmute(ptr) }
    }
}

/// Represents the possible errors that can occur on a `Signal`
#[derive(Debug, PartialEq, Eq)]
pub enum WaitError {
    /// The `Pulse` was dropped before it could `Pulse`
    Dropped
}

/// Represents the possible errors from a wait timeout
#[derive(Debug, PartialEq, Eq)]
pub enum TimeoutError {
    /// A `WaitError` has occurred
    Error(WaitError),
    /// The `Signal` timed-out before a `Pulse` was observed.
    Timeout
}

struct ArmedSignal {
    pulse: Signal,
    id: usize
}

impl Deref for ArmedSignal {
    type Target = Signal;

    fn deref(&self) -> &Signal { &self.pulse }
}

impl ArmedSignal {
    fn disarm(self) -> Signal {
        self.remove_from_waitlist(self.id);
        self.pulse
    }
}

/// allows an object to assert a wait signal
pub trait Signals {
    /// Get a signal from a object
    fn signal(&self) -> Signal;

    /// Block the current thread until the object
    /// assets a pulse.
    fn wait(&self) -> Result<(), WaitError> {
        let signal = self.signal();
        signal.wait()
    }

    /// Block the current thread until the object
    /// assets a pulse. Or until the timeout has been asserted.
    fn wait_timeout_ms(&self, ms: u32) -> Result<(), TimeoutError> {
        let signal = self.signal();
        signal.wait_timeout_ms(ms)
    }
}

/// This is the hook into the async wait methods provided
/// by `pulse`. It is required for the user to override
/// the current system scheduler.
pub trait Scheduler {
    /// Wait until the signal is made `ready` or `errored`
    fn wait(&self, signal: Signal) -> Result<(), WaitError>;

    /// Wait until the signal is made `ready` or `errored` or the
    /// timeout has been reached.
    fn wait_timeout_ms(&self, signal: Signal, timeout: u32) -> Result<(), TimeoutError>;
}

/// This is the `default` system scheduler that is used if no
/// user provided scheduler is installed. It is very basic
/// and will block the OS thread using `thread::park`
pub struct ThreadScheduler;

impl Scheduler for ThreadScheduler {
    fn wait(&self, signal: Signal) -> Result<(), WaitError> {
        loop {
            let id = signal.add_to_waitlist(Waiting::thread());
            if signal.is_pending() {
                thread::park();
            }
            signal.remove_from_waitlist(id);

            if !signal.is_pending() {
                let state = signal.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(WaitError::Dropped)
                };
            }
        }
    }

    fn wait_timeout_ms(&self, signal: Signal, ms: u32) -> Result<(), TimeoutError> {
        let mut now = (precise_time_s() * 1000.) as u64;
        let end = now + ms as u64;

        loop {
            let id = signal.add_to_waitlist(Waiting::thread());
            if signal.is_pending() {
                now = (precise_time_s() * 1000.) as u64;
                if now > end {
                    return Err(TimeoutError::Timeout)
                }
                thread::park_timeout_ms((end - now) as u32);
            }
            signal.remove_from_waitlist(id);

            if !signal.is_pending() {
                let state = signal.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(TimeoutError::Error(WaitError::Dropped))
                };
            }
        }
    }
}

/// The TLS scheduler
thread_local!(static SCHED: RefCell<Box<Scheduler>> = RefCell::new(Box::new(ThreadScheduler)));

/// Replace the current Scheduler with your own supplied scheduler.
/// all `wait()` commands will be run through this scheduler now.
///
/// This will return the current TLS scheduler, which may be useful
/// to restore it later.
pub fn swap_scheduler(mut sched: Box<Scheduler>) -> Box<Scheduler> {
    use std::mem;

    SCHED.with(|s| {
        mem::swap(&mut *s.borrow_mut(), &mut sched);
    });

    sched
}<commit_msg>Added with_scheduler<commit_after>//   Copyright 2015 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate atom;
extern crate time;

use std::sync::atomic::{AtomicUsize};
use std::thread;
use std::mem;
use std::fmt;
use std::ops::Deref;
use std::sync::atomic::Ordering;
use std::cell::RefCell;

use atom::*;
use time::precise_time_s;

pub use select::{Select, SelectMap};
pub use barrier::Barrier;
mod select;
mod barrier;

/// Drop rules
/// This may be freed iff state is Signald | Dropped
/// and Waiting is Dropped
struct Inner {
    state: AtomicUsize,
    waiting: Atom<Box<Waiting>>
}

// TODO 64bit sized, probably does not matter now
const PULSED: usize = 0x8000_0000;
const TX_DROP: usize = 0x4000_0000;
const TX_FLAGS: usize = PULSED | TX_DROP;
const REF_COUNT: usize = !TX_FLAGS;

struct Waiting {
    next: Option<Box<Waiting>>,
    wake: Wake
}

impl GetNextMut for Box<Waiting> {
    type NextPtr = Option<Box<Waiting>>;

    fn get_next(&mut self) -> &mut Option<Box<Waiting>> {
        &mut self.next
    }
}

enum Wake {
    Thread(thread::Thread),
    Select(select::Handle),
    Barrier(barrier::Handle)
}

impl Waiting {
    fn wake(s: Box<Self>, id: usize) {
        let mut next = Some(s);
        while let Some(s) = next {
            // There must be a better way to do this...
            let s = *s;
            let Waiting { next: n, wake } = s;
            next = n;
            match wake {
                Wake::Thread(thread) => thread.unpark(),
                Wake::Select(select) => {
                    let trigger = {
                        let mut guard = select.0.lock().unwrap();
                        guard.ready.push(id);
                        guard.trigger.take()
                    };
                    trigger.map(|x| x.pulse());
                }
                Wake::Barrier(barrier) => {
                    let count = barrier.0.count.fetch_sub(1, Ordering::Relaxed);
                    if count == 1 {
                        let mut guard = barrier.0.trigger.lock().unwrap();
                        if let Some(t) = guard.take() {
                            t.pulse();
                        }
                    }
                }
            }
        }
    }

    fn id(&self) -> usize {
        unsafe { mem::transmute(self) }
    }

    fn thread() -> Box<Waiting> {
        Box::new(Waiting {
            next: None,
            wake: Wake::Thread(thread::current())
        })
    }

    fn select(handle: select::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Select(handle)
        })
    }

    fn barrier(handle: barrier::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Barrier(handle)
        })
    }
}

unsafe impl Send for Pulse {}

/// A `Pulse` is represents an unfired signal. It is the tx side of Signal
/// A `Pulse` can only purpose it to be fired, and then it will be moved
/// as to never allow it to fire again. `Dropping` a pulse will `pulse`
/// The signal, but the signal will enter an error state.
pub struct Pulse {
    inner: *mut Inner
}

impl fmt::Debug for Pulse {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let id: usize = unsafe { mem::transmute(self.inner) };
        write!(f, "Pulse({:?})", id)
    }
}

fn delete_inner(state: usize, inner: *mut Inner) {
    if state & REF_COUNT == 1 {
        let inner: Box<Inner> = unsafe {
            mem::transmute(inner)
        };
        drop(inner);
    }
}

impl Drop for Pulse {
    fn drop(&mut self) {
        self.set(TX_DROP);
        self.wake();
        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner)
    }
}

impl Pulse {
    /// Create a Pulse from a usize. This is naturally unsafe.
    pub unsafe fn cast_from_usize(ptr: usize) -> Pulse {
        Pulse {
            inner: mem::transmute(ptr)
        }
    }

    /// Convert a trigger to a `usize`, This is unsafe
    /// and it will kill your kittens if you are not careful
    pub unsafe fn cast_to_usize(self) -> usize {
        let us = mem::transmute(self.inner);
        mem::forget(self);
        us
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    fn set(&self, state: usize) -> usize {
        self.inner().state.fetch_or(state, Ordering::Relaxed)
    }

    fn wake(&self) {
        let id = unsafe { mem::transmute(self.inner) };
        match self.inner().waiting.take() {
            None => (),
            Some(v) => Waiting::wake(v, id)
        }
    }

    /// Pulse the `pulse` which will transition the `Signal` out from pending
    /// to ready. This moves the pulse so that it can only be fired once.
    pub fn pulse(self) {
        self.set(PULSED);
        self.wake();

        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner);
        unsafe { mem::forget(self) }
    }
}

unsafe impl Send for Signal {}

/// A `Signal` represents listens for a `pulse` to occur in the system. A
/// `Signal` has one of three states. Pending, Pulsed, or Errored. Pending
/// means the pulse has not fired, but still exists. Pulsed meaning the
/// pulse has fired, and no longer exists. Errored means the pulse was dropped
/// without firing. This normally means a programming error of some sort.
pub struct Signal {
    inner: *mut Inner
}

impl fmt::Debug for Signal {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "Signal(id={:?}, pending={:?})", self.id(), self.is_pending())
    }
}

impl Clone for Signal {
    fn clone(&self) -> Signal {
        self.inner().state.fetch_add(1, Ordering::Relaxed);
        Signal { inner: self.inner }
    }
}

impl Drop for Signal {
    #[inline]
    fn drop(&mut self) {
        let flag = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(flag, self.inner);
    }
}

impl Signal {
    /// Create a Signal and a Pulse that are associated.
    pub fn new() -> (Signal, Pulse) {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(2),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        (Signal {
            inner: inner
         },
         Pulse {
            inner: inner,
        })
    }

    /// Create a signal that is already pulsed
    pub fn pulsed() -> Signal {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(1 | PULSED),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        Signal { inner: inner }
    }

    #[inline]
    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    /// Read out the state of the Signal
    #[inline]
    fn state(&self) -> usize {
        self.inner().state.load(Ordering::Relaxed)
    }

    /// Check to see if the signal is pending. A signal
    #[inline]
    pub fn is_pending(&self) -> bool {
        self.state() & TX_FLAGS == 0
    }

    /// Add a waiter to a waitlist
    fn add_to_waitlist(&self, waiter: Box<Waiting>) -> usize {
        let id = waiter.id();

        self.inner().waiting.replace_and_set_next(waiter);

        // if armed fire now
        if !self.is_pending() {
            if let Some(t) = self.inner().waiting.take() {
                Waiting::wake(t, self.id());
            }
        }
        id
    }

    /// Remove Waiter with `id` from the waitlist
    fn remove_from_waitlist(&self, id: usize) {
        let mut wl = self.inner().waiting.take();
        while let Some(mut w) = wl {
            let next = w.next.take();
            if w.id() != id {
                self.add_to_waitlist(w);
            }
            wl = next;
        }
    }

    /// Arm a pulse to wake
    fn arm(self, waiter: Box<Waiting>) -> ArmedSignal {
        let id = self.add_to_waitlist(waiter);
        ArmedSignal {
            id: id,
            pulse: self
        }
    }

    /// This is a unique id that can be used to identify the signal from others
    /// See `Select` for how this api is useful.
    pub fn id(&self) -> usize {
        unsafe { mem::transmute_copy(&self.inner) }
    }

    /// Block the current thread until a `pulse` is ready.
    /// This will block indefinably if the pulse never fires.
    #[inline]
    pub fn wait(self) -> Result<(), WaitError> {
        if !self.is_pending() {
            let state = self.state();
            return if (state & PULSED) == PULSED {
                Ok(())
            } else {
                Err(WaitError::Dropped)
            };
        } else {
            SCHED.with(|sched| {
                sched.borrow().wait(self)
            })
        }
    }

    /// Block until either the pulse is sent, or the timeout is reached
    pub fn wait_timeout_ms(self, ms: u32) -> Result<(), TimeoutError> {
        SCHED.with(|sched| {
            sched.borrow().wait_timeout_ms(self, ms)
        })
    }
}

impl IntoRawPtr for Pulse {
    unsafe fn into_raw(self) -> *mut () {
        let inner = self.inner;
        mem::forget(self);
        mem::transmute(inner)
    }
}

impl FromRawPtr for Pulse {
    unsafe fn from_raw(ptr: *mut ()) -> Pulse {
        Pulse { inner: mem::transmute(ptr) }
    }
}

/// Represents the possible errors that can occur on a `Signal`
#[derive(Debug, PartialEq, Eq)]
pub enum WaitError {
    /// The `Pulse` was dropped before it could `Pulse`
    Dropped
}

/// Represents the possible errors from a wait timeout
#[derive(Debug, PartialEq, Eq)]
pub enum TimeoutError {
    /// A `WaitError` has occurred
    Error(WaitError),
    /// The `Signal` timed-out before a `Pulse` was observed.
    Timeout
}

struct ArmedSignal {
    pulse: Signal,
    id: usize
}

impl Deref for ArmedSignal {
    type Target = Signal;

    fn deref(&self) -> &Signal { &self.pulse }
}

impl ArmedSignal {
    fn disarm(self) -> Signal {
        self.remove_from_waitlist(self.id);
        self.pulse
    }
}

/// allows an object to assert a wait signal
pub trait Signals {
    /// Get a signal from a object
    fn signal(&self) -> Signal;

    /// Block the current thread until the object
    /// assets a pulse.
    fn wait(&self) -> Result<(), WaitError> {
        let signal = self.signal();
        signal.wait()
    }

    /// Block the current thread until the object
    /// assets a pulse. Or until the timeout has been asserted.
    fn wait_timeout_ms(&self, ms: u32) -> Result<(), TimeoutError> {
        let signal = self.signal();
        signal.wait_timeout_ms(ms)
    }
}

/// This is the hook into the async wait methods provided
/// by `pulse`. It is required for the user to override
/// the current system scheduler.
pub trait Scheduler {
    /// Wait until the signal is made `ready` or `errored`
    fn wait(&self, signal: Signal) -> Result<(), WaitError>;

    /// Wait until the signal is made `ready` or `errored` or the
    /// timeout has been reached.
    fn wait_timeout_ms(&self, signal: Signal, timeout: u32) -> Result<(), TimeoutError>;
}

/// This is the `default` system scheduler that is used if no
/// user provided scheduler is installed. It is very basic
/// and will block the OS thread using `thread::park`
pub struct ThreadScheduler;

impl Scheduler for ThreadScheduler {
    fn wait(&self, signal: Signal) -> Result<(), WaitError> {
        loop {
            let id = signal.add_to_waitlist(Waiting::thread());
            if signal.is_pending() {
                thread::park();
            }
            signal.remove_from_waitlist(id);

            if !signal.is_pending() {
                let state = signal.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(WaitError::Dropped)
                };
            }
        }
    }

    fn wait_timeout_ms(&self, signal: Signal, ms: u32) -> Result<(), TimeoutError> {
        let mut now = (precise_time_s() * 1000.) as u64;
        let end = now + ms as u64;

        loop {
            let id = signal.add_to_waitlist(Waiting::thread());
            if signal.is_pending() {
                now = (precise_time_s() * 1000.) as u64;
                if now > end {
                    return Err(TimeoutError::Timeout)
                }
                thread::park_timeout_ms((end - now) as u32);
            }
            signal.remove_from_waitlist(id);

            if !signal.is_pending() {
                let state = signal.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(TimeoutError::Error(WaitError::Dropped))
                };
            }
        }
    }
}

/// The TLS scheduler
thread_local!(static SCHED: RefCell<Box<Scheduler>> = RefCell::new(Box::new(ThreadScheduler)));

/// Replace the current Scheduler with your own supplied scheduler.
/// all `wait()` commands will be run through this scheduler now.
///
/// This will return the current TLS scheduler, which may be useful
/// to restore it later.
pub fn swap_scheduler(mut sched: Box<Scheduler>) -> Box<Scheduler> {
    use std::mem;

    SCHED.with(|s| {
        mem::swap(&mut *s.borrow_mut(), &mut sched);
    });

    sched
}

/// Call the suppled closure using the supplied schedulee
pub fn with_scheduler<F>(f: F, sched: Box<Scheduler>) -> Box<Scheduler> where F: FnOnce() {
    let old = swap_scheduler(sched);
    f();
    swap_scheduler(old)
}<|endoftext|>


<commit_before>extern crate byteorder;
extern crate crc;
extern crate inflate;
extern crate number_prefix;
#[macro_use]
extern crate slog;

use byteorder::ReadBytesExt;

use crc::crc32::Hasher32;

use std::io::{
    BufRead,
    Error,
    ErrorKind,
    Read,
    Seek,
    SeekFrom,
    Write
};

use std::str;

const GZIP_IDENTIFIER: [u8; 2] = [0x1f, 0x8b];
const BGZF_IDENTIFIER: [u8; 2] = [0x42, 0x43];

const DEFLATE: u8 = 8;

const EXTRA: u8 = 1 << 2;

pub fn version() -> &'static str {
    return option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
}

enum BGZFBlockInformation {
    EOF,
    Size(u32)
}

pub trait Rescuable: BufRead + Seek {}
impl<T: BufRead + Seek> Rescuable for T {}

fn check_block_header(reader: &mut Rescuable, logger: &slog::Logger) -> Result<BGZFBlockInformation, Error> {
    let mut gzip_identifier = [0u8; 2];
    let read_bytes = reader.read(&mut gzip_identifier)?;
    if read_bytes == 0 {
        return Ok(BGZFBlockInformation::EOF);
    }
    if read_bytes != 2 || gzip_identifier != GZIP_IDENTIFIER {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: gzip identitifer not found"));
    }

    let mut compression_method = [0u8; 1];
    reader.read_exact(&mut compression_method)?;
    if compression_method[0] != DEFLATE {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: gzip compression method is not deflate"));
    }

    let mut flags = [0u8; 1];
    reader.read_exact(&mut flags)?;
    if flags[0] != EXTRA {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: unexpected gzip flags"));
    }

    let mut modification_time = [0u8; 4];
    reader.read_exact(&mut modification_time)?;

    let mut extra_flags = [0u8; 1];
    reader.read_exact(&mut extra_flags)?;

    let mut operating_system = [0u8; 1];
    reader.read_exact(&mut operating_system)?;

    let mut block_size = 0u16;

    let extra_field_length = reader.read_u16::<byteorder::LittleEndian>()?;
    debug!(logger, "\tExtra field length of {} bytes", extra_field_length);

    let mut remaining_extra_field_length = extra_field_length;
    while remaining_extra_field_length > 0 {
        let mut subfield_identifier = [0u8; 2];
        reader.read_exact(&mut subfield_identifier)?;

        let subfield_length = reader.read_u16::<byteorder::LittleEndian>()?;
        debug!(logger, "\t\tSubfield length of {} bytes", subfield_length);

        if subfield_identifier == BGZF_IDENTIFIER {
            debug!(logger, "\t\t\tSubfield is bgzf metadata");

            if subfield_length != 2 {
                return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: bgzf block size is not a 16 bits number"));
            }

            block_size = reader.read_u16::<byteorder::LittleEndian>()? + 1;
            debug!(logger, "\t\t\t\tbgzf block size is {} bytes", block_size);
        } else {
            reader.seek(SeekFrom::Current(subfield_length as i64))?;
        }

        remaining_extra_field_length -= 4 + subfield_length;
    }
    if block_size == 0 {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: bgzf block size not found in gzip extra field"));
    }

    Ok(BGZFBlockInformation::Size((block_size - extra_field_length - 20u16) as u32))
}

fn check_block_payload(reader: &mut Rescuable, deflated_payload_size: u32, logger: &slog::Logger) -> Result<BGZFBlockInformation, Error> {
    let mut deflated_bytes = vec![];
    {
        let mut deflate_reader = reader.take(deflated_payload_size as u64);
        deflate_reader.read_to_end(&mut deflated_bytes)?;
    }

    let mut data_crc32 = [0u8; 4];
    reader.read_exact(&mut data_crc32)?;

    let data_size = reader.read_u32::<byteorder::LittleEndian>()?;
    debug!(logger, "\tData size is {} bytes", data_size);

    let inflated_bytes = match inflate::inflate_bytes(&deflated_bytes) {
        Ok(inflated_bytes) => inflated_bytes,
        Err(error) => return Err(Error::new(ErrorKind::InvalidData, format!("Invalid bam file: unable to inflate payload: {}", error))),
    };

    let mut payload_digest = crc::crc32::Digest::new(crc::crc32::IEEE);
    payload_digest.write(&inflated_bytes);
    let payload_crc32 = payload_digest.sum32();

    if data_crc32[0] != ((payload_crc32 & 0xff) as u8) ||
       data_crc32[1] != (((payload_crc32 >> 8) & 0xff) as u8) ||
       data_crc32[2] != (((payload_crc32 >> 16) & 0xff) as u8) ||
       data_crc32[3] != (((payload_crc32 >> 24) & 0xff) as u8) {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: incorrect payload CRC32"));
    }

    let inflated_payload_size = inflated_bytes.len();

    if data_size as usize != inflated_payload_size {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: incorrect payload size"));
    }

    Ok(BGZFBlockInformation::Size(data_size))
}

fn check_block(reader: &mut Rescuable, logger: &slog::Logger) -> Result<BGZFBlockInformation, Error> {
    let deflated_payload_size = match check_block_header(reader, &logger)? {
        BGZFBlockInformation::EOF => return Ok(BGZFBlockInformation::EOF),
        BGZFBlockInformation::Size(deflated_payload_size) => deflated_payload_size,
    };

    let payload_position = reader.seek(SeekFrom::Current(0i64))?;

    match check_block_payload(reader, deflated_payload_size, &logger) {
        Ok(bgzf_information) => Ok(bgzf_information),
        Err(error) => {
            reader.seek(SeekFrom::Start(payload_position + deflated_payload_size as u64 + 8u64))?;
            Err(error)
        }
    }
}

pub fn check(reader: &mut Rescuable, quiet: bool, logger: &slog::Logger) -> Result<(), Error> {
    info!(logger, "Checking integrity…");

    let mut blocks_count = 0u64;
    let mut blocks_size = 0u64;
    let mut bad_blocks_count = 0u64;
    let mut bad_blocks_size = 0u64;
    let mut truncated = false;
    let mut data_size = 0u32;
    loop {
        let block_offset = reader.seek(SeekFrom::Current(0))?;
        debug!(logger, "Checking block {} at offset {}", blocks_count + 1, block_offset);

        match check_block(reader, &logger) {
            Ok(bgzf_size) => {
                data_size = match bgzf_size {
                    BGZFBlockInformation::EOF => {
                        if data_size != 0u32 {
                            truncated = true;
                            if quiet {
                                return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: unexpected end of file while last bgzf block was not empty"));
                            }
                        }
                        break
                    },
                    BGZFBlockInformation::Size(data_size) => data_size,
                };
            },
            Err(error) => {
                if quiet {
                    return Err(error);
                }
                bad_blocks_count += 1;
                let current_offset = reader.seek(SeekFrom::Current(0))?;
                bad_blocks_size += current_offset - block_offset;
            }
        }

        blocks_count += 1;
        blocks_size += data_size as u64;
    }

    if !quiet {
        println!("bam file statistics:");
        match number_prefix::binary_prefix(blocks_size as f64) {
            number_prefix::Standalone(_) => println!("{: >7} bgzf {} found ({} {} of bam payload)", blocks_count, if blocks_count > 1 { "blocks" } else { "block" }, blocks_size, if blocks_size > 1 { "bytes" } else { "byte" }),
            number_prefix::Prefixed(prefix, number) => println!("{: >7} bgzf {} found ({:.0} {}B of bam payload)", blocks_count, if blocks_count > 1 { "blocks" } else { "block" }, number, prefix),
        }
        println!("{: >7} corrupted {} found ({:.2}% of total)", bad_blocks_count, if bad_blocks_count > 1 { "blocks" } else { "block" }, if blocks_count > 0 { (bad_blocks_count * 100) / blocks_count } else { 0 });
        match number_prefix::binary_prefix(bad_blocks_size as f64) {
            number_prefix::Standalone(_) => println!("{: >7} {} of bam payload lost ({:.2}% of total)", bad_blocks_size, if bad_blocks_size > 1 { "bytes" } else { "byte" }, if blocks_size > 0 { (bad_blocks_size * 100) / blocks_size } else { 0 }),
            number_prefix::Prefixed(prefix, number) => println!("{: >7.0} {}B of bam payload lost ({:.2}% of total)", number, prefix, if blocks_size > 0 { (bad_blocks_size * 100) / blocks_size } else { 0 }),
        }
        if truncated {
            println!("        file truncated");
        }
    }

    if bad_blocks_count > 0 {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: corrupted bgzf blocks found"));
    }

    if truncated {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: unexpected end of file while last bgzf block was not empty"));
    }

    Ok(())
}

pub fn rescue(reader: &mut Rescuable, writer: &mut Write, logger: &slog::Logger) -> Result<(), Error> {
    info!(logger, "Rescuing file…");

    error!(logger, "bamrescue::rescue() is not yet implemented");
    unimplemented!();
}
<commit_msg>Take the bad blocks size into account in the total size<commit_after>extern crate byteorder;
extern crate crc;
extern crate inflate;
extern crate number_prefix;
#[macro_use]
extern crate slog;

use byteorder::ReadBytesExt;

use crc::crc32::Hasher32;

use std::io::{
    BufRead,
    Error,
    ErrorKind,
    Read,
    Seek,
    SeekFrom,
    Write
};

use std::str;

const GZIP_IDENTIFIER: [u8; 2] = [0x1f, 0x8b];
const BGZF_IDENTIFIER: [u8; 2] = [0x42, 0x43];

const DEFLATE: u8 = 8;

const EXTRA: u8 = 1 << 2;

pub fn version() -> &'static str {
    return option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
}

enum BGZFBlockInformation {
    EOF,
    Size(u32)
}

pub trait Rescuable: BufRead + Seek {}
impl<T: BufRead + Seek> Rescuable for T {}

fn check_block_header(reader: &mut Rescuable, logger: &slog::Logger) -> Result<BGZFBlockInformation, Error> {
    let mut gzip_identifier = [0u8; 2];
    let read_bytes = reader.read(&mut gzip_identifier)?;
    if read_bytes == 0 {
        return Ok(BGZFBlockInformation::EOF);
    }
    if read_bytes != 2 || gzip_identifier != GZIP_IDENTIFIER {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: gzip identitifer not found"));
    }

    let mut compression_method = [0u8; 1];
    reader.read_exact(&mut compression_method)?;
    if compression_method[0] != DEFLATE {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: gzip compression method is not deflate"));
    }

    let mut flags = [0u8; 1];
    reader.read_exact(&mut flags)?;
    if flags[0] != EXTRA {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: unexpected gzip flags"));
    }

    let mut modification_time = [0u8; 4];
    reader.read_exact(&mut modification_time)?;

    let mut extra_flags = [0u8; 1];
    reader.read_exact(&mut extra_flags)?;

    let mut operating_system = [0u8; 1];
    reader.read_exact(&mut operating_system)?;

    let mut block_size = 0u16;

    let extra_field_length = reader.read_u16::<byteorder::LittleEndian>()?;
    debug!(logger, "\tExtra field length of {} bytes", extra_field_length);

    let mut remaining_extra_field_length = extra_field_length;
    while remaining_extra_field_length > 0 {
        let mut subfield_identifier = [0u8; 2];
        reader.read_exact(&mut subfield_identifier)?;

        let subfield_length = reader.read_u16::<byteorder::LittleEndian>()?;
        debug!(logger, "\t\tSubfield length of {} bytes", subfield_length);

        if subfield_identifier == BGZF_IDENTIFIER {
            debug!(logger, "\t\t\tSubfield is bgzf metadata");

            if subfield_length != 2 {
                return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: bgzf block size is not a 16 bits number"));
            }

            block_size = reader.read_u16::<byteorder::LittleEndian>()? + 1;
            debug!(logger, "\t\t\t\tbgzf block size is {} bytes", block_size);
        } else {
            reader.seek(SeekFrom::Current(subfield_length as i64))?;
        }

        remaining_extra_field_length -= 4 + subfield_length;
    }
    if block_size == 0 {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: bgzf block size not found in gzip extra field"));
    }

    Ok(BGZFBlockInformation::Size((block_size - extra_field_length - 20u16) as u32))
}

fn check_block_payload(reader: &mut Rescuable, deflated_payload_size: u32, logger: &slog::Logger) -> Result<BGZFBlockInformation, Error> {
    let mut deflated_bytes = vec![];
    {
        let mut deflate_reader = reader.take(deflated_payload_size as u64);
        deflate_reader.read_to_end(&mut deflated_bytes)?;
    }

    let mut data_crc32 = [0u8; 4];
    reader.read_exact(&mut data_crc32)?;

    let data_size = reader.read_u32::<byteorder::LittleEndian>()?;
    debug!(logger, "\tData size is {} bytes", data_size);

    let inflated_bytes = match inflate::inflate_bytes(&deflated_bytes) {
        Ok(inflated_bytes) => inflated_bytes,
        Err(error) => return Err(Error::new(ErrorKind::InvalidData, format!("Invalid bam file: unable to inflate payload: {}", error))),
    };

    let mut payload_digest = crc::crc32::Digest::new(crc::crc32::IEEE);
    payload_digest.write(&inflated_bytes);
    let payload_crc32 = payload_digest.sum32();

    if data_crc32[0] != ((payload_crc32 & 0xff) as u8) ||
       data_crc32[1] != (((payload_crc32 >> 8) & 0xff) as u8) ||
       data_crc32[2] != (((payload_crc32 >> 16) & 0xff) as u8) ||
       data_crc32[3] != (((payload_crc32 >> 24) & 0xff) as u8) {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: incorrect payload CRC32"));
    }

    let inflated_payload_size = inflated_bytes.len();

    if data_size as usize != inflated_payload_size {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: incorrect payload size"));
    }

    Ok(BGZFBlockInformation::Size(data_size))
}

fn check_block(reader: &mut Rescuable, logger: &slog::Logger) -> Result<BGZFBlockInformation, Error> {
    let deflated_payload_size = match check_block_header(reader, &logger)? {
        BGZFBlockInformation::EOF => return Ok(BGZFBlockInformation::EOF),
        BGZFBlockInformation::Size(deflated_payload_size) => deflated_payload_size,
    };

    let payload_position = reader.seek(SeekFrom::Current(0i64))?;

    match check_block_payload(reader, deflated_payload_size, &logger) {
        Ok(bgzf_information) => Ok(bgzf_information),
        Err(error) => {
            reader.seek(SeekFrom::Start(payload_position + deflated_payload_size as u64 + 8u64))?;
            Err(error)
        }
    }
}

pub fn check(reader: &mut Rescuable, quiet: bool, logger: &slog::Logger) -> Result<(), Error> {
    info!(logger, "Checking integrity…");

    let mut blocks_count = 0u64;
    let mut blocks_size = 0u64;
    let mut bad_blocks_count = 0u64;
    let mut bad_blocks_size = 0u64;
    let mut truncated = false;
    let mut data_size = 0u32;
    loop {
        let block_offset = reader.seek(SeekFrom::Current(0))?;
        debug!(logger, "Checking block {} at offset {}", blocks_count + 1, block_offset);

        match check_block(reader, &logger) {
            Ok(bgzf_size) => {
                data_size = match bgzf_size {
                    BGZFBlockInformation::EOF => {
                        if data_size != 0u32 {
                            truncated = true;
                            if quiet {
                                return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: unexpected end of file while last bgzf block was not empty"));
                            }
                        }
                        break
                    },
                    BGZFBlockInformation::Size(data_size) => data_size,
                };
                blocks_size += data_size as u64;
            },
            Err(error) => {
                if quiet {
                    return Err(error);
                }
                bad_blocks_count += 1;
                let current_offset = reader.seek(SeekFrom::Current(0))?;
                blocks_size += current_offset - block_offset;
                bad_blocks_size += current_offset - block_offset;
            }
        }

        blocks_count += 1;
    }

    if !quiet {
        println!("bam file statistics:");
        match number_prefix::binary_prefix(blocks_size as f64) {
            number_prefix::Standalone(_) => println!("{: >7} bgzf {} found ({} {} of bam payload)", blocks_count, if blocks_count > 1 { "blocks" } else { "block" }, blocks_size, if blocks_size > 1 { "bytes" } else { "byte" }),
            number_prefix::Prefixed(prefix, number) => println!("{: >7} bgzf {} found ({:.0} {}B of bam payload)", blocks_count, if blocks_count > 1 { "blocks" } else { "block" }, number, prefix),
        }
        println!("{: >7} corrupted {} found ({:.2}% of total)", bad_blocks_count, if bad_blocks_count > 1 { "blocks" } else { "block" }, if blocks_count > 0 { (bad_blocks_count * 100) / blocks_count } else { 0 });
        match number_prefix::binary_prefix(bad_blocks_size as f64) {
            number_prefix::Standalone(_) => println!("{: >7} {} of bam payload lost ({:.2}% of total)", bad_blocks_size, if bad_blocks_size > 1 { "bytes" } else { "byte" }, if blocks_size > 0 { (bad_blocks_size * 100) / blocks_size } else { 0 }),
            number_prefix::Prefixed(prefix, number) => println!("{: >7.0} {}B of bam payload lost ({:.2}% of total)", number, prefix, if blocks_size > 0 { (bad_blocks_size * 100) / blocks_size } else { 0 }),
        }
        if truncated {
            println!("        file truncated");
        }
    }

    if bad_blocks_count > 0 {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: corrupted bgzf blocks found"));
    }

    if truncated {
        return Err(Error::new(ErrorKind::InvalidData, "Invalid bam file: unexpected end of file while last bgzf block was not empty"));
    }

    Ok(())
}

pub fn rescue(reader: &mut Rescuable, writer: &mut Write, logger: &slog::Logger) -> Result<(), Error> {
    info!(logger, "Rescuing file…");

    error!(logger, "bamrescue::rescue() is not yet implemented");
    unimplemented!();
}
<|endoftext|>