<commit_before>extern crate num_cpus;
extern crate itertools;
extern crate rand;
extern crate crossbeam;

use self::rand::Rng;
use self::itertools::Itertools;
use self::crossbeam::{scope, ScopedJoinHandle};

use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::sync::{Mutex, RwLock, MutexGuard};

use task::{TaskGenerator, Task};
use candidate::{WorkingCandidate, Candidate};
use solution::Solution;
use scaling::{ScalingFunction, proportionate};
use result::{Result as AbcResult, Error as AbcError};
pub struct Hive<S: Solution> {
    workers: usize,
    observers: usize,
    retries: usize,

    working: Vec<RwLock<WorkingCandidate<S>>>,
    best: Mutex<Candidate<S>>,
    tasks: Mutex<Option<TaskGenerator>>,

    threads: usize,
    scale: Box<ScalingFunction>,
}

impl<S: Solution + Debug> Debug for Hive<S> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        for mutex in (&self.working).iter() {
            let working = mutex.read().unwrap();
            try!(write!(f, "..{:?}..\n", working.candidate));
        }
        let best_candidate = self.get().unwrap();
        write!(f, ">>{:?}<<", *best_candidate)
    }
}

impl<S: Solution> Hive<S> {
    pub fn new(workers: usize, observers: usize, retries: usize) -> Hive<S> {
        if workers == 0 {
            panic!("Hive must have at least one worker.");
        }

        let mut candidates = (0..workers)
            .map(|_| Candidate::new(S::make()))
            .collect::<Vec<_>>();

        let best = {
            let best_candidate = candidates.iter()
                .fold1(|best, next| if next.fitness > best.fitness { next } else { best })
                .unwrap();
            Mutex::new(best_candidate.clone())
        };

        let working = candidates.drain(..)
            .map(|c| RwLock::new(WorkingCandidate::new(c, retries))).collect::<Vec<_>>();

        Hive {
            workers: workers,
            observers: observers,
            retries: retries,

            working: working,
            best: best,
            tasks: Mutex::new(None),

            threads: num_cpus::get(),
            scale: proportionate(),
        }
    }

    pub fn set_threads(mut self, threads: usize) -> Hive<S> {
        self.threads = threads;
        self
    }

    pub fn set_scaling(mut self, scale: Box<ScalingFunction>) -> Hive<S> {
        self.scale = scale;
        self
    }

    fn current_working(&self) -> AbcResult<Vec<Candidate<S>>> {
        let mut current_working = Vec::with_capacity(self.working.len());
        for candidate_mutex in &self.working {
            let read_guard = try!(candidate_mutex.read());
            current_working.push(read_guard.candidate.clone())
        }
        Ok(current_working)
    }

    fn consider_improvement(&self, candidate: &Candidate<S>) -> AbcResult<()> {
        let mut best_guard = try!(self.best.lock());
        if candidate.fitness > best_guard.fitness {
            *best_guard = candidate.clone();
        }
        Ok(())
    }

    fn work_on(&self, current_working: &[Candidate<S>], n: usize) -> AbcResult<()> {
        let variant = Candidate::new(S::explore(current_working, n));

        let mut write_guard = try!(self.working[n].write());
        if variant.fitness > write_guard.candidate.fitness {
            *write_guard = WorkingCandidate::new(variant, self.retries);
            try!(self.consider_improvement(&write_guard.candidate));
        } else {
            write_guard.deplete();
            // Scouting has been folded into the working process
            if write_guard.expired() {
                let candidate = Candidate::new(S::make());
                *write_guard = WorkingCandidate::new(candidate, self.retries);
                try!(self.consider_improvement(&write_guard.candidate));
            }
        }
        Ok(())
    }

    fn choose(&self, current_working: &[Candidate<S>], rng: &mut Rng) -> usize {
        let fitnesses = (self.scale)(current_working.iter()
            .map(|candidate| candidate.fitness)
            .collect::<Vec<f64>>());

        let running_totals = fitnesses.iter()
            .scan(0f64, |total, fitness| {
                *total += *fitness;
                Some(*total)
            })
            .collect::<Vec<f64>>();

        let total_fitness = running_totals.last().unwrap();
        let choice_point = rng.next_f64() * total_fitness;

        for (i, total) in running_totals.iter().enumerate() {
            if *total > choice_point {
                return i;
            }
        }
        unreachable!();
    }

    fn execute(&self, task: &Task, rng: &mut Rng) -> AbcResult<()> {
        let current_working = try!(self.current_working());
        let index = match *task {
            Task::Worker(n) => n,
            Task::Observer(_) => self.choose(&current_working, rng),
        };
        self.work_on(&current_working, index)
    }

    fn run(&self, tasks: TaskGenerator) -> AbcResult<()> {
        let mut guard = try!(self.tasks.lock());
        *guard = Some(tasks);
        drop(guard);

        scope(|scope| {

            // We need to use a mut and a for loop in order to make the
            // lifetimes work out for the scoped threads.
            let mut handles: Vec<ScopedJoinHandle<AbcResult<()>>> =
                Vec::with_capacity(self.threads);

            for _ in 0..self.threads {
                handles.push(scope.spawn(|| {
                    let mut rng = rand::thread_rng();
                    loop {
                        let mut guard = try!(self.tasks.lock());
                        let task = guard.as_mut().and_then(|gen| gen.next());
                        drop(guard);

                        match task {
                            Some(t) => try!(self.execute(&t, &mut rng)),
                            None => break
                        };
                    }
                    Ok(())
                }));
            }

            for handle in handles {
                try!(handle.join());
            }

            Ok(())
        })
    }

    pub fn run_for_rounds(&self, rounds: usize) -> AbcResult<Candidate<S>> {
        let tasks = TaskGenerator::new(self.workers, self.observers).max_rounds(rounds);
        try!(self.run(tasks));
        let guard = try!(self.get());
        Ok(guard.clone())
    }

    /// Get a guard for the current best solution found by the hive.
    ///
    /// If the hive is running, you should drop the guard returned by this
    /// function as soon as convenient, since the logic of the hive can block
    /// on the availability of the associated mutex. If you plan on performing
    /// expensive computations, you should `drop` the guard as soon as
    /// possible, or acquire and clone it within a small block, like this:
    ///
    /// ```
    /// # extern crate abc; use abc::{Solution, Candidate, Hive};
    /// # #[derive(Clone)] struct X;
    /// # impl Solution for X {
    /// #     fn make() -> X { X }
    /// #     fn evaluate_fitness(&self) -> f64 { 0_f64 }
    /// #     fn explore(field: &[Candidate<X>], n: usize) -> X { X }
    /// # }
    /// # fn main() {
    /// let hive: Hive<X> = Hive::new(5, 5, 5);
    /// let current_best = {
    ///     let guard = hive.get().unwrap();
    ///     guard.clone()
    /// };
    /// # }
    /// ```
    pub fn get(&self) -> AbcResult<MutexGuard<Candidate<S>>> {
        self.best.lock().map_err(AbcError::from)
    }

    pub fn stop(&self) -> AbcResult<()> {
        self.tasks.lock()
            .map_err(AbcError::from)
            .map(|mut guard| guard.as_mut().map_or((), |t| t.stop()))
    }

    pub fn get_round(&self) -> AbcResult<Option<usize>> {
        self.tasks.lock()
            .map_err(AbcError::from)
            .map(|guard| guard.as_ref().map(|tasks| tasks.round))
    }
}

impl<S: Solution> Drop for Hive<S> {
    fn drop(&mut self) {
        self.stop().unwrap()
    }
}<commit_msg>Several minor refactoring tweaks<commit_after>extern crate num_cpus;
extern crate itertools;
extern crate rand;
extern crate crossbeam;

use self::rand::Rng;
use self::itertools::Itertools;
use self::crossbeam::{scope, ScopedJoinHandle};

use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::sync::{Mutex, RwLock, MutexGuard};

use task::{TaskGenerator, Task};
use candidate::{WorkingCandidate, Candidate};
use solution::Solution;
use scaling::{ScalingFunction, proportionate};
use result::{Result as AbcResult, Error as AbcError};

pub struct Hive<S: Solution> {
    workers: usize,
    observers: usize,
    retries: usize,

    working: Vec<RwLock<WorkingCandidate<S>>>,
    best: Mutex<Candidate<S>>,
    tasks: Mutex<Option<TaskGenerator>>,

    threads: usize,
    scale: Box<ScalingFunction>,
}

impl<S: Solution + Debug> Debug for Hive<S> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        for mutex in (&self.working).iter() {
            let working = mutex.read().unwrap();
            try!(write!(f, "..{:?}..\n", working.candidate));
        }
        let best_candidate = self.get().unwrap();
        write!(f, ">>{:?}<<", *best_candidate)
    }
}

impl<S: Solution> Hive<S> {
    pub fn new(workers: usize, observers: usize, retries: usize) -> Hive<S> {
        if workers == 0 {
            panic!("Hive must have at least one worker.");
        }

        let mut candidates = (0..workers)
            .map(|_| Candidate::new(S::make()))
            .collect::<Vec<_>>();

        let best = {
            let best_candidate = candidates.iter()
                .fold1(|best, next| if next.fitness > best.fitness { next } else { best })
                .unwrap();
            Mutex::new(best_candidate.clone())
        };

        let working = candidates.drain(..)
            .map(|c| RwLock::new(WorkingCandidate::new(c, retries)))
            .collect::<Vec<_>>();

        Hive {
            workers: workers,
            observers: observers,
            retries: retries,

            working: working,
            best: best,
            tasks: Mutex::new(None),

            threads: num_cpus::get(),
            scale: proportionate(),
        }
    }

    pub fn set_threads(mut self, threads: usize) -> Hive<S> {
        self.threads = threads;
        self
    }

    pub fn set_scaling(mut self, scale: Box<ScalingFunction>) -> Hive<S> {
        self.scale = scale;
        self
    }

    fn current_working(&self) -> AbcResult<Vec<Candidate<S>>> {
        let mut current_working = Vec::with_capacity(self.working.len());
        for candidate_mutex in &self.working {
            let read_guard = try!(candidate_mutex.read());
            current_working.push(read_guard.candidate.clone())
        }
        Ok(current_working)
    }

    fn consider_improvement(&self, candidate: &Candidate<S>) -> AbcResult<()> {
        let mut best_guard = try!(self.best.lock());
        if candidate.fitness > best_guard.fitness {
            *best_guard = candidate.clone();
        }
        Ok(())
    }

    fn work_on(&self, current_working: &[Candidate<S>], n: usize) -> AbcResult<()> {
        let variant = Candidate::new(S::explore(current_working, n));

        let mut write_guard = try!(self.working[n].write());
        if variant.fitness > write_guard.candidate.fitness {
            *write_guard = WorkingCandidate::new(variant, self.retries);
            try!(self.consider_improvement(&write_guard.candidate));
        } else {
            write_guard.deplete();
            // Scouting has been folded into the working process
            if write_guard.expired() {
                let candidate = Candidate::new(S::make());
                *write_guard = WorkingCandidate::new(candidate, self.retries);
                try!(self.consider_improvement(&write_guard.candidate));
            }
        }
        Ok(())
    }

    fn choose(&self, current_working: &[Candidate<S>], rng: &mut Rng) -> usize {
        let fitnesses = (self.scale)(current_working.iter()
            .map(|candidate| candidate.fitness)
            .collect::<Vec<f64>>());

        let running_totals = fitnesses.iter()
            .scan(0f64, |total, fitness| {
                *total += *fitness;
                Some(*total)
            })
            .collect::<Vec<f64>>();

        let total_fitness = running_totals.last().unwrap();
        let choice_point = rng.next_f64() * total_fitness;

        for (i, total) in running_totals.iter().enumerate() {
            if *total > choice_point {
                return i;
            }
        }
        unreachable!();
    }

    fn execute(&self, task: &Task, rng: &mut Rng) -> AbcResult<()> {
        let current_working = try!(self.current_working());
        let index = match *task {
            Task::Worker(n) => n,
            Task::Observer(_) => self.choose(&current_working, rng),
        };
        self.work_on(&current_working, index)
    }

    fn run(&self, tasks: TaskGenerator) -> AbcResult<()> {
        let mut guard = try!(self.tasks.lock());
        *guard = Some(tasks);
        drop(guard);

        let mut handles: Vec<ScopedJoinHandle<AbcResult<()>>> = Vec::with_capacity(self.threads);

        scope(|scope| {
            for _ in 0..self.threads {
                handles.push(scope.spawn(|| {
                    let mut rng = rand::thread_rng();
                    loop {
                        let mut guard = try!(self.tasks.lock());
                        let task = guard.as_mut().and_then(|gen| gen.next());
                        drop(guard);

                        match task {
                            Some(t) => try!(self.execute(&t, &mut rng)),
                            None => return Ok(())
                        };
                    }
                }));
            }

            // Return Ok(()) only if all threads join cleanly.
            handles.drain(..).fold(Ok(()), |result, handle| result.and(handle.join()))
        })
    }

    pub fn run_for_rounds(&self, rounds: usize) -> AbcResult<Candidate<S>> {
        let tasks = TaskGenerator::new(self.workers, self.observers).max_rounds(rounds);
        try!(self.run(tasks));
        self.get().map(|guard| guard.clone())
    }

    /// Get a guard for the current best solution found by the hive.
    ///
    /// If the hive is running, you should drop the guard returned by this
    /// function as soon as convenient, since the logic of the hive can block
    /// on the availability of the associated mutex. If you plan on performing
    /// expensive computations, you should `drop` the guard as soon as
    /// possible, or acquire and clone it within a small block, like this:
    ///
    /// ```
    /// # extern crate abc; use abc::{Solution, Candidate, Hive};
    /// # #[derive(Clone)] struct X;
    /// # impl Solution for X {
    /// #     fn make() -> X { X }
    /// #     fn evaluate_fitness(&self) -> f64 { 0_f64 }
    /// #     fn explore(field: &[Candidate<X>], n: usize) -> X { X }
    /// # }
    /// # fn main() {
    /// let hive: Hive<X> = Hive::new(5, 5, 5);
    /// let current_best = {
    ///     let guard = hive.get().unwrap();
    ///     guard.clone()
    /// };
    /// # }
    /// ```
    pub fn get(&self) -> AbcResult<MutexGuard<Candidate<S>>> {
        self.best.lock().map_err(AbcError::from)
    }

    pub fn stop(&self) -> AbcResult<()> {
        let mut tasks_guard = try!(self.tasks.lock());
        Ok(tasks_guard.as_mut().map_or((), |t| t.stop()))
    }

    pub fn get_round(&self) -> AbcResult<Option<usize>> {
        let tasks_guard = try!(self.tasks.lock());
        Ok(tasks_guard.as_ref().map(|tasks| tasks.round))
    }
}

impl<S: Solution> Drop for Hive<S> {
    fn drop(&mut self) {
        self.stop().unwrap()
    }
}<|endoftext|>


<commit_before>use std::fmt;
use std::str;

const ISBN_13_MULTIPLIERS: [u32; 13] = [1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1];

#[derive(Debug)]
pub struct Isbn {
    raw: String,
    values: Vec<u32>
}

#[derive(Debug)]
pub struct IsbnParseError {
    raw: String,
    error_type: IsbnParseErrorType,
}

#[derive(Debug)]
pub enum IsbnParseErrorType {
    FailedCheck10,
    FailedCheck13,
    WrongLength,
}

impl IsbnParseError {
    fn from_raw<T: Into<String>>(error_type: IsbnParseErrorType, s: T) -> IsbnParseError {
        IsbnParseError {
            raw: s.into(),
            error_type: error_type,
        }
    }
}

impl str::FromStr for Isbn {
    type Err = IsbnParseError;

    fn from_str(s: &str) -> Result<Isbn, Self::Err> {
        let values: Vec<_> = s.chars().filter_map(|c| as_value(c)).collect();
        match values.len() {
            10 => match check_10(&values) {
                true => Ok(Isbn { raw: s.to_owned(), values: values }),
                false => Err(IsbnParseError::from_raw(IsbnParseErrorType::FailedCheck10, s)),
            },
            13 => match check_13(&values) {
                true => Ok(Isbn { raw: s.to_owned(), values: values }),
                false => Err(IsbnParseError::from_raw(IsbnParseErrorType::FailedCheck13, s)),
            },
            _ => Err(IsbnParseError::from_raw(IsbnParseErrorType::WrongLength, s)),
        }
    }
}

impl fmt::Display for Isbn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.raw)
    }
}

fn check_10(s: &[u32]) -> bool {
    s.iter().cloned().enumerate().map(|(idx, n)| n * (10 - idx as u32)).sum::<u32>() % 11 == 0
}

fn check_13(s: &[u32]) -> bool {
    s.iter().zip(ISBN_13_MULTIPLIERS.iter()).map(|(a, b)| a * b).sum::<u32>() % 10 == 0
}

fn as_value(c: char) -> Option<u32> {
    match c {
        '0' => Some(0),
        '1' => Some(1),
        '2' => Some(2),
        '3' => Some(3),
        '4' => Some(4),
        '5' => Some(5),
        '6' => Some(6),
        '7' => Some(7),
        '8' => Some(8),
        '9' => Some(9),
        _ => None
    }
}

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

    #[test]
    fn isnb_10_good() {
        "99921-58-10-7".parse::<Isbn>().unwrap();
    }

    #[test]
    #[should_panic]
    fn isbn_10_bad() {
        "99921-58-10-8".parse::<Isbn>().unwrap();
    }

    #[test]
    fn isbn_13_good() {
        "978-0-306-40615-7".parse::<Isbn>().unwrap();
    }

    #[test]
    #[should_panic]
    fn isbn_13_bad() {
        "978-0-306-40615-8".parse::<Isbn>().unwrap();
    }
}
<commit_msg>scouting<commit_after>use std::fmt;
use std::str;

const ISBN_13_MULTIPLIERS: [u32; 13] = [1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1];

#[derive(Debug)]
pub struct Isbn {
    raw: String,
    values: Vec<u32>
}

#[derive(Debug)]
pub struct IsbnParseError {
    raw: String,
    error_type: IsbnParseErrorType,
}

#[derive(Debug)]
pub enum IsbnParseErrorType {
    FailedCheck10,
    FailedCheck13,
    WrongLength,
}

impl IsbnParseError {
    fn from_raw<T: Into<String>>(error_type: IsbnParseErrorType, s: T) -> IsbnParseError {
        IsbnParseError {
            raw: s.into(),
            error_type: error_type,
        }
    }
}

impl str::FromStr for Isbn {
    type Err = IsbnParseError;

    fn from_str(s: &str) -> Result<Isbn, Self::Err> {
        let values: Vec<_> = s.chars().filter_map(|c| as_value(c)).collect();
        match values.len() {
            10 => match check_10(&values) {
                true => Ok(Isbn { raw: s.to_owned(), values: values }),
                false => Err(IsbnParseError::from_raw(IsbnParseErrorType::FailedCheck10, s)),
            },
            13 => match check_13(&values) {
                true => Ok(Isbn { raw: s.to_owned(), values: values }),
                false => Err(IsbnParseError::from_raw(IsbnParseErrorType::FailedCheck13, s)),
            },
            _ => Err(IsbnParseError::from_raw(IsbnParseErrorType::WrongLength, s)),
        }
    }
}

impl fmt::Display for Isbn {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.raw)
    }
}

fn check_10(s: &[u32]) -> bool {
    s.iter().cloned().enumerate().map(|(idx, n)| n * (10 - idx as u32)).sum::<u32>() % 11 == 0
}

fn check_13(s: &[u32]) -> bool {
    s.iter().zip(ISBN_13_MULTIPLIERS.iter()).map(|(a, b)| a * b).sum::<u32>() % 10 == 0
}

fn as_value(c: char) -> Option<u32> {
    match c {
        '0' => Some(0),
        '1' => Some(1),
        '2' => Some(2),
        '3' => Some(3),
        '4' => Some(4),
        '5' => Some(5),
        '6' => Some(6),
        '7' => Some(7),
        '8' => Some(8),
        '9' => Some(9),
        _ => None
    }
}

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

    #[test]
    fn isnb_10_good() {
        assert!("99921-58-10-7".parse::<Isbn>().is_ok());
    }

    #[test]
    #[should_panic]
    fn isbn_10_bad() {
        assert!("99921-58-10-8".parse::<Isbn>().is_ok());
    }

    #[test]
    fn isbn_13_good() {
        assert!("978-0-306-40615-7".parse::<Isbn>().is_ok());
    }

    #[test]
    #[should_panic]
    fn isbn_13_bad() {
        assert!("978-0-306-40615-8".parse::<Isbn>().is_ok());
    }
}
<|endoftext|>


<commit_before>///! An item is line of text that read from `find` command or stdin together with
///! the internal states, such as selected or not
use std::borrow::Cow;
use std::cmp::min;
use std::default::Default;
use std::ops::Deref;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use regex::Regex;

use crate::ansi::{ANSIParser, AnsiString};
use crate::field::{parse_matching_fields, parse_transform_fields, FieldRange};
use crate::spinlock::{SpinLock, SpinLockGuard};
use crate::SkimItem;

//------------------------------------------------------------------------------
/// An item will store everything that one line input will need to be operated and displayed.
///
/// What's special about an item?
/// The simplest version of an item is a line of string, but things are getting more complex:
/// - The conversion of lower/upper case is slow in rust, because it involds unicode.
/// - We may need to interpret the ANSI codes in the text.
/// - The text can be transformed and limited while searching.
///
/// About the ANSI, we made assumption that it is linewise, that means no ANSI codes will affect
/// more than one line.
#[derive(Debug)]
pub struct DefaultSkimItem {
    /// The text that will be output when user press `enter`
    /// `Some(..)` => the original input is transformed, could not output `text` directly
    /// `None` => that it is safe to output `text` directly
    orig_text: Option<String>,

    /// The text that will be shown on screen and matched.
    text: AnsiString<'static>,

    matching_ranges: Option<Vec<(usize, usize)>>,
}

impl<'a> DefaultSkimItem {
    pub fn new(
        orig_text: String,
        ansi_enabled: bool,
        trans_fields: &[FieldRange],
        matching_fields: &[FieldRange],
        delimiter: &Regex,
    ) -> Self {
        let using_transform_fields = !trans_fields.is_empty();

        //        transformed | ANSI             | output
        //------------------------------------------------------
        //                    +- T -> trans+ANSI | ANSI
        //                    |                  |
        //      +- T -> trans +- F -> trans      | orig
        // orig |                                |
        //      +- F -> orig  +- T -> ANSI     ==| ANSI
        //                    |                  |
        //                    +- F -> orig       | orig

        let mut ansi_parser: ANSIParser = Default::default();

        let (orig_text, text) = if using_transform_fields && ansi_enabled {
            // ansi and transform
            let transformed = ansi_parser.parse_ansi(&parse_transform_fields(delimiter, &orig_text, trans_fields));
            (Some(orig_text), transformed)
        } else if using_transform_fields {
            // transformed, not ansi
            let transformed = parse_transform_fields(delimiter, &orig_text, trans_fields).into();
            (Some(orig_text), transformed)
        } else if ansi_enabled {
            // not transformed, ansi
            (None, ansi_parser.parse_ansi(&orig_text))
        } else {
            // normal case
            (None, orig_text.into())
        };

        let matching_ranges = if !matching_fields.is_empty() {
            Some(parse_matching_fields(delimiter, text.stripped(), matching_fields))
        } else {
            None
        };

        DefaultSkimItem {
            orig_text,
            text,
            matching_ranges,
        }
    }
}

impl SkimItem for DefaultSkimItem {
    #[inline]
    fn display(&self) -> Cow<AnsiString> {
        Cow::Borrowed(&self.text)
    }

    #[inline]
    fn text(&self) -> Cow<str> {
        Cow::Borrowed(self.text.stripped())
    }

    fn output(&self) -> Cow<str> {
        if self.orig_text.is_some() {
            if self.text.has_attrs() {
                let mut ansi_parser: ANSIParser = Default::default();
                let text = ansi_parser.parse_ansi(self.orig_text.as_ref().unwrap());
                text.into_inner()
            } else {
                Cow::Borrowed(self.orig_text.as_ref().unwrap())
            }
        } else {
            Cow::Borrowed(self.text.stripped())
        }
    }

    fn get_matching_ranges(&self) -> Option<&[(usize, usize)]> {
        self.matching_ranges.as_ref().map(|vec| vec as &[(usize, usize)])
    }
}

//------------------------------------------------------------------------------
pub type ItemIndex = (u32, u32);

//------------------------------------------------------------------------------
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Rank {
    pub score: i64,
    pub begin: i64,
    pub end: i64,
}

#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(dead_code)]
pub enum MatchedRange {
    ByteRange(usize, usize),
    // range of bytes
    Chars(Vec<usize>), // individual character indices matched
}

#[derive(Clone)]
pub struct MatchedItem {
    pub item: Arc<dyn SkimItem>,
    pub rank: Rank,
    pub matched_range: Option<MatchedRange>, // range of chars that matched the pattern
}

impl MatchedItem {
    pub fn builder(item: Arc<dyn SkimItem>) -> Self {
        MatchedItem {
            item,
            rank: Rank::default(),
            matched_range: None,
        }
    }

    pub fn matched_range(mut self, range: MatchedRange) -> Self {
        self.matched_range = Some(range);
        self
    }

    pub fn rank(mut self, rank: Rank) -> Self {
        self.rank = rank;
        self
    }

    pub fn build(self) -> Self {
        self
    }

    pub fn range_char_indices(&self) -> Option<Vec<usize>> {
        self.matched_range.as_ref().map(|r| match r {
            MatchedRange::ByteRange(start, end) => {
                let first = self.item.text()[..*start].chars().count();
                let last = first + self.item.text()[*start..*end].chars().count();
                (first..last).collect()
            }
            MatchedRange::Chars(vec) => vec.clone(),
        })
    }
}

//------------------------------------------------------------------------------
const ITEM_POOL_CAPACITY: usize = 1024;

pub struct ItemPool {
    length: AtomicUsize,
    pool: SpinLock<Vec<Arc<dyn SkimItem>>>,
    /// number of items that was `take`n
    taken: AtomicUsize,

    /// reverse first N lines as header
    reserved_items: SpinLock<Vec<Arc<dyn SkimItem>>>,
    lines_to_reserve: usize,
}

impl ItemPool {
    pub fn new() -> Self {
        Self {
            length: AtomicUsize::new(0),
            pool: SpinLock::new(Vec::with_capacity(ITEM_POOL_CAPACITY)),
            taken: AtomicUsize::new(0),
            reserved_items: SpinLock::new(Vec::new()),
            lines_to_reserve: 0,
        }
    }

    pub fn lines_to_reserve(mut self, lines_to_reserve: usize) -> Self {
        self.lines_to_reserve = lines_to_reserve;
        self
    }

    pub fn len(&self) -> usize {
        self.length.load(Ordering::SeqCst)
    }

    pub fn num_not_taken(&self) -> usize {
        self.length.load(Ordering::SeqCst) - self.taken.load(Ordering::SeqCst)
    }

    pub fn clear(&self) {
        let mut items = self.pool.lock();
        items.clear();
        let mut header_items = self.reserved_items.lock();
        header_items.clear();
        self.taken.store(0, Ordering::SeqCst);
        self.length.store(0, Ordering::SeqCst);
    }

    pub fn reset(&self) {
        // lock to ensure consistency
        let _items = self.pool.lock();
        self.taken.store(0, Ordering::SeqCst);
    }

    pub fn append(&self, mut items: Vec<Arc<dyn SkimItem>>) {
        let mut pool = self.pool.lock();
        let mut header_items = self.reserved_items.lock();

        let to_reserve = self.lines_to_reserve - header_items.len();
        if to_reserve > 0 {
            let to_reserve = min(to_reserve, items.len());
            header_items.extend_from_slice(&items[..to_reserve]);
            pool.extend_from_slice(&items[to_reserve..]);
        } else {
            pool.append(&mut items);
        }
        self.length.store(pool.len(), Ordering::SeqCst);
    }

    pub fn take(&self) -> ItemPoolGuard<Arc<dyn SkimItem>> {
        let guard = self.pool.lock();
        let taken = self.taken.swap(guard.len(), Ordering::SeqCst);
        ItemPoolGuard { guard, start: taken }
    }

    pub fn reserved(&self) -> ItemPoolGuard<Arc<dyn SkimItem>> {
        let guard = self.reserved_items.lock();
        ItemPoolGuard { guard, start: 0 }
    }
}

pub struct ItemPoolGuard<'a, T: Sized + 'a> {
    guard: SpinLockGuard<'a, Vec<T>>,
    start: usize,
}

impl<'mutex, T: Sized> Deref for ItemPoolGuard<'mutex, T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        &self.guard[self.start..]
    }
}

//------------------------------------------------------------------------------
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum RankCriteria {
    Score,
    Begin,
    End,
    NegScore,
    NegBegin,
    NegEnd,
}

pub fn parse_criteria(text: &str) -> Option<RankCriteria> {
    match text.to_lowercase().as_ref() {
        "score" => Some(RankCriteria::Score),
        "begin" => Some(RankCriteria::Begin),
        "end" => Some(RankCriteria::End),
        "-score" => Some(RankCriteria::NegScore),
        "-begin" => Some(RankCriteria::NegBegin),
        "-end" => Some(RankCriteria::NegEnd),
        _ => None,
    }
}
<commit_msg>[size] DefaultSkimItem -> 88B<commit_after>///! An item is line of text that read from `find` command or stdin together with
///! the internal states, such as selected or not
use std::borrow::Cow;
use std::cmp::min;
use std::default::Default;
use std::ops::Deref;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use regex::Regex;

use crate::ansi::{ANSIParser, AnsiString};
use crate::field::{parse_matching_fields, parse_transform_fields, FieldRange};
use crate::spinlock::{SpinLock, SpinLockGuard};
use crate::SkimItem;

//------------------------------------------------------------------------------
/// An item will store everything that one line input will need to be operated and displayed.
///
/// What's special about an item?
/// The simplest version of an item is a line of string, but things are getting more complex:
/// - The conversion of lower/upper case is slow in rust, because it involds unicode.
/// - We may need to interpret the ANSI codes in the text.
/// - The text can be transformed and limited while searching.
///
/// About the ANSI, we made assumption that it is linewise, that means no ANSI codes will affect
/// more than one line.
#[derive(Debug)]
pub struct DefaultSkimItem {
    /// The text that will be output when user press `enter`
    /// `Some(..)` => the original input is transformed, could not output `text` directly
    /// `None` => that it is safe to output `text` directly
    orig_text: Option<String>,

    /// The text that will be shown on screen and matched.
    text: AnsiString<'static>,

    // Option<Box<_>> to reduce memory use in normal cases where no matching ranges are specified.
    matching_ranges: Option<Box<Vec<(usize, usize)>>>,
}

impl<'a> DefaultSkimItem {
    pub fn new(
        orig_text: String,
        ansi_enabled: bool,
        trans_fields: &[FieldRange],
        matching_fields: &[FieldRange],
        delimiter: &Regex,
    ) -> Self {
        let using_transform_fields = !trans_fields.is_empty();

        //        transformed | ANSI             | output
        //------------------------------------------------------
        //                    +- T -> trans+ANSI | ANSI
        //                    |                  |
        //      +- T -> trans +- F -> trans      | orig
        // orig |                                |
        //      +- F -> orig  +- T -> ANSI     ==| ANSI
        //                    |                  |
        //                    +- F -> orig       | orig

        let mut ansi_parser: ANSIParser = Default::default();

        let (orig_text, text) = if using_transform_fields && ansi_enabled {
            // ansi and transform
            let transformed = ansi_parser.parse_ansi(&parse_transform_fields(delimiter, &orig_text, trans_fields));
            (Some(orig_text), transformed)
        } else if using_transform_fields {
            // transformed, not ansi
            let transformed = parse_transform_fields(delimiter, &orig_text, trans_fields).into();
            (Some(orig_text), transformed)
        } else if ansi_enabled {
            // not transformed, ansi
            (None, ansi_parser.parse_ansi(&orig_text))
        } else {
            // normal case
            (None, orig_text.into())
        };

        let matching_ranges = if !matching_fields.is_empty() {
            Some(Box::new(parse_matching_fields(
                delimiter,
                text.stripped(),
                matching_fields,
            )))
        } else {
            None
        };

        DefaultSkimItem {
            orig_text,
            text,
            matching_ranges,
        }
    }
}

impl SkimItem for DefaultSkimItem {
    #[inline]
    fn display(&self) -> Cow<AnsiString> {
        Cow::Borrowed(&self.text)
    }

    #[inline]
    fn text(&self) -> Cow<str> {
        Cow::Borrowed(self.text.stripped())
    }

    fn output(&self) -> Cow<str> {
        if self.orig_text.is_some() {
            if self.text.has_attrs() {
                let mut ansi_parser: ANSIParser = Default::default();
                let text = ansi_parser.parse_ansi(self.orig_text.as_ref().unwrap());
                text.into_inner()
            } else {
                Cow::Borrowed(self.orig_text.as_ref().unwrap())
            }
        } else {
            Cow::Borrowed(self.text.stripped())
        }
    }

    fn get_matching_ranges(&self) -> Option<&[(usize, usize)]> {
        self.matching_ranges.as_ref().map(|vec| vec as &[(usize, usize)])
    }
}

//------------------------------------------------------------------------------
pub type ItemIndex = (u32, u32);

//------------------------------------------------------------------------------
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Rank {
    pub score: i64,
    pub begin: i64,
    pub end: i64,
}

#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(dead_code)]
pub enum MatchedRange {
    ByteRange(usize, usize),
    // range of bytes
    Chars(Vec<usize>), // individual character indices matched
}

#[derive(Clone)]
pub struct MatchedItem {
    pub item: Arc<dyn SkimItem>,
    pub rank: Rank,
    pub matched_range: Option<MatchedRange>, // range of chars that matched the pattern
}

impl MatchedItem {
    pub fn builder(item: Arc<dyn SkimItem>) -> Self {
        MatchedItem {
            item,
            rank: Rank::default(),
            matched_range: None,
        }
    }

    pub fn matched_range(mut self, range: MatchedRange) -> Self {
        self.matched_range = Some(range);
        self
    }

    pub fn rank(mut self, rank: Rank) -> Self {
        self.rank = rank;
        self
    }

    pub fn build(self) -> Self {
        self
    }

    pub fn range_char_indices(&self) -> Option<Vec<usize>> {
        self.matched_range.as_ref().map(|r| match r {
            MatchedRange::ByteRange(start, end) => {
                let first = self.item.text()[..*start].chars().count();
                let last = first + self.item.text()[*start..*end].chars().count();
                (first..last).collect()
            }
            MatchedRange::Chars(vec) => vec.clone(),
        })
    }
}

//------------------------------------------------------------------------------
const ITEM_POOL_CAPACITY: usize = 1024;

pub struct ItemPool {
    length: AtomicUsize,
    pool: SpinLock<Vec<Arc<dyn SkimItem>>>,
    /// number of items that was `take`n
    taken: AtomicUsize,

    /// reverse first N lines as header
    reserved_items: SpinLock<Vec<Arc<dyn SkimItem>>>,
    lines_to_reserve: usize,
}

impl ItemPool {
    pub fn new() -> Self {
        Self {
            length: AtomicUsize::new(0),
            pool: SpinLock::new(Vec::with_capacity(ITEM_POOL_CAPACITY)),
            taken: AtomicUsize::new(0),
            reserved_items: SpinLock::new(Vec::new()),
            lines_to_reserve: 0,
        }
    }

    pub fn lines_to_reserve(mut self, lines_to_reserve: usize) -> Self {
        self.lines_to_reserve = lines_to_reserve;
        self
    }

    pub fn len(&self) -> usize {
        self.length.load(Ordering::SeqCst)
    }

    pub fn num_not_taken(&self) -> usize {
        self.length.load(Ordering::SeqCst) - self.taken.load(Ordering::SeqCst)
    }

    pub fn clear(&self) {
        let mut items = self.pool.lock();
        items.clear();
        let mut header_items = self.reserved_items.lock();
        header_items.clear();
        self.taken.store(0, Ordering::SeqCst);
        self.length.store(0, Ordering::SeqCst);
    }

    pub fn reset(&self) {
        // lock to ensure consistency
        let _items = self.pool.lock();
        self.taken.store(0, Ordering::SeqCst);
    }

    pub fn append(&self, mut items: Vec<Arc<dyn SkimItem>>) {
        let mut pool = self.pool.lock();
        let mut header_items = self.reserved_items.lock();

        let to_reserve = self.lines_to_reserve - header_items.len();
        if to_reserve > 0 {
            let to_reserve = min(to_reserve, items.len());
            header_items.extend_from_slice(&items[..to_reserve]);
            pool.extend_from_slice(&items[to_reserve..]);
        } else {
            pool.append(&mut items);
        }
        self.length.store(pool.len(), Ordering::SeqCst);
    }

    pub fn take(&self) -> ItemPoolGuard<Arc<dyn SkimItem>> {
        let guard = self.pool.lock();
        let taken = self.taken.swap(guard.len(), Ordering::SeqCst);
        ItemPoolGuard { guard, start: taken }
    }

    pub fn reserved(&self) -> ItemPoolGuard<Arc<dyn SkimItem>> {
        let guard = self.reserved_items.lock();
        ItemPoolGuard { guard, start: 0 }
    }
}

pub struct ItemPoolGuard<'a, T: Sized + 'a> {
    guard: SpinLockGuard<'a, Vec<T>>,
    start: usize,
}

impl<'mutex, T: Sized> Deref for ItemPoolGuard<'mutex, T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        &self.guard[self.start..]
    }
}

//------------------------------------------------------------------------------
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum RankCriteria {
    Score,
    Begin,
    End,
    NegScore,
    NegBegin,
    NegEnd,
}

pub fn parse_criteria(text: &str) -> Option<RankCriteria> {
    match text.to_lowercase().as_ref() {
        "score" => Some(RankCriteria::Score),
        "begin" => Some(RankCriteria::Begin),
        "end" => Some(RankCriteria::End),
        "-score" => Some(RankCriteria::NegScore),
        "-begin" => Some(RankCriteria::NegBegin),
        "-end" => Some(RankCriteria::NegEnd),
        _ => None,
    }
}
<|endoftext|>


<commit_before>//! Contains information for keybindings.

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...
use std::hash::{Hash, Hasher};

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> = {
        let mut map = HashMap::<KeyPress, KeyEvent>::new();
        let press_s = KeyPress::from_key_names(vec!["Mod4"], vec!["s"]).unwrap();
        println!("[bindings] Press_s: {:?}", press_s);
        map.insert(press_s, Arc::new(Box::new(key_s)));
        let press_f4 = KeyPress::from_key_names(vec!["Alt"], vec!["F4"]).unwrap();
        println!("[bindings] press_f4: {:?}", press_f4);
        map.insert(press_f4, Arc::new(Box::new(key_f4)));
        RwLock::new(map)
    };
}

fn key_s() {
    println!("S keypress!");
}

fn key_f4() {
    println!("F4 keypress!");
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        match keymod_from_names(mods) {
            Err(message) => Err(message),
            Ok(mods) => {
                let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
                for name in keys {
                    if let Some(sym) = Keysym::from_name(name.to_string(),
                                                         NameFlags::None) {
                            syms.push(sym);
                    }
                    // Else if could not parse
                    else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                        NameFlags::CaseInsensitive) {
                        syms.push(sym);
                    }
                    else {
                        return Err(format!("Invalid key: {}", name));
                    }
                }
                syms.sort_by_key(|s| s.get_code());
                syms.dedup();
                return Ok(KeyPress { modifiers: mods, keys: syms });
            }
        }
    }

    /// Creates a KeyPress from keys that are pressed at the moment
    pub fn new(mods: KeyMod, mut keys: Vec<Keysym>) -> KeyPress {
        keys.sort_by_key(|k| k.get_code());
        keys.dedup();

        KeyPress { modifiers: mods, keys: keys }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<Fn() + Send + Sync>>;

/// Get a key mapping from the list.
pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

/// Register a new key mapping
pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<commit_msg>Changed keypress printlns to logs<commit_after>//! Contains information for keybindings.

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...
use std::hash::{Hash, Hasher};

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> = {
        let mut map = HashMap::<KeyPress, KeyEvent>::new();
        let press_s = KeyPress::from_key_names(vec!["Mod4"], vec!["s"]).unwrap();
        trace!("[bindings] Press_s: {:?}", press_s);
        map.insert(press_s, Arc::new(Box::new(key_s)));
        let press_f4 = KeyPress::from_key_names(vec!["Alt"], vec!["F4"]).unwrap();
        trace!("[bindings] press_f4: {:?}", press_f4);
        map.insert(press_f4, Arc::new(Box::new(key_f4)));
        RwLock::new(map)
    };
}

fn key_s() {
    info!("[Key handler] S keypress!");
}

fn key_f4() {
    info!("[Key handler] F4 keypress!");
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        match keymod_from_names(mods) {
            Err(message) => Err(message),
            Ok(mods) => {
                let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
                for name in keys {
                    if let Some(sym) = Keysym::from_name(name.to_string(),
                                                         NameFlags::None) {
                            syms.push(sym);
                    }
                    // Else if could not parse
                    else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                        NameFlags::CaseInsensitive) {
                        syms.push(sym);
                    }
                    else {
                        return Err(format!("Invalid key: {}", name));
                    }
                }
                syms.sort_by_key(|s| s.get_code());
                syms.dedup();
                return Ok(KeyPress { modifiers: mods, keys: syms });
            }
        }
    }

    /// Creates a KeyPress from keys that are pressed at the moment
    pub fn new(mods: KeyMod, mut keys: Vec<Keysym>) -> KeyPress {
        keys.sort_by_key(|k| k.get_code());
        keys.dedup();

        KeyPress { modifiers: mods, keys: keys }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<Fn() + Send + Sync>>;

/// Get a key mapping from the list.
pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

/// Register a new key mapping
pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<|endoftext|>


<commit_before>//! Contains information for keybindings.

use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::hash::{Hash, Hasher};

use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...

use super::layout::tree;
use super::lua;

macro_rules! gen_switch_workspace {
    ($($b:ident, $n:expr);+) => {
        $(fn $b() {
            trace!("Switching to workspace {}", $n);
            tree::switch_workspace(&$n.to_string()).expect("Could not switch to a work-space");
        })+
    };
}

gen_switch_workspace!(switch_workspace_1, 1;
                      switch_workspace_2, 2;
                      switch_workspace_3, 3;
                      switch_workspace_4, 4;
                      switch_workspace_5, 5;
                      switch_workspace_6, 6;
                      switch_workspace_7, 7;
                      switch_workspace_8, 8;
                      switch_workspace_9, 9;
                      switch_workspace_0, 0);

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> = {
        let mut map = HashMap::<KeyPress, KeyEvent>::new();

        let press_s = KeyPress::from_key_names(vec!["Mod4"], vec!["s"]).unwrap();
        map.insert(press_s, Arc::new(Box::new(key_s)));

        let press_f4 = KeyPress::from_key_names(vec!["Alt"],vec!["F4"]).unwrap();
        map.insert(press_f4, Arc::new(Box::new(key_f4)));

        let press_k = KeyPress::from_key_names(
            vec!["Ctrl"], vec!["k"]).unwrap();
        map.insert(press_k, Arc::new(Box::new(key_sleep)));

        let press_p = KeyPress::from_key_names(vec!["Ctrl"], vec!["p"]).unwrap();
        map.insert(press_p, Arc::new(Box::new(key_pointer_pos)));

        let press_esc = KeyPress::from_key_names(vec!["Ctrl"],
                                                 vec!["Escape"]).unwrap();
        map.insert(press_esc, Arc::new(Box::new(key_esc)));

        /* Workspace functions*/
        let terminal = KeyPress::from_key_names(vec!["Ctrl"], vec!["Return"]).unwrap();
        map.insert(terminal, Arc::new(Box::new(terminal_fn)));

        let dmenu = KeyPress::from_key_names(vec!["Alt"], vec!["d"]).unwrap();
        map.insert(dmenu, Arc::new(Box::new(dmenu_fn)));

        let switch_1 = KeyPress::from_key_names(vec!["Ctrl"], vec!["1"]).unwrap();
        map.insert(switch_1, Arc::new(Box::new(switch_workspace_1)));

        let switch_2 = KeyPress::from_key_names(vec!["Ctrl"], vec!["2"]).unwrap();
        map.insert(switch_2, Arc::new(Box::new(switch_workspace_2)));

        let switch_3 = KeyPress::from_key_names(vec!["Ctrl"], vec!["3"]).unwrap();
        map.insert(switch_3, Arc::new(Box::new(switch_workspace_3)));

        let switch_4 = KeyPress::from_key_names(vec!["Ctrl"], vec!["4"]).unwrap();
        map.insert(switch_4, Arc::new(Box::new(switch_workspace_4)));

        let switch_5 = KeyPress::from_key_names(vec!["Ctrl"], vec!["5"]).unwrap();
        map.insert(switch_5, Arc::new(Box::new(switch_workspace_5)));

        let switch_6 = KeyPress::from_key_names(vec!["Ctrl"], vec!["6"]).unwrap();
        map.insert(switch_6, Arc::new(Box::new(switch_workspace_6)));

        let switch_7 = KeyPress::from_key_names(vec!["Ctrl"], vec!["7"]).unwrap();
        map.insert(switch_7, Arc::new(Box::new(switch_workspace_7)));

        let switch_8 = KeyPress::from_key_names(vec!["Ctrl"], vec!["8"]).unwrap();
        map.insert(switch_8, Arc::new(Box::new(switch_workspace_8)));

        let switch_9 = KeyPress::from_key_names(vec!["Ctrl"], vec!["9"]).unwrap();
        map.insert(switch_9, Arc::new(Box::new(switch_workspace_9)));

        let switch_0 = KeyPress::from_key_names(vec!["Ctrl"], vec!["0"]).unwrap();
        map.insert(switch_0, Arc::new(Box::new(switch_workspace_0)));

        RwLock::new(map)
    };
}

fn terminal_fn() {
    use std::process::Command;
    Command::new("sh")
        .arg("-c")
        .arg("weston-terminal")
        .spawn().unwrap();
}

fn dmenu_fn() {
    use std::process::Command;
    Command::new("sh")
        .arg("-c")
        .arg("dmenu_run")
        .spawn().unwrap();
}

fn key_sleep() {
    use lua::LuaQuery;

    info!("keyhandler: Beginning thread::sleep keypress!");
    lua::send(LuaQuery::Execute("print('>entering sleep')\
                                 os.execute('sleep 5')\
                                 print('>leaving sleep')".to_string()))
                  .unwrap();
    info!("keyhandler: Finished thread::sleep keypress!");
}

fn key_pointer_pos() {
    use lua::LuaQuery;
    let code = "if wm == nil then print('wm table does not exist')\n\
                elseif wm.pointer == nil then print('wm.pointer table does not exist')\n\
                else\n\
                print('get_position is a func, preparing execution')
                local x, y = wm.pointer.get_position()\n\
                print('The cursor is at ' .. x .. ', ' .. y)\n\
                end".to_string();
    lua::send(LuaQuery::Execute(code)).unwrap();
}

fn key_s() {
    info!("[Key handler] S keypress!");
}

fn key_f4() {
    info!("[Key handler] F4 keypress!");
}

fn key_esc() {
    info!("handler: Esc keypress!");
    ::rustwlc::terminate();
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        keymod_from_names(mods).and_then(|mods| {
            let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
            for name in keys {
                // Parse a keysym for each given key
                if let Some(sym) = Keysym::from_name(name.to_string(),
                                                     NameFlags::None) {
                    syms.push(sym);
                }
                // If lowercase cannot be parsed, try case insensitive
                else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                          NameFlags::CaseInsensitive) {
                    syms.push(sym);
                }
                else {
                    return Err(format!("Invalid key: {}", name));
                }
            }
            // Sort and dedup to make sure hashes are the same
            syms.sort_by_key(|s| s.get_code());
            syms.dedup();
            return Ok(KeyPress { modifiers: mods, keys: syms });
        })
    }

    /// Creates a KeyPress from keys that are pressed at the moment
    pub fn new(mods: KeyMod, mut keys: Vec<Keysym>) -> KeyPress {
        // Sort and dedup to make sure hashes are the same
        keys.sort_by_key(|k| k.get_code());
        keys.dedup();

        KeyPress { modifiers: mods, keys: keys }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<Fn() + Send + Sync>>;

/// Get a key mapping from the list.
pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

/// Register a new set of key mappings
#[allow(dead_code)]
pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<commit_msg>Register default keybindings with a macro<commit_after>//! Contains information for keybindings.

use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::hash::{Hash, Hasher};

use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...

use super::layout::tree;
use super::lua;

macro_rules! keypress {
    ($modifier:expr, $key:expr) => {
        KeyPress::from_key_names(vec![$modifier],
                                 vec![$key])
            .expect(concat!("Unable to create keypress from macro with ",
                            $modifier, " and ", $key))
    };
}

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> = {
        let mut map = HashMap::<KeyPress, KeyEvent>::new();

        macro_rules! register_defaults {
            ( $map:expr; $($func:expr, $press:expr);+ ) => {
                $(
                    let _ = $map.insert($press, Arc::new(Box::new($func)));
                 )+
            }
        }
        macro_rules! gen_switch_workspace {
            ($map:expr; $($b:ident, $n:expr);+) => {
                $(fn $b() {
                    trace!("Switching to workspace {}", $n);
                    tree::switch_workspace(&$n.to_string())
                        .expect("Could not switch to a work-space");
                }
                register_defaults!( $map; $b, keypress!("Alt", $n) );
                )+
            };
        }

        gen_switch_workspace!(map; switch_workspace_1, "1";
                              switch_workspace_2, "2";
                              switch_workspace_3, "3";
                              switch_workspace_4, "4";
                              switch_workspace_5, "5";
                              switch_workspace_6, "6";
                              switch_workspace_7, "7";
                              switch_workspace_8, "8";
                              switch_workspace_9, "9";
                              switch_workspace_0, "0");

        register_defaults! {
            map;
            quit_fn, keypress!("Alt", "Escape");
            terminal_fn, keypress!("Alt", "Return");
            dmenu_fn, keypress!("Alt", "d");
            pointer_fn, keypress!("Alt", "p")
        }

        RwLock::new(map)
    };
}

fn terminal_fn() {
    use std::process::Command;
    Command::new("sh")
        .arg("-c")
        .arg("weston-terminal")
        .spawn().unwrap();
}

fn dmenu_fn() {
    use std::process::Command;
    Command::new("sh")
        .arg("-c")
        .arg("dmenu_run")
        .spawn().unwrap();
}

fn pointer_fn() {
    use lua::LuaQuery;
    let code = "if wm == nil then print('wm table does not exist')\n\
                elseif wm.pointer == nil then print('wm.pointer table does not exist')\n\
                else\n\
                print('get_position is a func, preparing execution')
                local x, y = wm.pointer.get_position()\n\
                print('The cursor is at ' .. x .. ', ' .. y)\n\
                end".to_string();
    lua::send(LuaQuery::Execute(code)).unwrap();
}

fn quit_fn() {
    info!("handler: Esc keypress!");
    ::rustwlc::terminate();
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        keymod_from_names(mods).and_then(|mods| {
            let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
            for name in keys {
                // Parse a keysym for each given key
                if let Some(sym) = Keysym::from_name(name.to_string(),
                                                     NameFlags::None) {
                    syms.push(sym);
                }
                // If lowercase cannot be parsed, try case insensitive
                else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                          NameFlags::CaseInsensitive) {
                    syms.push(sym);
                }
                else {
                    return Err(format!("Invalid key: {}", name));
                }
            }
            // Sort and dedup to make sure hashes are the same
            syms.sort_by_key(|s| s.get_code());
            syms.dedup();
            return Ok(KeyPress { modifiers: mods, keys: syms });
        })
    }

    /// Creates a KeyPress from keys that are pressed at the moment
    pub fn new(mods: KeyMod, mut keys: Vec<Keysym>) -> KeyPress {
        // Sort and dedup to make sure hashes are the same
        keys.sort_by_key(|k| k.get_code());
        keys.dedup();

        KeyPress { modifiers: mods, keys: keys }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<Fn() + Send + Sync>>;

/// Get a key mapping from the list.
pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

/// Register a new set of key mappings
#[allow(dead_code)]
pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<|endoftext|>


<commit_before>//! Functions for splitting sequences into fixed-width moving windows (kmers)
//! and utilities for dealing with these kmers.

/// Returns true if the base is a unambiguous nucleic acid base (e.g. ACGT) and
/// false otherwise.
fn is_good_base(chr: u8) -> bool {
    match chr as char {
        'a' | 'c' | 'g' | 't' | 'A' | 'C' | 'G' | 'T' => true,
        _ => false,
    }
}

/// Generic moving window iterator over sequences to return k-mers
///
/// Iterator returns slices to the original data.
pub struct Kmers<'a> {
    k: u8,
    start_pos: usize,
    buffer: &'a [u8],
}

impl<'a> Kmers<'a> {
    /// Creates a new kmer-izer for a nucleotide/amino acid sequence.
    pub fn new(buffer: &'a [u8], k: u8) -> Self {
        Kmers {
            k,
            start_pos: 0,
            buffer,
        }
    }
}

impl<'a> Iterator for Kmers<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        if self.start_pos + self.k as usize > self.buffer.len() {
            return None;
        }
        let pos = self.start_pos;
        self.start_pos += 1;
        Some(&self.buffer[pos..pos + self.k as usize])
    }
}

/// A kmer-izer for a nucleotide acid sequences to return canonical kmers.
///
/// Iterator returns the position of the kmer, a slice to the original data,
/// and an boolean indicating if the kmer returned is the original or the
/// reverse complement.
pub struct CanonicalKmers<'a> {
    k: u8,
    start_pos: usize,
    buffer: &'a [u8],
    rc_buffer: &'a [u8],
}

impl<'a> CanonicalKmers<'a> {
    /// Creates a new iterator.
    ///
    /// It's generally more useful to use this directly from a sequences (e.g.
    /// `seq.canonical_kmers`. Requires a reference to the reverse complement
    /// of the sequence it's created on, e.g.
    /// ```
    /// use needletail::Sequence;
    /// use needletail::kmer::CanonicalKmers;
    ///
    /// let seq = b"ACGT";
    /// let rc = seq.reverse_complement();
    /// let c_iter = CanonicalKmers::new(seq, &rc, 3);
    /// for (pos, kmer, canonical) in c_iter {
    ///    // process data in here
    /// }
    ///
    /// ```
    pub fn new(buffer: &'a [u8], rc_buffer: &'a [u8], k: u8) -> Self {
        let mut nucl_kmers = CanonicalKmers {
            k,
            start_pos: 0,
            buffer,
            rc_buffer,
        };
        nucl_kmers.update_position(true);
        nucl_kmers
    }

    fn update_position(&mut self, initial: bool) -> bool {
        // check if we have enough "physical" space for one more kmer
        if self.start_pos + self.k as usize > self.buffer.len() {
            return false;
        }

        let (mut kmer_len, stop_len) = if initial {
            (0, (self.k - 1) as usize)
        } else {
            ((self.k - 1) as usize, self.k as usize)
        };

        while kmer_len < stop_len {
            if is_good_base(self.buffer[self.start_pos + kmer_len]) {
                kmer_len += 1;
            } else {
                kmer_len = 0;
                self.start_pos += kmer_len + 1;
                if self.start_pos + self.k as usize > self.buffer.len() {
                    return false;
                }
            }
        }
        true
    }
}

impl<'a> Iterator for CanonicalKmers<'a> {
    type Item = (usize, &'a [u8], bool);

    fn next(&mut self) -> Option<(usize, &'a [u8], bool)> {
        if !self.update_position(false) {
            return None;
        }
        let pos = self.start_pos;
        self.start_pos += 1;

        let result = &self.buffer[pos..pos + self.k as usize];
        let rc_buffer = self.rc_buffer;
        let rc_result = &rc_buffer[rc_buffer.len() - pos - self.k as usize..rc_buffer.len() - pos];
        if result < rc_result {
            Some((pos, result, false))
        } else {
            Some((pos, rc_result, true))
        }
    }
}

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

    #[test]
    fn can_kmerize() {
        let k_iter = Kmers::new(b"AGCT", 1);
        // test general function
        for (i, k) in k_iter.enumerate() {
            match i {
                0 => assert_eq!(k, b"A"),
                1 => assert_eq!(k, b"G"),
                2 => assert_eq!(k, b"C"),
                3 => assert_eq!(k, b"T"),
                _ => unreachable!("Too many kmers"),
            }
        }

        // test that we handle length 2 (and don't drop Ns)
        let k_iter = Kmers::new(b"AGNCT", 2);
        for (i, k) in k_iter.enumerate() {
            match i {
                0 => assert_eq!(k, b"AG"),
                1 => assert_eq!(k, b"GN"),
                2 => assert_eq!(k, b"NC"),
                3 => assert_eq!(k, b"CT"),
                _ => unreachable!("Too many kmers"),
            }
        }

        // test that the minimum length works
        let k_iter = Kmers::new(b"AC", 2);
        for k in k_iter {
            assert_eq!(k, &b"AC"[..]);
        }
    }

    #[test]
    fn can_canonicalize() {
        // test general function
        let seq = b"AGCT";
        let rc_seq = seq.reverse_complement();
        let c_iter = CanonicalKmers::new(seq, &rc_seq, 1);
        for (i, (_, k, is_c)) in c_iter.enumerate() {
            match i {
                0 => {
                    assert_eq!(k, b"A");
                    assert_eq!(is_c, false);
                }
                1 => {
                    assert_eq!(k, b"C");
                    assert_eq!(is_c, true);
                }
                2 => {
                    assert_eq!(k, b"C");
                    assert_eq!(is_c, false);
                }
                3 => {
                    assert_eq!(k, b"A");
                    assert_eq!(is_c, true);
                }
                _ => unreachable!("Too many kmers"),
            }
        }

        let seq = b"AGCTA";
        let rc_seq = seq.reverse_complement();
        let c_iter = CanonicalKmers::new(seq, &rc_seq, 2);
        for (i, (_, k, _)) in c_iter.enumerate() {
            match i {
                0 => assert_eq!(k, b"AG"),
                1 => assert_eq!(k, b"GC"),
                2 => assert_eq!(k, b"AG"),
                3 => assert_eq!(k, b"TA"),
                _ => unreachable!("Too many kmers"),
            }
        }

        let seq = b"AGNTA";
        let rc_seq = seq.reverse_complement();
        let c_iter = CanonicalKmers::new(seq, &rc_seq, 2);
        for (i, (ix, k, _)) in c_iter.enumerate() {
            match i {
                0 => {
                    assert_eq!(ix, 0);
                    assert_eq!(k, b"AG");
                }
                1 => {
                    assert_eq!(ix, 3);
                    assert_eq!(k, b"TA");
                }
                _ => unreachable!("Too many kmers"),
            }
        }
    }
}
<commit_msg>use matches macro to check valid base [appease clippy]<commit_after>//! Functions for splitting sequences into fixed-width moving windows (kmers)
//! and utilities for dealing with these kmers.

/// Returns true if the base is a unambiguous nucleic acid base (e.g. ACGT) and
/// false otherwise.
fn is_good_base(chr: u8) -> bool {
    matches!(chr as char, 'a' | 'c' | 'g' | 't' | 'A' | 'C' | 'G' | 'T')
}

/// Generic moving window iterator over sequences to return k-mers
///
/// Iterator returns slices to the original data.
pub struct Kmers<'a> {
    k: u8,
    start_pos: usize,
    buffer: &'a [u8],
}

impl<'a> Kmers<'a> {
    /// Creates a new kmer-izer for a nucleotide/amino acid sequence.
    pub fn new(buffer: &'a [u8], k: u8) -> Self {
        Kmers {
            k,
            start_pos: 0,
            buffer,
        }
    }
}

impl<'a> Iterator for Kmers<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        if self.start_pos + self.k as usize > self.buffer.len() {
            return None;
        }
        let pos = self.start_pos;
        self.start_pos += 1;
        Some(&self.buffer[pos..pos + self.k as usize])
    }
}

/// A kmer-izer for a nucleotide acid sequences to return canonical kmers.
///
/// Iterator returns the position of the kmer, a slice to the original data,
/// and an boolean indicating if the kmer returned is the original or the
/// reverse complement.
pub struct CanonicalKmers<'a> {
    k: u8,
    start_pos: usize,
    buffer: &'a [u8],
    rc_buffer: &'a [u8],
}

impl<'a> CanonicalKmers<'a> {
    /// Creates a new iterator.
    ///
    /// It's generally more useful to use this directly from a sequences (e.g.
    /// `seq.canonical_kmers`. Requires a reference to the reverse complement
    /// of the sequence it's created on, e.g.
    /// ```
    /// use needletail::Sequence;
    /// use needletail::kmer::CanonicalKmers;
    ///
    /// let seq = b"ACGT";
    /// let rc = seq.reverse_complement();
    /// let c_iter = CanonicalKmers::new(seq, &rc, 3);
    /// for (pos, kmer, canonical) in c_iter {
    ///    // process data in here
    /// }
    ///
    /// ```
    pub fn new(buffer: &'a [u8], rc_buffer: &'a [u8], k: u8) -> Self {
        let mut nucl_kmers = CanonicalKmers {
            k,
            start_pos: 0,
            buffer,
            rc_buffer,
        };
        nucl_kmers.update_position(true);
        nucl_kmers
    }

    fn update_position(&mut self, initial: bool) -> bool {
        // check if we have enough "physical" space for one more kmer
        if self.start_pos + self.k as usize > self.buffer.len() {
            return false;
        }

        let (mut kmer_len, stop_len) = if initial {
            (0, (self.k - 1) as usize)
        } else {
            ((self.k - 1) as usize, self.k as usize)
        };

        while kmer_len < stop_len {
            if is_good_base(self.buffer[self.start_pos + kmer_len]) {
                kmer_len += 1;
            } else {
                kmer_len = 0;
                self.start_pos += kmer_len + 1;
                if self.start_pos + self.k as usize > self.buffer.len() {
                    return false;
                }
            }
        }
        true
    }
}

impl<'a> Iterator for CanonicalKmers<'a> {
    type Item = (usize, &'a [u8], bool);

    fn next(&mut self) -> Option<(usize, &'a [u8], bool)> {
        if !self.update_position(false) {
            return None;
        }
        let pos = self.start_pos;
        self.start_pos += 1;

        let result = &self.buffer[pos..pos + self.k as usize];
        let rc_buffer = self.rc_buffer;
        let rc_result = &rc_buffer[rc_buffer.len() - pos - self.k as usize..rc_buffer.len() - pos];
        if result < rc_result {
            Some((pos, result, false))
        } else {
            Some((pos, rc_result, true))
        }
    }
}

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

    #[test]
    fn can_kmerize() {
        let k_iter = Kmers::new(b"AGCT", 1);
        // test general function
        for (i, k) in k_iter.enumerate() {
            match i {
                0 => assert_eq!(k, b"A"),
                1 => assert_eq!(k, b"G"),
                2 => assert_eq!(k, b"C"),
                3 => assert_eq!(k, b"T"),
                _ => unreachable!("Too many kmers"),
            }
        }

        // test that we handle length 2 (and don't drop Ns)
        let k_iter = Kmers::new(b"AGNCT", 2);
        for (i, k) in k_iter.enumerate() {
            match i {
                0 => assert_eq!(k, b"AG"),
                1 => assert_eq!(k, b"GN"),
                2 => assert_eq!(k, b"NC"),
                3 => assert_eq!(k, b"CT"),
                _ => unreachable!("Too many kmers"),
            }
        }

        // test that the minimum length works
        let k_iter = Kmers::new(b"AC", 2);
        for k in k_iter {
            assert_eq!(k, &b"AC"[..]);
        }
    }

    #[test]
    fn can_canonicalize() {
        // test general function
        let seq = b"AGCT";
        let rc_seq = seq.reverse_complement();
        let c_iter = CanonicalKmers::new(seq, &rc_seq, 1);
        for (i, (_, k, is_c)) in c_iter.enumerate() {
            match i {
                0 => {
                    assert_eq!(k, b"A");
                    assert_eq!(is_c, false);
                }
                1 => {
                    assert_eq!(k, b"C");
                    assert_eq!(is_c, true);
                }
                2 => {
                    assert_eq!(k, b"C");
                    assert_eq!(is_c, false);
                }
                3 => {
                    assert_eq!(k, b"A");
                    assert_eq!(is_c, true);
                }
                _ => unreachable!("Too many kmers"),
            }
        }

        let seq = b"AGCTA";
        let rc_seq = seq.reverse_complement();
        let c_iter = CanonicalKmers::new(seq, &rc_seq, 2);
        for (i, (_, k, _)) in c_iter.enumerate() {
            match i {
                0 => assert_eq!(k, b"AG"),
                1 => assert_eq!(k, b"GC"),
                2 => assert_eq!(k, b"AG"),
                3 => assert_eq!(k, b"TA"),
                _ => unreachable!("Too many kmers"),
            }
        }

        let seq = b"AGNTA";
        let rc_seq = seq.reverse_complement();
        let c_iter = CanonicalKmers::new(seq, &rc_seq, 2);
        for (i, (ix, k, _)) in c_iter.enumerate() {
            match i {
                0 => {
                    assert_eq!(ix, 0);
                    assert_eq!(k, b"AG");
                }
                1 => {
                    assert_eq!(ix, 3);
                    assert_eq!(k, b"TA");
                }
                _ => unreachable!("Too many kmers"),
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(io)]
#![cfg(not(test))]

extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;
extern crate rustbox;
extern crate docopt;
extern crate iota;

use std::io::stdin;
use docopt::Docopt;
use iota::{
    Editor, Input,
    StandardMode, NormalMode,
    RustboxFrontend, Mode
};
use rustbox::{InitOptions, RustBox, InputMode};
static USAGE: &'static str = "
Usage: iota [<filename>] [options]
       iota --help

Options:
    --vi           Start Iota with vi-like modes
    -h, --help     Show this message.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_filename: Option<String>,
    flag_vi: bool,
    flag_help: bool,
}

fn is_atty(fileno: libc::c_int) -> bool {
    // FIXME: find a way to do this without unsafe
    //        std::io doesn't allow for this, currently
    unsafe { libc::isatty(fileno) != 0 }
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let stdin_is_atty = is_atty(libc::STDIN_FILENO);
    let stderr_is_atty = is_atty(libc::STDERR_FILENO);

    // editor source - either a filename or stdin
    let source = if stdin_is_atty {
        Input::Filename(args.arg_filename)
    } else {
        Input::Stdin(stdin())
    };

    // initialise rustbox
    let rb = match RustBox::init(InitOptions{
        buffer_stderr: stderr_is_atty,
        input_mode: InputMode::Esc,
    }) {
        Result::Ok(v) => v,
        Result::Err(e) => panic!("{}", e),
    };

    // initialise the frontend
    let frontend = RustboxFrontend::new(&rb);

    // initialise the editor mode
    let mode: Box<Mode> = if args.flag_vi {
        Box::new(NormalMode::new())
    } else {
         Box::new(StandardMode::new())
    };

    // start the editor
    let mut editor = Editor::new(source, mode, frontend);
    editor.start();
}
<commit_msg>Remove unused feature<commit_after>#![feature(libc)]
#![cfg(not(test))]

extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;
extern crate rustbox;
extern crate docopt;
extern crate iota;

use std::io::stdin;
use docopt::Docopt;
use iota::{
    Editor, Input,
    StandardMode, NormalMode,
    RustboxFrontend, Mode
};
use rustbox::{InitOptions, RustBox, InputMode};
static USAGE: &'static str = "
Usage: iota [<filename>] [options]
       iota --help

Options:
    --vi           Start Iota with vi-like modes
    -h, --help     Show this message.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_filename: Option<String>,
    flag_vi: bool,
    flag_help: bool,
}

fn is_atty(fileno: libc::c_int) -> bool {
    // FIXME: find a way to do this without unsafe
    //        std::io doesn't allow for this, currently
    unsafe { libc::isatty(fileno) != 0 }
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let stdin_is_atty = is_atty(libc::STDIN_FILENO);
    let stderr_is_atty = is_atty(libc::STDERR_FILENO);

    // editor source - either a filename or stdin
    let source = if stdin_is_atty {
        Input::Filename(args.arg_filename)
    } else {
        Input::Stdin(stdin())
    };

    // initialise rustbox
    let rb = match RustBox::init(InitOptions{
        buffer_stderr: stderr_is_atty,
        input_mode: InputMode::Esc,
    }) {
        Result::Ok(v) => v,
        Result::Err(e) => panic!("{}", e),
    };

    // initialise the frontend
    let frontend = RustboxFrontend::new(&rb);

    // initialise the editor mode
    let mode: Box<Mode> = if args.flag_vi {
        Box::new(NormalMode::new())
    } else {
         Box::new(StandardMode::new())
    };

    // start the editor
    let mut editor = Editor::new(source, mode, frontend);
    editor.start();
}
<|endoftext|>


<commit_before>#![feature(exit_status)]

extern crate identicon;
extern crate openssl;
extern crate image;

use std::env;
use std::io;
use std::io::{Read, Write, Result};

use image::ColorType;
use image::png::PNGEncoder;
use openssl::crypto::hash::{Hasher, Type};

use identicon::Identicon;

fn main() {
    match hash() {
        Ok(bytes) => {
            match generate(&bytes[..]) {
                Ok(_) => (),
                Err(e) => {
                    println!("{}", e);
                    env::set_exit_status(2);
                },
            }
        },
        Err(e) => {
            println!("{}", e);
            env::set_exit_status(1)
        },
    }
}

fn generate(input: &[u8]) -> Result<()> {
    let identicon = Identicon::new(input);
    let image = identicon.image();
    let (width, height) = image.dimensions();
    let output = &mut io::stdout();
    let mut encoder = PNGEncoder::new(output);
    encoder.encode(image.as_ref(), width, height, ColorType::RGB(8))
}

fn hash() -> Result<Vec<u8>> {
    let mut hash = Hasher::new(Type::MD5);
    let input = io::stdin();
    for result in input.lock().bytes() {
        match result {
            Ok(byte) => {
                let _ = hash.write(&[byte]);
            },
            Err(e) => {
                return Err(e)
            },
        }
    }
    Ok(hash.finish())
}
<commit_msg>Read 1kb chunks into buffer.<commit_after>#![feature(exit_status)]

extern crate identicon;
extern crate openssl;
extern crate image;

use std::env;
use std::io;
use std::io::{Read, Write, Result};

use image::ColorType;
use image::png::PNGEncoder;
use openssl::crypto::hash::{Hasher, Type};

use identicon::Identicon;

fn main() {
    match hash() {
        Ok(bytes) => {
            match generate(&bytes[..]) {
                Ok(_) => (),
                Err(e) => {
                    println!("{}", e);
                    env::set_exit_status(2);
                },
            }
        },
        Err(e) => {
            println!("{}", e);
            env::set_exit_status(1)
        },
    }
}

fn generate(input: &[u8]) -> Result<()> {
    let identicon = Identicon::new(input);
    let image = identicon.image();
    let (width, height) = image.dimensions();
    let output = &mut io::stdout();
    let mut encoder = PNGEncoder::new(output);
    encoder.encode(image.as_ref(), width, height, ColorType::RGB(8))
}

fn hash() -> Result<Vec<u8>> {
    let mut hash = Hasher::new(Type::MD5);
    let input = io::stdin();
    let mut reader = input.lock();
    let mut buf = [0; 1024];
    loop {
        match reader.read(&mut buf) {
            Ok(n) => {
                if n == 0 {
                    break;
                }
                let _ = hash.write(&buf[0..n]);
            },
            Err(e) => {
                return Err(e)
            },
        }
    }
    Ok(hash.finish())
}
<|endoftext|>


<commit_before>#![feature(core, io, std_misc, path, env)]

extern crate time;

use std::old_io::{File, SeekStyle, FileMode, FileAccess, USER_RWX,
    BufferedReader, Lines, IoResult};
use std::old_io::fs::{unlink, PathExtensions, mkdir};
use std::env::{args, home_dir, set_exit_status};
use std::fmt;
use std::time::Duration;
use time::{now_utc, Tm, empty_tm, strptime};

fn main() {
    let result = match args().nth(1) {
        None => Err(PunchClockError::NoCommandGiven),
        Some(command) => {
            let mut time_clock = TimeClock::new();
            match &command[] {
                "in" => time_clock.punch_in(),
                "out" => time_clock.punch_out(),
                "status" => time_clock.status(),
                "report" => time_clock.report_daily_hours(),
                _ => Err(PunchClockError::UnknownCommand)
            }
        }
    };

    if let Err(e) = result {
        println!("Error: {}", e);
        set_exit_status(1);
    }
}

enum PunchClockError {
    NoCommandGiven,
    UnknownCommand,
    AlreadyPunchedIn,
    AlreadyPunchedOut,
    CorruptedTimeSheet,
    IoError(std::old_io::IoError),
}

impl fmt::Display for PunchClockError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use PunchClockError::*;
        fmt.write_str(
            match *self {
                NoCommandGiven => "No command given",
                UnknownCommand => "Unknown command",
                AlreadyPunchedIn => "You are already punched in",
                AlreadyPunchedOut => "You're not currently punched in",
                CorruptedTimeSheet => "Bad data in timesheet",
                IoError(_) => "IO error"
            }
        )
    }
}

type PunchClockResult<T> = Result<T, PunchClockError>;

struct TimeClock {
    now: Tm,
    timesheet: File,
    currently_working: bool,
    state_path: Path
}

impl TimeClock {
    fn new() -> TimeClock {
        let now = now_utc();
        let home = home_dir().unwrap();
        let base_dir = home.join(Path::new(".punch"));
        let timesheet_path = base_dir.join("timesheet");
        let working_state_path = base_dir.join("state");
        if !base_dir.exists() {
            mkdir(&base_dir, USER_RWX).unwrap();
        }
        let timesheet = File::open_mode(&timesheet_path,
                                            FileMode::Append,
                                            FileAccess::Write).unwrap();
        TimeClock {
            timesheet: timesheet,
            currently_working: working_state_path.exists(),
            state_path: working_state_path,
            now: now
        }
    }

    // commands

    fn punch_in(&mut self) -> PunchClockResult<()> {
        if self.currently_working {
            return Err(PunchClockError::AlreadyPunchedIn);
        }
        self.timesheet.seek(0, SeekStyle::SeekEnd).unwrap();
        writeln!(&mut self.timesheet, "in: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(true);
        Ok(())
    }

    fn punch_out(&mut self) -> PunchClockResult<()> {
        if !self.currently_working {
            return Err(PunchClockError::AlreadyPunchedOut);
        }
        self.timesheet.seek(0, SeekStyle::SeekEnd).unwrap();
        writeln!(&mut self.timesheet, "out: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(false);
        Ok(())
    }

    fn status(&self) -> PunchClockResult<()> {
        if self.currently_working {
            println!("You're punched in");
        } else {
            println!("You're punched out");
        }
        Ok(())
    }

    fn report_daily_hours(&mut self) -> PunchClockResult<()> {
        self.timesheet.seek(0, SeekStyle::SeekSet).unwrap();
        let mut buf =
            BufferedReader::new(File::open(self.timesheet.path()).unwrap());
        let mut current_day = empty_tm();
        let mut time_worked_today = Duration::zero();

        for interval in IntervalIter::from_lines(buf.lines()) {
            let (start, end) = try!(interval);
            if !same_day(&start, &current_day) {
                if !time_worked_today.is_zero() {
                    print_time_worked(&time_worked_today, &current_day);
                }
                current_day = start;
                time_worked_today = Duration::zero();
            }
            time_worked_today =
                time_worked_today + (end.to_timespec() - start.to_timespec());
        }

        if !time_worked_today.is_zero() {
            print_time_worked(&time_worked_today, &current_day);
        }
        Ok(())
    }

    // aux. methods

    fn set_current_working_state(&mut self, currently_working: bool) {
        self.currently_working = currently_working;
        if currently_working {
            File::create(&self.state_path).unwrap();
        } else {
            unlink(&self.state_path).unwrap();
        }
    }
}

struct IntervalIter<'a> {
    lines: Lines<'a, BufferedReader<File>>
}

impl <'a> IntervalIter<'a> {
    fn from_lines(lines: Lines<'a, BufferedReader<File>>) -> IntervalIter<'a> {
        IntervalIter {lines: lines}
    }
}

impl <'a> Iterator for IntervalIter<'a> {
    type Item = PunchClockResult<(Tm, Tm)>;
    fn next(&mut self) -> Option<PunchClockResult<(Tm, Tm)>> {

        // helper function to make error handling a bit nicer
        fn inner_unwrap<T>(x: Option<IoResult<T>>)
                -> PunchClockResult<Option<T>> {
            match x {
                None => Ok(None),
                Some(Ok(inner)) => Ok(Some(inner)),
                Some(Err(e)) => Err(PunchClockError::IoError(e))
            }
        }

        let line_1 = match inner_unwrap(self.lines.next()) {
            Ok(l) => l,
            Err(e) => return Some(Err(e))
        };
        let line_2 = match inner_unwrap(self.lines.next()) {
            Ok(l) => l,
            Err(e) => return Some(Err(e))
        };

        match (line_1, line_2) {
            (None, None) => None,
            (Some(start_line), o_end_line) => {
                if !start_line.starts_with("in: ") {
                    return Some(Err(PunchClockError::CorruptedTimeSheet));
                }
                let start = parse_time(&start_line[4..]);
                let end = match o_end_line {
                    None => now_utc(),
                    Some(end_line) => {
                        if !end_line.starts_with("out: ") {
                            return Some(Err(PunchClockError::CorruptedTimeSheet));
                        }
                        parse_time(&end_line[5..])
                    },
                };
                Some(Ok((start, end)))
            },
            _ => unreachable!() // (None, Some(l)) should not happen
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, None)
    }
}

fn parse_time(s: &str) -> Tm {
    strptime(&s[..s.len() - 1], "%a, %d %b %Y %T %Z").unwrap()
}

fn same_day(t1: &Tm, t2: &Tm) -> bool {
    t1.tm_year == t2.tm_year &&
    t1.tm_mon == t2.tm_mon &&
    t1.tm_mday == t2.tm_mday
}

fn print_time_worked(t: &Duration, day: &Tm) {
    println!("{}: {}:{:02}",
        day.strftime("%a, %d %b %Y").unwrap(),
        t.num_hours() ,
        t.num_minutes() % 60
    );
}
<commit_msg>Switch to new io library<commit_after>#![feature(core, io, fs, std_misc, path, env)]

extern crate time;

use std::fs::{File, create_dir, OpenOptions};
use std::io::{Seek, SeekFrom, BufReader, BufReadExt, Lines, Write};
use std::io;
use std::old_io::fs::{unlink, PathExtensions};
use std::env::{args, home_dir, set_exit_status};
use std::fmt;
use std::time::Duration;
use time::{now_utc, Tm, empty_tm, strptime};

fn main() {
    let result = match args().nth(1) {
        None => Err(PunchClockError::NoCommandGiven),
        Some(command) => {
            let mut time_clock = TimeClock::new();
            match &command[] {
                "in" => time_clock.punch_in(),
                "out" => time_clock.punch_out(),
                "status" => time_clock.status(),
                "report" => time_clock.report_daily_hours(),
                _ => Err(PunchClockError::UnknownCommand)
            }
        }
    };

    if let Err(e) = result {
        println!("Error: {}", e);
        set_exit_status(1);
    }
}

enum PunchClockError {
    NoCommandGiven,
    UnknownCommand,
    AlreadyPunchedIn,
    AlreadyPunchedOut,
    CorruptedTimeSheet,
    IoError(io::Error),
}

impl fmt::Display for PunchClockError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        use PunchClockError::*;
        fmt.write_str(
            match *self {
                NoCommandGiven => "No command given",
                UnknownCommand => "Unknown command",
                AlreadyPunchedIn => "You are already punched in",
                AlreadyPunchedOut => "You're not currently punched in",
                CorruptedTimeSheet => "Bad data in timesheet",
                IoError(_) => "IO error"
            }
        )
    }
}

type PunchClockResult<T> = Result<T, PunchClockError>;

struct TimeClock {
    now: Tm,
    timesheet: File,
    currently_working: bool,
    state_path: Path
}

impl TimeClock {
    fn new() -> TimeClock {
        let now = now_utc();
        let home = home_dir().unwrap();
        let base_dir = home.join(Path::new(".punch"));
        let timesheet_path = base_dir.join("timesheet");
        let working_state_path = base_dir.join("state");
        if !base_dir.exists() {
            create_dir(&base_dir).unwrap();
        }
        let mut open_opts = OpenOptions::new();
        open_opts.write(true).append(true);
        let timesheet = open_opts.open(&timesheet_path).unwrap();
        TimeClock {
            timesheet: timesheet,
            currently_working: working_state_path.exists(),
            state_path: working_state_path,
            now: now
        }
    }

    // commands

    fn punch_in(&mut self) -> PunchClockResult<()> {
        if self.currently_working {
            return Err(PunchClockError::AlreadyPunchedIn);
        }
        self.timesheet.seek(SeekFrom::End(0)).unwrap();
        writeln!(&mut self.timesheet, "in: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(true);
        Ok(())
    }

    fn punch_out(&mut self) -> PunchClockResult<()> {
        if !self.currently_working {
            return Err(PunchClockError::AlreadyPunchedOut);
        }
        self.timesheet.seek(SeekFrom::End(0)).unwrap();
        writeln!(&mut self.timesheet, "out: {}", self.now.rfc822()).unwrap();
        self.set_current_working_state(false);
        Ok(())
    }

    fn status(&self) -> PunchClockResult<()> {
        if self.currently_working {
            println!("You're punched in");
        } else {
            println!("You're punched out");
        }
        Ok(())
    }

    fn report_daily_hours(&mut self) -> PunchClockResult<()> {
        self.timesheet.seek(SeekFrom::Start(0)).unwrap();
        let buf =
            BufReader::new(File::open(self.timesheet.path().unwrap()).unwrap());
        let mut current_day = empty_tm();
        let mut time_worked_today = Duration::zero();

        for interval in IntervalIter::from_lines(buf.lines()) {
            let (start, end) = try!(interval);
            if !same_day(&start, &current_day) {
                if !time_worked_today.is_zero() {
                    print_time_worked(&time_worked_today, &current_day);
                }
                current_day = start;
                time_worked_today = Duration::zero();
            }
            time_worked_today =
                time_worked_today + (end.to_timespec() - start.to_timespec());
        }

        if !time_worked_today.is_zero() {
            print_time_worked(&time_worked_today, &current_day);
        }
        Ok(())
    }

    // aux. methods

    fn set_current_working_state(&mut self, currently_working: bool) {
        self.currently_working = currently_working;
        if currently_working {
            File::create(&self.state_path).unwrap();
        } else {
            unlink(&self.state_path).unwrap();
        }
    }
}

struct IntervalIter {
    lines: Lines<BufReader<File>>
}

impl IntervalIter {
    fn from_lines(lines: Lines<BufReader<File>>) -> IntervalIter {
        IntervalIter {lines: lines}
    }
}

impl Iterator for IntervalIter {
    type Item = PunchClockResult<(Tm, Tm)>;
    fn next(&mut self) -> Option<PunchClockResult<(Tm, Tm)>> {

        // helper function to make error handling a bit nicer
        fn inner_unwrap<T>(x: Option<io::Result<T>>)
                -> PunchClockResult<Option<T>> {
            match x {
                None => Ok(None),
                Some(Ok(inner)) => Ok(Some(inner)),
                Some(Err(e)) => Err(PunchClockError::IoError(e))
            }
        }

        let line_1 = match inner_unwrap(self.lines.next()) {
            Ok(l) => l,
            Err(e) => return Some(Err(e))
        };
        let line_2 = match inner_unwrap(self.lines.next()) {
            Ok(l) => l,
            Err(e) => return Some(Err(e))
        };

        match (line_1, line_2) {
            (None, None) => None,
            (Some(start_line), o_end_line) => {
                if !start_line.starts_with("in: ") {
                    return Some(Err(PunchClockError::CorruptedTimeSheet));
                }
                let start = parse_time(&start_line[4..]);
                let end = match o_end_line {
                    None => now_utc(),
                    Some(end_line) => {
                        if !end_line.starts_with("out: ") {
                            return Some(Err(PunchClockError::CorruptedTimeSheet));
                        }
                        parse_time(&end_line[5..])
                    },
                };
                Some(Ok((start, end)))
            },
            _ => unreachable!() // (None, Some(l)) should not happen
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, None)
    }
}

fn parse_time(s: &str) -> Tm {
    strptime(&s[..s.len() - 1], "%a, %d %b %Y %T %Z").unwrap()
}

fn same_day(t1: &Tm, t2: &Tm) -> bool {
    t1.tm_year == t2.tm_year &&
    t1.tm_mon == t2.tm_mon &&
    t1.tm_mday == t2.tm_mday
}

fn print_time_worked(t: &Duration, day: &Tm) {
    println!("{}: {}:{:02}",
        day.strftime("%a, %d %b %Y").unwrap(),
        t.num_hours() ,
        t.num_minutes() % 60
    );
}
<|endoftext|>