<commit_before>#[cfg(feature = "std")]
use crate::convert::Convert;
use crate::{AHasher};
#[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
use const_random::const_random;
use core::fmt;
use core::hash::BuildHasher;
use core::hash::Hasher;
#[cfg(feature = "std")]
use lazy_static::*;
use core::sync::atomic::{AtomicUsize, Ordering};

#[cfg(feature = "std")]
lazy_static! {
    static ref SEEDS: [[u64; 4]; 2] = {
        let mut result: [u8; 64] = [0; 64];
        getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
        result.convert()
    };
}
static COUNTER: AtomicUsize = AtomicUsize::new(0);

pub(crate) const PI: [u64; 4] = [
    0x243f_6a88_85a3_08d3,
    0x1319_8a2e_0370_7344,
    0xa409_3822_299f_31d0,
    0x082e_fa98_ec4e_6c89,
];

#[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
const PI2: [u64; 4] = [
    0x4528_21e6_38d0_1377,
    0xbe54_66cf_34e9_0c6c,
    0xc0ac_29b7_c97c_50dd,
    0x3f84_d5b5_b547_0917,
];

#[inline]
pub(crate) fn seeds() -> [u64; 4] {
    #[cfg(feature = "std")]
    { SEEDS[1] }
    #[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
    { [const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)] }
    #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
    { PI }
}

/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct RandomState {
    pub(crate) k0: u64,
    pub(crate) k1: u64,
    pub(crate) k2: u64,
    pub(crate) k3: u64,
}

impl fmt::Debug for RandomState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("RandomState { .. }")
    }
}

impl RandomState {
    /// Use randomly generated keys
    #[inline]
    pub fn new() -> RandomState {
        #[cfg(feature = "std")]
        {
            let seeds = *SEEDS;
            RandomState::from_keys(seeds[0], seeds[1])
        }
        #[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
        {
            RandomState::from_keys(
                [const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)],
                [const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)],
            )
        }
        #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
        {
            RandomState::from_keys(PI, PI2)
        }
    }

    /// Allows for supplying seeds, but each time it is called the resulting state will be different.
    /// This is done using a static counter, so it can safely be used with a fixed keys.
    #[inline]
    pub fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState::from_keys(seeds(), [k0, k1, k2, k3])
    }

    fn from_keys(a: [u64; 4], b: [u64; 4]) -> RandomState {
        let [k0, k1, k2, k3] = a;
        let mut hasher = AHasher::from_random_state(&RandomState { k0, k1, k2, k3 });

        let stack_mem_loc = &hasher as *const _ as usize;
        hasher.write_usize(COUNTER.fetch_add(stack_mem_loc, Ordering::Relaxed));
        #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
        hasher.write_usize(&PI as *const _ as usize);
        let mix = |k: u64| {
            let mut h = hasher.clone();
            h.write_u64(k);
            h.finish()
        };

        RandomState { k0: mix(b[0]), k1: mix(b[1]), k2: mix(b[2]), k3: mix(b[3]) }
    }

    /// Internal. Used by Default.
    #[inline]
    pub(crate) fn with_fixed_keys() -> RandomState {
        let [k0, k1, k2, k3] = seeds();
        RandomState { k0, k1, k2, k3 }
    }

    /// Allows for explicitly setting the seeds to used.
    #[inline]
    pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState { k0, k1, k2, k3 }
    }
}

impl Default for RandomState {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for RandomState {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on this [RandomState] object.
    /// This means that two different [RandomState]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, RandomState};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = RandomState::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = RandomState::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        AHasher::from_random_state(self)
    }
}

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

    #[test]
    fn test_unique() {
        let a = RandomState::new();
        let b = RandomState::new();
        assert_ne!(a.build_hasher().finish(), b.build_hasher().finish());
    }

    #[test]
    fn test_with_seeds_const() {
        const _CONST_RANDOM_STATE: RandomState = RandomState::with_seeds(17, 19, 21, 23);
    }
}
<commit_msg>Add fallback if atomic-usize is not available<commit_after>#[cfg(feature = "std")]
use crate::convert::Convert;
use crate::{AHasher};
#[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
use const_random::const_random;
use core::fmt;
use core::hash::BuildHasher;
use core::hash::Hasher;
#[cfg(feature = "std")]
use lazy_static::*;
use core::sync::atomic::{AtomicUsize, Ordering};

#[cfg(feature = "std")]
lazy_static! {
    static ref SEEDS: [[u64; 4]; 2] = {
        let mut result: [u8; 64] = [0; 64];
        getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
        result.convert()
    };
}
#[cfg(target_has_atomic = "ptr")]
static COUNTER: AtomicUsize = AtomicUsize::new(0);

pub(crate) const PI: [u64; 4] = [
    0x243f_6a88_85a3_08d3,
    0x1319_8a2e_0370_7344,
    0xa409_3822_299f_31d0,
    0x082e_fa98_ec4e_6c89,
];

#[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
const PI2: [u64; 4] = [
    0x4528_21e6_38d0_1377,
    0xbe54_66cf_34e9_0c6c,
    0xc0ac_29b7_c97c_50dd,
    0x3f84_d5b5_b547_0917,
];

#[inline]
pub(crate) fn seeds() -> [u64; 4] {
    #[cfg(feature = "std")]
    { SEEDS[1] }
    #[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
    { [const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)] }
    #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
    { PI }
}

/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct RandomState {
    pub(crate) k0: u64,
    pub(crate) k1: u64,
    pub(crate) k2: u64,
    pub(crate) k3: u64,
}

impl fmt::Debug for RandomState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("RandomState { .. }")
    }
}

impl RandomState {
    /// Use randomly generated keys
    #[inline]
    pub fn new() -> RandomState {
        #[cfg(feature = "std")]
        {
            let seeds = *SEEDS;
            RandomState::from_keys(seeds[0], seeds[1])
        }
        #[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
        {
            RandomState::from_keys(
                [const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)],
                [const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)],
            )
        }
        #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
        {
            RandomState::from_keys(PI, PI2)
        }
    }

    /// Allows for supplying seeds, but each time it is called the resulting state will be different.
    /// This is done using a static counter, so it can safely be used with a fixed keys.
    #[inline]
    pub fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState::from_keys(seeds(), [k0, k1, k2, k3])
    }

    fn from_keys(a: [u64; 4], b: [u64; 4]) -> RandomState {
        let [k0, k1, k2, k3] = a;
        let mut hasher = AHasher::from_random_state(&RandomState { k0, k1, k2, k3 });

        let stack_mem_loc = &hasher as *const _ as usize;
        #[cfg(target_has_atomic = "ptr")]
        hasher.write_usize(COUNTER.fetch_add(stack_mem_loc, Ordering::Relaxed));
        #[cfg(not(target_has_atomic = "ptr"))]
        hasher.write_usize(stack_mem_loc);
        #[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
        hasher.write_usize(&PI as *const _ as usize);
        let mix = |k: u64| {
            let mut h = hasher.clone();
            h.write_u64(k);
            h.finish()
        };

        RandomState { k0: mix(b[0]), k1: mix(b[1]), k2: mix(b[2]), k3: mix(b[3]) }
    }

    /// Internal. Used by Default.
    #[inline]
    pub(crate) fn with_fixed_keys() -> RandomState {
        let [k0, k1, k2, k3] = seeds();
        RandomState { k0, k1, k2, k3 }
    }

    /// Allows for explicitly setting the seeds to used.
    #[inline]
    pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState { k0, k1, k2, k3 }
    }
}

impl Default for RandomState {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for RandomState {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on this [RandomState] object.
    /// This means that two different [RandomState]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, RandomState};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = RandomState::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = RandomState::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        AHasher::from_random_state(self)
    }
}

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

    #[test]
    fn test_unique() {
        let a = RandomState::new();
        let b = RandomState::new();
        assert_ne!(a.build_hasher().finish(), b.build_hasher().finish());
    }

    #[test]
    fn test_with_seeds_const() {
        const _CONST_RANDOM_STATE: RandomState = RandomState::with_seeds(17, 19, 21, 23);
    }
}
<|endoftext|>


<commit_before>use crate::ignore::{Ignore, IgnoreGit, IgnoreVcs};
use crate::pipeline::{PipelineFork, PipelineInfo};
use crossbeam_channel::{Receiver, Sender};
use std::fs;
use std::path::PathBuf;
use std::time::{Duration, Instant};

// ---------------------------------------------------------------------------------------------------------------------
// PathInfo
// ---------------------------------------------------------------------------------------------------------------------

#[derive(Debug, Clone)]
pub struct PathInfo {
    pub path: PathBuf,
}

// ---------------------------------------------------------------------------------------------------------------------
// PipelineFinder
// ---------------------------------------------------------------------------------------------------------------------

pub struct PipelineFinder {
    pub is_recursive: bool,
    pub follow_symlink: bool,
    pub skip_vcs: bool,
    pub skip_gitignore: bool,
    pub skip_hgignore: bool,
    pub skip_ambignore: bool,
    pub print_skipped: bool,
    pub find_parent_ignore: bool,
    pub infos: Vec<String>,
    pub errors: Vec<String>,
    time_beg: Instant,
    time_bsy: Duration,
    seq_no: usize,
    current_tx: usize,
    ignore_vcs: IgnoreVcs,
    ignore_git: Vec<IgnoreGit>,
}

impl PipelineFinder {
    pub fn new() -> Self {
        PipelineFinder {
            is_recursive: true,
            follow_symlink: true,
            skip_vcs: true,
            skip_gitignore: true,
            skip_hgignore: true,
            skip_ambignore: true,
            print_skipped: false,
            find_parent_ignore: true,
            infos: Vec::new(),
            errors: Vec::new(),
            time_beg: Instant::now(),
            time_bsy: Duration::new(0, 0),
            seq_no: 0,
            current_tx: 0,
            ignore_vcs: IgnoreVcs::new(),
            ignore_git: Vec::new(),
        }
    }

    fn find_path(&mut self, base: PathBuf, tx: &Vec<Sender<PipelineInfo<PathInfo>>>, is_symlink: bool) {
        let attr = match fs::metadata(&base) {
            Ok(x) => x,
            Err(e) => {
                if !is_symlink {
                    self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                }
                return;
            }
        };

        if attr.is_file() {
            if attr.len() != 0 {
                self.send_path(base, &tx);
            }
        } else {
            let reader = match fs::read_dir(&base) {
                Ok(x) => x,
                Err(e) => {
                    self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                    return;
                }
            };

            let gitignore_exist = self.push_gitignore(&base);

            for i in reader {
                match i {
                    Ok(entry) => {
                        let file_type = match entry.file_type() {
                            Ok(x) => x,
                            Err(e) => {
                                self.errors.push(format!("Error: {}", e));
                                continue;
                            }
                        };
                        if file_type.is_file() {
                            self.send_path(entry.path(), &tx);
                        } else {
                            let find_dir = file_type.is_dir() & self.is_recursive;
                            let find_symlink = file_type.is_symlink() & self.is_recursive & self.follow_symlink;
                            if (find_dir | find_symlink) & self.check_path(&entry.path(), true) {
                                self.find_path(entry.path(), &tx, find_symlink);
                            }
                        }
                    }
                    Err(e) => self.errors.push(format!("Error: {}", e)),
                };
            }

            self.pop_gitignore(gitignore_exist)
        }
    }

    fn send_path(&mut self, path: PathBuf, tx: &Vec<Sender<PipelineInfo<PathInfo>>>) {
        if self.check_path(&path, false) {
            let _ = tx[self.current_tx].send(PipelineInfo::SeqDat(self.seq_no, PathInfo { path: path }));
            self.seq_no += 1;
            self.current_tx = if self.current_tx == tx.len() - 1 {
                0
            } else {
                self.current_tx + 1
            };
        }
    }

    fn push_gitignore(&mut self, path: &PathBuf) -> bool {
        if !self.skip_gitignore {
            return false;
        }

        let reader = fs::read_dir(&path).unwrap();
        for i in reader {
            match i {
                Ok(entry) => {
                    if entry.path().ends_with(".gitignore") {
                        self.ignore_git.push(IgnoreGit::new(&entry.path()));
                        return true;
                    }
                }
                Err(e) => self.errors.push(format!("Error: {}", e)),
            }
        }
        false
    }

    fn pop_gitignore(&mut self, exist: bool) {
        if exist {
            let _ = self.ignore_git.pop();
        }
    }

    fn check_path(&mut self, path: &PathBuf, is_dir: bool) -> bool {
        let ok_vcs = if self.skip_vcs {
            !self.ignore_vcs.is_ignore(&path, is_dir)
        } else {
            true
        };

        let ok_git = if self.skip_gitignore && !self.ignore_git.is_empty() {
            !self.ignore_git.last().unwrap().is_ignore(&path, is_dir)
        } else {
            true
        };

        if !ok_vcs & self.print_skipped {
            self.infos.push(format!("Skipped: {:?} ( vcs file )\n", path));
        }

        if !ok_git & self.print_skipped {
            self.infos.push(format!("Skipped: {:?} ( .gitignore )\n", path));
        }

        ok_vcs && ok_git
    }

    fn set_default_gitignore(&mut self, base: &PathBuf) -> PathBuf {
        if !self.skip_gitignore {
            return base.clone();
        }
        if !self.find_parent_ignore {
            return base.clone();
        }

        let base_abs = match base.canonicalize() {
            Ok(x) => x,
            Err(e) => {
                self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                return base.clone();
            }
        };

        let mut parent_abs = base_abs.parent();
        let mut parent = base.clone();
        if parent.is_dir() {
            parent.push("..");
        } else {
            parent = parent.parent().unwrap().to_path_buf();
        }
        while parent_abs.is_some() {
            if self.push_gitignore(&PathBuf::from(&parent)) {
                self.infos
                    .push(format!("Found .gitignore at the parent directory: {:?}\n", parent));
                return base.clone();
            }
            parent_abs = parent_abs.unwrap().parent();
            parent.push("..");
        }

        return base.clone();
    }
}

impl PipelineFork<PathBuf, PathInfo> for PipelineFinder {
    fn setup(&mut self, id: usize, rx: Receiver<PipelineInfo<PathBuf>>, tx: Vec<Sender<PipelineInfo<PathInfo>>>) {
        self.infos = Vec::new();
        self.errors = Vec::new();
        let mut seq_beg_arrived = false;

        loop {
            match rx.recv() {
                Ok(PipelineInfo::SeqDat(_, p)) => {
                    watch_time!(self.time_bsy, {
                        let p = self.set_default_gitignore(&p);
                        self.find_path(p, &tx, false);
                    });
                }

                Ok(PipelineInfo::SeqBeg(x)) => {
                    if !seq_beg_arrived {
                        self.seq_no = x;
                        self.time_beg = Instant::now();

                        for tx in &tx {
                            let _ = tx.send(PipelineInfo::SeqBeg(x));
                        }

                        seq_beg_arrived = true;
                    }
                }

                Ok(PipelineInfo::SeqEnd(_)) => {
                    for i in &self.infos {
                        let _ = tx[0].send(PipelineInfo::MsgInfo(id, i.clone()));
                    }
                    for e in &self.errors {
                        let _ = tx[0].send(PipelineInfo::MsgErr(id, e.clone()));
                    }

                    let _ = tx[0].send(PipelineInfo::MsgTime(id, self.time_bsy, self.time_beg.elapsed()));

                    for tx in &tx {
                        let _ = tx.send(PipelineInfo::SeqEnd(self.seq_no));
                    }

                    break;
                }

                Ok(PipelineInfo::MsgInfo(i, e)) => {
                    let _ = tx[0].send(PipelineInfo::MsgInfo(i, e));
                }
                Ok(PipelineInfo::MsgErr(i, e)) => {
                    let _ = tx[0].send(PipelineInfo::MsgErr(i, e));
                }
                Ok(PipelineInfo::MsgTime(i, t0, t1)) => {
                    let _ = tx[0].send(PipelineInfo::MsgTime(i, t0, t1));
                }
                Err(_) => break,
            }
        }
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// Test
// ---------------------------------------------------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use crate::pipeline::{PipelineFork, PipelineInfo};
    use crossbeam_channel::unbounded;
    use std::path::{Path, PathBuf};
    use std::thread;

    fn test<T: 'static + PipelineFork<PathBuf, PathInfo> + Send>(mut finder: T, path: String) -> Vec<PathInfo> {
        let (in_tx, in_rx) = unbounded();
        let (out_tx, out_rx) = unbounded();
        thread::spawn(move || {
            finder.setup(0, in_rx, vec![out_tx]);
        });
        let _ = in_tx.send(PipelineInfo::SeqBeg(0));
        let _ = in_tx.send(PipelineInfo::SeqDat(0, PathBuf::from(path)));
        let _ = in_tx.send(PipelineInfo::SeqEnd(1));

        let mut ret = Vec::new();
        loop {
            match out_rx.recv().unwrap() {
                PipelineInfo::SeqDat(_, x) => ret.push(x),
                PipelineInfo::SeqEnd(_) => break,
                _ => (),
            }
        }

        ret
    }

    #[test]
    fn pipeline_finder_default() {
        if !Path::new("./.git/config").exists() {
            fs::create_dir_all("./.git").unwrap();
            fs::File::create("./.git/config").unwrap();
        }

        let finder = PipelineFinder::new();
        let ret = test(finder, "./".to_string());

        assert!(ret.iter().any(|x| x.path == PathBuf::from("./Cargo.toml")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambr.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambs.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/console.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/lib.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/matcher.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/util.rs")));
        assert!(!ret.iter().any(|x| x.path == PathBuf::from("./.git/config")));
    }

    #[test]
    fn pipeline_finder_not_skip_vcs() {
        if !Path::new("./.git/config").exists() {
            fs::create_dir_all("./.git").unwrap();
            fs::File::create("./.git/config").unwrap();
        }

        let mut finder = PipelineFinder::new();
        finder.skip_vcs = false;
        let ret = test(finder, "./".to_string());

        assert!(ret.iter().any(|x| x.path == PathBuf::from("./Cargo.toml")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambr.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambs.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/console.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/lib.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/matcher.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/util.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./.git/config")));
    }
}
<commit_msg>Fix panic #36<commit_after>use crate::ignore::{Ignore, IgnoreGit, IgnoreVcs};
use crate::pipeline::{PipelineFork, PipelineInfo};
use crossbeam_channel::{Receiver, Sender};
use std::fs;
use std::path::PathBuf;
use std::time::{Duration, Instant};

// ---------------------------------------------------------------------------------------------------------------------
// PathInfo
// ---------------------------------------------------------------------------------------------------------------------

#[derive(Debug, Clone)]
pub struct PathInfo {
    pub path: PathBuf,
}

// ---------------------------------------------------------------------------------------------------------------------
// PipelineFinder
// ---------------------------------------------------------------------------------------------------------------------

pub struct PipelineFinder {
    pub is_recursive: bool,
    pub follow_symlink: bool,
    pub skip_vcs: bool,
    pub skip_gitignore: bool,
    pub skip_hgignore: bool,
    pub skip_ambignore: bool,
    pub print_skipped: bool,
    pub find_parent_ignore: bool,
    pub infos: Vec<String>,
    pub errors: Vec<String>,
    time_beg: Instant,
    time_bsy: Duration,
    seq_no: usize,
    current_tx: usize,
    ignore_vcs: IgnoreVcs,
    ignore_git: Vec<IgnoreGit>,
}

impl PipelineFinder {
    pub fn new() -> Self {
        PipelineFinder {
            is_recursive: true,
            follow_symlink: true,
            skip_vcs: true,
            skip_gitignore: true,
            skip_hgignore: true,
            skip_ambignore: true,
            print_skipped: false,
            find_parent_ignore: true,
            infos: Vec::new(),
            errors: Vec::new(),
            time_beg: Instant::now(),
            time_bsy: Duration::new(0, 0),
            seq_no: 0,
            current_tx: 0,
            ignore_vcs: IgnoreVcs::new(),
            ignore_git: Vec::new(),
        }
    }

    fn find_path(&mut self, base: PathBuf, tx: &Vec<Sender<PipelineInfo<PathInfo>>>, is_symlink: bool) {
        let attr = match fs::metadata(&base) {
            Ok(x) => x,
            Err(e) => {
                if !is_symlink {
                    self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                }
                return;
            }
        };

        if attr.is_file() {
            if attr.len() != 0 {
                self.send_path(base, &tx);
            }
        } else {
            let reader = match fs::read_dir(&base) {
                Ok(x) => x,
                Err(e) => {
                    self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                    return;
                }
            };

            let gitignore_exist = self.push_gitignore(&base);

            for i in reader {
                match i {
                    Ok(entry) => {
                        let file_type = match entry.file_type() {
                            Ok(x) => x,
                            Err(e) => {
                                self.errors.push(format!("Error: {}", e));
                                continue;
                            }
                        };
                        if file_type.is_file() {
                            self.send_path(entry.path(), &tx);
                        } else {
                            let find_dir = file_type.is_dir() & self.is_recursive;
                            let find_symlink = file_type.is_symlink() & self.is_recursive & self.follow_symlink;
                            if (find_dir | find_symlink) & self.check_path(&entry.path(), true) {
                                self.find_path(entry.path(), &tx, find_symlink);
                            }
                        }
                    }
                    Err(e) => self.errors.push(format!("Error: {}", e)),
                };
            }

            self.pop_gitignore(gitignore_exist)
        }
    }

    fn send_path(&mut self, path: PathBuf, tx: &Vec<Sender<PipelineInfo<PathInfo>>>) {
        if self.check_path(&path, false) {
            let _ = tx[self.current_tx].send(PipelineInfo::SeqDat(self.seq_no, PathInfo { path: path }));
            self.seq_no += 1;
            self.current_tx = if self.current_tx == tx.len() - 1 {
                0
            } else {
                self.current_tx + 1
            };
        }
    }

    fn push_gitignore(&mut self, path: &PathBuf) -> bool {
        if !self.skip_gitignore {
            return false;
        }

        if let Ok(reader) = fs::read_dir(&path) {
            for i in reader {
                match i {
                    Ok(entry) => {
                        if entry.path().ends_with(".gitignore") {
                            self.ignore_git.push(IgnoreGit::new(&entry.path()));
                            return true;
                        }
                    }
                    Err(e) => self.errors.push(format!("Error: {}", e)),
                }
            }
        }
        false
    }

    fn pop_gitignore(&mut self, exist: bool) {
        if exist {
            let _ = self.ignore_git.pop();
        }
    }

    fn check_path(&mut self, path: &PathBuf, is_dir: bool) -> bool {
        let ok_vcs = if self.skip_vcs {
            !self.ignore_vcs.is_ignore(&path, is_dir)
        } else {
            true
        };

        let ok_git = if self.skip_gitignore && !self.ignore_git.is_empty() {
            !self.ignore_git.last().unwrap().is_ignore(&path, is_dir)
        } else {
            true
        };

        if !ok_vcs & self.print_skipped {
            self.infos.push(format!("Skipped: {:?} ( vcs file )\n", path));
        }

        if !ok_git & self.print_skipped {
            self.infos.push(format!("Skipped: {:?} ( .gitignore )\n", path));
        }

        ok_vcs && ok_git
    }

    fn set_default_gitignore(&mut self, base: &PathBuf) -> PathBuf {
        if !self.skip_gitignore {
            return base.clone();
        }
        if !self.find_parent_ignore {
            return base.clone();
        }

        let base_abs = match base.canonicalize() {
            Ok(x) => x,
            Err(e) => {
                self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                return base.clone();
            }
        };

        let mut parent_abs = base_abs.parent();
        let mut parent = base.clone();
        if parent.is_dir() {
            parent.push("..");
        } else {
            parent = parent.parent().unwrap().to_path_buf();
        }
        while parent_abs.is_some() {
            if self.push_gitignore(&PathBuf::from(&parent)) {
                self.infos
                    .push(format!("Found .gitignore at the parent directory: {:?}\n", parent));
                return base.clone();
            }
            parent_abs = parent_abs.unwrap().parent();
            parent.push("..");
        }

        return base.clone();
    }
}

impl PipelineFork<PathBuf, PathInfo> for PipelineFinder {
    fn setup(&mut self, id: usize, rx: Receiver<PipelineInfo<PathBuf>>, tx: Vec<Sender<PipelineInfo<PathInfo>>>) {
        self.infos = Vec::new();
        self.errors = Vec::new();
        let mut seq_beg_arrived = false;

        loop {
            match rx.recv() {
                Ok(PipelineInfo::SeqDat(_, p)) => {
                    watch_time!(self.time_bsy, {
                        let p = self.set_default_gitignore(&p);
                        self.find_path(p, &tx, false);
                    });
                }

                Ok(PipelineInfo::SeqBeg(x)) => {
                    if !seq_beg_arrived {
                        self.seq_no = x;
                        self.time_beg = Instant::now();

                        for tx in &tx {
                            let _ = tx.send(PipelineInfo::SeqBeg(x));
                        }

                        seq_beg_arrived = true;
                    }
                }

                Ok(PipelineInfo::SeqEnd(_)) => {
                    for i in &self.infos {
                        let _ = tx[0].send(PipelineInfo::MsgInfo(id, i.clone()));
                    }
                    for e in &self.errors {
                        let _ = tx[0].send(PipelineInfo::MsgErr(id, e.clone()));
                    }

                    let _ = tx[0].send(PipelineInfo::MsgTime(id, self.time_bsy, self.time_beg.elapsed()));

                    for tx in &tx {
                        let _ = tx.send(PipelineInfo::SeqEnd(self.seq_no));
                    }

                    break;
                }

                Ok(PipelineInfo::MsgInfo(i, e)) => {
                    let _ = tx[0].send(PipelineInfo::MsgInfo(i, e));
                }
                Ok(PipelineInfo::MsgErr(i, e)) => {
                    let _ = tx[0].send(PipelineInfo::MsgErr(i, e));
                }
                Ok(PipelineInfo::MsgTime(i, t0, t1)) => {
                    let _ = tx[0].send(PipelineInfo::MsgTime(i, t0, t1));
                }
                Err(_) => break,
            }
        }
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// Test
// ---------------------------------------------------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use crate::pipeline::{PipelineFork, PipelineInfo};
    use crossbeam_channel::unbounded;
    use std::path::{Path, PathBuf};
    use std::thread;

    fn test<T: 'static + PipelineFork<PathBuf, PathInfo> + Send>(mut finder: T, path: String) -> Vec<PathInfo> {
        let (in_tx, in_rx) = unbounded();
        let (out_tx, out_rx) = unbounded();
        thread::spawn(move || {
            finder.setup(0, in_rx, vec![out_tx]);
        });
        let _ = in_tx.send(PipelineInfo::SeqBeg(0));
        let _ = in_tx.send(PipelineInfo::SeqDat(0, PathBuf::from(path)));
        let _ = in_tx.send(PipelineInfo::SeqEnd(1));

        let mut ret = Vec::new();
        loop {
            match out_rx.recv().unwrap() {
                PipelineInfo::SeqDat(_, x) => ret.push(x),
                PipelineInfo::SeqEnd(_) => break,
                _ => (),
            }
        }

        ret
    }

    #[test]
    fn pipeline_finder_default() {
        if !Path::new("./.git/config").exists() {
            fs::create_dir_all("./.git").unwrap();
            fs::File::create("./.git/config").unwrap();
        }

        let finder = PipelineFinder::new();
        let ret = test(finder, "./".to_string());

        assert!(ret.iter().any(|x| x.path == PathBuf::from("./Cargo.toml")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambr.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambs.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/console.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/lib.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/matcher.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/util.rs")));
        assert!(!ret.iter().any(|x| x.path == PathBuf::from("./.git/config")));
    }

    #[test]
    fn pipeline_finder_not_skip_vcs() {
        if !Path::new("./.git/config").exists() {
            fs::create_dir_all("./.git").unwrap();
            fs::File::create("./.git/config").unwrap();
        }

        let mut finder = PipelineFinder::new();
        finder.skip_vcs = false;
        let ret = test(finder, "./".to_string());

        assert!(ret.iter().any(|x| x.path == PathBuf::from("./Cargo.toml")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambr.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambs.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/console.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/lib.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/matcher.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/util.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./.git/config")));
    }
}
<|endoftext|>


<commit_before>use player;
use player::Player;
use arena::Arena;
use super::enums;
use super::moves::Technique;
//use super::resolve;
use super::pokemon_token::PokemonToken;
use super::movedex::Movedex;
//use super::moves::Technique;
use self::rand::{Rng, thread_rng};

extern crate rand;

pub fn test(){
    println!("Unique");
    for entry in Movedex::new().get_entries() {
         if entry.get_category() == enums::MoveCategory::Unique {
             println!("{:?}: {:?} - {:?}", entry.get_id(), entry.get_name(), entry.get_type());
         }
    }
}

pub fn test2(){
    println!("Unique");
    for entry in Movedex::new().get_entries() {
         if entry.get_category() == enums::MoveCategory::Unique {
             println!("{:?}", entry.get_name());
         }
    }
}

pub fn unique(attack: &Technique, name: &str, move_type: enums::Types, mut user: PokemonToken, mut target: PokemonToken, attacker: &mut Player, defender: &mut Player, arena: &mut Arena) {
    let movedex = Movedex::new();
    let mut rng = thread_rng();

    // target.get_moves(dex.move_by_id());
    // match dex.get_entries() {
    match name {
        "disable" => {
            println!("disable" );
        },
        "teleport" => {
            println!("teleport");
        },
        "mimic" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id()).unwrap();
            attack.resolve(arena, 1);
        },
        "focus-energy" => {
        },
        "metronome" => {
            let random = rng.gen_range(1, 616);
            let attack = movedex.move_by_id(random).unwrap();
            attack.resolve(arena, 1);
        },
        "mirror-move" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id()).unwrap();
            attack.resolve(arena, 1);
        },
        "nature-power" => {
            match arena.get_current_effect().0 {
                enums::Types::Normal => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "tri-attack" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Flying => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "air-slash" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Ground => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "earth_power" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Rock => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "power_gem" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Fire => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "lava_plume" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Water => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "hydro_pump" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Grass => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "energy-ball" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Electric => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "thunderbolt" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Ice => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "ice_beam" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                _ => {},
            }
        },
        // "transform" => {
        // },
        "splash" => {
            if arena.get_current_effect().0 == enums::Types::Flying{
                println!("The attack can not be used because {:?} is activated.", enums::Types::Flying);
            }else{
                println!("Nothing happens...");
            }
        },
        "rest" => {
            for entry in Movedex::new().get_entries() {
                if entry.get_name() == "rest" {
                    ////Fehler muss noch behofen werden
                    //let mut user_clone = moves::get_user(1, arena).clone();
                    // resolve::ailment("rest",
                    //                  entry.get_type(),
                    //                  entry.get_ailment(),
                    //                  100,
                    //                  user,
                    //                  &mut target,
                    //                  defender);
                }
            }

        },
        "conversion" => {
            user.set_type(0, attack.get_type());
        },
        "spite" => {
            // defender.get_last_move().unwrap().0.get_power_points();
            // target.decrement_ap();
        },
        "sleep-talk" => {
            struct AllMoves {
                one: String,
                two: String,
                three: String,
                four: String,
            }
            // let one: String;;
            let mut moves = AllMoves {one: "".to_string(), two: "".to_string(), three: "".to_string(), four: "".to_string(), };
            if user.is_asleep(){
                if attacker.get_attack(&player::AttackSlot::One).get_name() != "sleep-talk"{
                    // moves.one = attacker.get_attack(&player::AttackSlot::One).get_name();
                    moves.one = attacker.get_attack(&player::AttackSlot::One).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Two).get_name() != "sleep-talk"{
                    moves.two = attacker.get_attack(&player::AttackSlot::Two).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Three).get_name() != "sleep-talk"{
                    moves.three = attacker.get_attack(&player::AttackSlot::Three).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Four).get_name() != "sleep-talk"{
                    moves.four = attacker.get_attack(&player::AttackSlot::Four).get_name().to_string();
                }

                let mut random = rng.gen_range(1, 4);
                loop {
                    match random {
                        1 => {
                            if moves.one == "".to_string(){
                                random = rng.gen_range(2, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::One).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        2 => {
                            if moves.two == "".to_string(){
                                random = rng.gen_range(1, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Two).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        3 => {
                            if moves.three == "".to_string(){
                                random = rng.gen_range(1, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Three).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        4 => {
                            if moves.four == "".to_string(){
                                random = rng.gen_range(1, 3);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Four).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        _=> { random = rng.gen_range(1, 4); }
                    }
                }
            }
        },
        "celebrate" => {
            println!("{:?} disappears and then rises out of a birthday present that falls into the picture from above.", user.get_name());
        },
        "powder" => {
            if target.get_types().0 == enums::Types::Grass || target.get_types().1 == enums::Types::Grass{
                println!("{:?} has no effect on  Pokemon type plants", name);
            }
        },
        "reflect-type" => {
            user.set_type(0, target.get_types().0);
            user.set_type(1, target.get_types().1);
        },
        "soak" => {
            target.set_type(0, enums::Types::Water);
            target.set_type(1, enums::Types::Water);
        },
        // "conversion-2" => {
        // },
        // "substitute" => {
        // },
        // "sketch" => {
        // },
        // "spider-web" => {
        // },
        // "mind-reader" => {
        // },
        // "curse" => {
        // },
        // "protect" => {
        // },
        // "belly-drum" => {
        // },
        // "destiny-bond" => {
        // },
        // "detect" => {
        // },
        // "lock-on" => {
        // },
        // "endure" => {
        // },
        // "mean-look" => {
        // },
        // "heal-bell" => {
        // },
        // "pain-split" => {
        // },
        // "baton-pass" => {
        // },
        // "encore" => {
        // },
        // "psych-up" => {
        // },
        // "future-sight" => {
        // },
        // "stockpile" => {
        // },
        // "memento" => {
        // },
        // "follow-me" => {
        // },
        // "taunt" => {
        // },
        // "helping-hand" => {
        // },
        // "trick" => {
        // },
        // "role-play" => {
        // },
        // "wish" => {
        // },
        // "assist" => {
        // },
        // "magic-coat" => {
        // },
        // "recycle" => {
        // },
        // "skill-swap" => {
        // },
        // "imprison" => {
        // },
        // "refresh" => {
        // },
        // "grudge" => {
        // },
        // "snatch" => {
        // },
        // "camouflage" => {
        // },
        // "aromatherapy" => {
        // },
        // "block" => {
        // },
        // "doom-desire" => {
        // },
        // "healing-wish" => {
        // },
        // "acupressure" => {
        // },
        // "psycho-shift" => {
        // },
        // "power-trick" => {
        // },
        // "gastro-acid" => {
        // },
        // "copycat" => {
        // },
        // "power-swap" => {
        // },
        // "guard-swap" => {
        // },
        // "worry-seed" => {
        // },
        // "heart-swap" => {
        // },
        // "aqua-ring" => {
        // },
        // "magnet-rise" => {
        // },
        // "switcheroo" => {
        // },
        // "defog" => {
        // },
        // "lunar-dance" => {
        // },
        // "guard-split" => {
        // },
        // "power-split" => {
        // },
        // "rage-powder" => {
        // },
        // "simple-beam" => {
        // },
        // "entrainment" => {
        // },
        // "after-you" => {
        // },
        // "ally-switch" => {
        // },
        // "shell-smash" => {
        // },
        // "quash" => {
        // },
        // "bestow" => {
        // },
        // "trick-or-treat" => {
        // },
        // "forests-curse" => {
        // },
        // "topsy-turvy" => {
        // },
        // "flower-shield" => {
        // },
        // "electrify" => {
        // },
        // "kings-shield" => {
        // },
        // "spiky-shield" => {
        // },
        // "happy-hour" => {
        // },
        // "hold-hands" => {
        // },
        _ => {},
    };
}
<commit_msg>addunique.rs<commit_after><|endoftext|>


<commit_before>//! The module for rendering

use std::path::Path;

use piston::event::RenderArgs;

use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;

use graphics;
use graphics::Transformed;

pub struct Renderer {
  font: GlyphCache<'static>,
  text: graphics::text::Text,
}

impl Renderer {
  pub fn new() -> Renderer {
    Renderer {
      font: GlyphCache::new(Path::new("./assets/MathJax.otf")).unwrap(),
      text: graphics::text::Text::new(10)
    }
  }

  pub fn draw_text(&mut self, args: &RenderArgs, gl: &mut GlGraphics, s: &str) {
    gl.draw(args.viewport(), |c, gl| {
      self.text.draw(s,
                     &mut self.font,
                     graphics::default_draw_state(),
                     c.trans(10.0, 20.0).transform,
                     gl );
    });
  }
}
<commit_msg>Bump up font size<commit_after>//! The module for rendering

use std::path::Path;

use piston::event::RenderArgs;

use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;

use graphics;
use graphics::Transformed;

pub struct Renderer {
  font: GlyphCache<'static>,
  text: graphics::text::Text,
}

impl Renderer {
  pub fn new() -> Renderer {
    Renderer {
      font: GlyphCache::new(Path::new("./assets/MathJax.otf")).unwrap(),
      text: graphics::text::Text::new(20)
    }
  }

  pub fn draw_text(&mut self, args: &RenderArgs, gl: &mut GlGraphics, s: &str) {
    gl.draw(args.viewport(), |c, gl| {
      self.text.draw(s,
                     &mut self.font,
                     graphics::default_draw_state(),
                     c.trans(10.0, 20.0).transform,
                     gl );
    });
  }
}
<|endoftext|>


<commit_before>//! An augmentation of the rust-http Response struct.

use std::io::{IoResult, File};
use std::io::util::copy;

pub use Response = http::server::response::ResponseWriter;

mod mimes;

/// Allow file-serving
pub trait ServeFile: Writer {
    /// Serve the file located at `path`.
    ///
    /// This is usually a terminal process, and `Middleware` may want to
    /// call `Unwind` after a file is served. If the status should be
    /// anything other than `200`, the `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will err out if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. Middleware should handle this gracefully.
    fn serve_file(&mut self, &Path) -> IoResult<()>;
}

impl<'a> ServeFile for Response<'a> {
    fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let mut file = try!(File::open(path));
        copy(&mut file, self)
    }
}
<commit_msg>(feat) Added content-type to Response::serve_file.<commit_after>//! An augmentation of the rust-http Response struct.

use std::io::{IoResult, File};
use std::io::util::copy;

pub use Response = http::server::response::ResponseWriter;

use self::mimes::get_content_type;

mod mimes;

/// Allow file-serving
pub trait ServeFile: Writer {
    /// Serve the file located at `path`.
    ///
    /// This is usually a terminal process, and `Middleware` may want to
    /// call `Unwind` after a file is served. If the status should be
    /// anything other than `200`, the `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will err out if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. Middleware should handle this gracefully.
    fn serve_file(&mut self, &Path) -> IoResult<()>;
}

impl<'a> ServeFile for Response<'a> {
    fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let mut file = try!(File::open(path));
        self.headers.content_type = get_content_type(path);
        copy(&mut file, self)
    }
}
<|endoftext|>


<commit_before>pub fn is_match(s: String, p: String) -> bool {
    //rec_match(s.as_bytes(), p.as_bytes())
    println!("{}, {}", s, p);
    no_rec_match(s.as_bytes(), p.as_bytes())
}

fn rec_match(s: &[u8], p: &[u8]) -> bool {
    if s.is_empty() && p.is_empty() {
        return true;
    }

    if p.is_empty() && !s.is_empty() {
        return false;
    }

    if !p.is_empty() && s.is_empty() && p[0] != b'*' {
        return false;
    }

    match p[0] {
        b'*' => {
            let mut pos = 1;
            {
                for i in 0..p.len() {
                    if p[i] != b'*' {
                        pos = i;
                        break;
                    };
                }
            }
            //dbg!(pos);
            for i in (0..s.len() + 1).rev() {
                let (_, right) = s.split_at(i);
                if rec_match(right, &p[pos..]) {
                    return true;
                }
            }
            return false;
        }
        b'?' => rec_match(&s[1..], &p[1..]),
        _ => {
            if p[0] != s[0] {
                return false;
            } else {
                rec_match(&s[1..], &p[1..])
            }
        }
    }
}

// fast version
fn no_rec_match(s: &[u8], p: &[u8]) -> bool {
    let (mut i, mut j) = (0, 0);
    let (mut last_match, mut start) = (0, -1);

    while i < s.len() {
        println!(
            "i: {}, j: {}, last_match: {}, start: {}",
            i, j, last_match, start
        );
        if j < p.len() && (p[j] == b'?' || s[i] == p[j]) {
            i += 1;
            j += 1;
        } else if j < p.len() && p[j] == b'*' {
            start = j as i32;
            last_match = i;
            j += 1;
        } else if start != -1 {
            j = start as usize + 1;
            last_match += 1;
            i = last_match;
        } else {
            return false;
        }
    }
    println!(
        "finally: i: {}, j: {}, last_match: {}, start: {}",
        i, j, last_match, start
    );
    while j < p.len() && p[j] == b'*' {
        j += 1;
    }

    j == p.len()
}

fn main() {
    //assert!(is_match("".to_string(), "".to_string()));
    //assert!(is_match("".to_string(), "*".to_string()));

    assert!(!is_match("aa".to_string(), "a".to_string()));
    assert!(is_match("aa".to_string(), "*".to_string()));
    assert!(!is_match("cb".to_string(), "?a".to_string()));
    assert!(is_match("adceb".to_string(), "*a*b".to_string()));
    //assert!(!is_match("acdcb".to_string(), "a*c?b".to_string()));

    // assert!(!is_match(
    //     "mississippi".to_string(),
    //     "m??*ss*?i*pi".to_string()
    // ));

    // assert!(!is_match(
    //     "aaabbbaabaaaaababaabaaabbabbbbbbbbaabababbabbbaaaaba".to_string(),
    //     "a*******b".to_string()
    // ));

    // assert!(!is_match(
    //         "abbabaaabbabbaababbabbbbbabbbabbbabaaaaababababbbabababaabbababaabbbbbbaaaabababbbaabbbbaabbbbababababbaabbaababaabbbababababbbbaaabbbbbabaaaabbababbbbaababaabbababbbbbababbbabaaaaaaaabbbbbaabaaababaaaabb".to_string(),
    //         "**aa*****ba*a*bb**aa*ab****a*aaaaaa***a*aaaa**bbabb*b*b**aaaaaaaaa*a********ba*bbb***a*ba*bb*bb**a*b*bb"
    // .to_string()
    //     ));
}
<commit_msg>a bit<commit_after>pub fn is_match(s: String, p: String) -> bool {
    //rec_match(s.as_bytes(), p.as_bytes())
    println!("{}, {}", s, p);
    no_rec_match(s.as_bytes(), p.as_bytes())
}

fn rec_match(s: &[u8], p: &[u8]) -> bool {
    if s.is_empty() && p.is_empty() {
        return true;
    }

    if p.is_empty() && !s.is_empty() {
        return false;
    }

    if !p.is_empty() && s.is_empty() && p[0] != b'*' {
        return false;
    }

    match p[0] {
        b'*' => {
            let mut pos = 1;
            {
                for i in 0..p.len() {
                    if p[i] != b'*' {
                        pos = i;
                        break;
                    };
                }
            }
            //dbg!(pos);
            for i in (0..s.len() + 1).rev() {
                let (_, right) = s.split_at(i);
                if rec_match(right, &p[pos..]) {
                    return true;
                }
            }
            return false;
        }
        b'?' => rec_match(&s[1..], &p[1..]),
        _ => {
            if p[0] != s[0] {
                return false;
            } else {
                rec_match(&s[1..], &p[1..])
            }
        }
    }
}

// fast version
fn no_rec_match(s: &[u8], p: &[u8]) -> bool {
    let (mut i, mut j) = (0, 0);
    let (mut last_match, mut start) = (0, -1);

    while i < s.len() {
        println!(
            "i: {}, j: {}, last_match: {}, start: {}",
            i, j, last_match, start
        );
        if j < p.len() && (p[j] == b'?' || s[i] == p[j]) {
            i += 1;
            j += 1;
        } else if j < p.len() && p[j] == b'*' {
            start = j as i32;
            last_match = i;
            j += 1;
        } else if start != -1 {
            j = start as usize + 1;
            last_match += 1;
            i = last_match;
        } else {
            return false;
        }
    }
    println!(
        "finally: i: {}, j: {}, last_match: {}, start: {}",
        i, j, last_match, start
    );
    while j < p.len() && p[j] == b'*' {
        j += 1;
    }

    j == p.len()
}

fn main() {
    assert!(is_match("".to_string(), "".to_string()));
    assert!(is_match("".to_string(), "*".to_string()));

    assert!(!is_match("aa".to_string(), "a".to_string()));
    assert!(is_match("aa".to_string(), "*".to_string()));
    assert!(!is_match("cb".to_string(), "?a".to_string()));
    assert!(is_match("adceb".to_string(), "*a*b".to_string()));
    assert!(!is_match("acdcb".to_string(), "a*c?b".to_string()));

    assert!(!is_match(
        "mississippi".to_string(),
        "m??*ss*?i*pi".to_string()
    ));

    assert!(!is_match(
        "aaabbbaabaaaaababaabaaabbabbbbbbbbaabababbabbbaaaaba".to_string(),
        "a*******b".to_string()
    ));

    assert!(!is_match(
            "abbabaaabbabbaababbabbbbbabbbabbbabaaaaababababbbabababaabbababaabbbbbbaaaabababbbaabbbbaabbbbababababbaabbaababaabbbababababbbbaaabbbbbabaaaabbababbbbaababaabbababbbbbababbbabaaaaaaaabbbbbaabaaababaaaabb".to_string(),
            "**aa*****ba*a*bb**aa*ab****a*aaaaaa***a*aaaa**bbabb*b*b**aaaaaaaaa*a********ba*bbb***a*ba*bb*bb**a*b*bb"
    .to_string()
        ));
}
<|endoftext|>


<commit_before>/*!
Querying SDL Version
 */

use std::fmt;
use std::c_str::CString;

#[doc(hidden)]
#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{uint8_t, c_char, c_int};
    pub struct SDL_version {
        pub major: uint8_t,
        pub minor: uint8_t,
        pub patch: uint8_t,
    }
    extern "C" {
        pub fn SDL_GetVersion(ver: *mut SDL_version);
        pub fn SDL_GetRevision() -> *c_char;
        pub fn SDL_GetRevisionNumber() -> c_int;
    }
}

/// A structure that contains information about the version of SDL in use.
#[deriving(Eq, Clone)]
pub struct Version {
    /// major version
    pub major: int,
    /// minor version
    pub minor: int,
    /// update version (patchlevel)
    pub patch: int,
}

impl Version {
    /// Converts a raw *SDL_version to Version
    pub fn from_ll(sv: *ll::SDL_version) -> Version {
        unsafe {
            let v = *sv;
            Version{ major: v.major as int, minor: v.minor as int, patch: v.patch as int }
        }
    }
}

impl fmt::Show for Version {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
    }
}

/// Get the version of SDL that is linked against your program.
pub fn get_version() -> Version {
    unsafe {
        let mut cver = ll::SDL_version { major: 0, minor: 0, patch: 0};
        ll::SDL_GetVersion(&mut cver);
        Version::from_ll(&cver)
    }
}

/// Get the code revision of SDL that is linked against your program.
pub fn get_revision() -> ~str {
    unsafe {
        let ret = ll::SDL_GetRevision();
        CString::new(ret, false).as_str().unwrap().into_owned()
    }
}

/// Get the revision number of SDL that is linked against your program.
pub fn get_revision_number() -> int {
    unsafe {
        ll::SDL_GetRevisionNumber() as int
    }
}
<commit_msg>fix typo in doc comment<commit_after>/*!
Querying SDL Version
 */

use std::fmt;
use std::c_str::CString;

#[doc(hidden)]
#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{uint8_t, c_char, c_int};
    pub struct SDL_version {
        pub major: uint8_t,
        pub minor: uint8_t,
        pub patch: uint8_t,
    }
    extern "C" {
        pub fn SDL_GetVersion(ver: *mut SDL_version);
        pub fn SDL_GetRevision() -> *c_char;
        pub fn SDL_GetRevisionNumber() -> c_int;
    }
}

/// A structure that contains information about the version of SDL in use.
#[deriving(Eq, Clone)]
pub struct Version {
    /// major version
    pub major: int,
    /// minor version
    pub minor: int,
    /// update version (patchlevel)
    pub patch: int,
}

impl Version {
    /// Convert a raw *SDL_version to Version.
    pub fn from_ll(sv: *ll::SDL_version) -> Version {
        unsafe {
            let v = *sv;
            Version{ major: v.major as int, minor: v.minor as int, patch: v.patch as int }
        }
    }
}

impl fmt::Show for Version {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
    }
}

/// Get the version of SDL that is linked against your program.
pub fn get_version() -> Version {
    unsafe {
        let mut cver = ll::SDL_version { major: 0, minor: 0, patch: 0};
        ll::SDL_GetVersion(&mut cver);
        Version::from_ll(&cver)
    }
}

/// Get the code revision of SDL that is linked against your program.
pub fn get_revision() -> ~str {
    unsafe {
        let ret = ll::SDL_GetRevision();
        CString::new(ret, false).as_str().unwrap().into_owned()
    }
}

/// Get the revision number of SDL that is linked against your program.
pub fn get_revision_number() -> int {
    unsafe {
        ll::SDL_GetRevisionNumber() as int
    }
}
<|endoftext|>


<commit_before>use core::fmt;

/// Specifies which element to load into a segment from
/// descritor tables (LDT or GDT).
bitflags! {
    flags SegmentSelector: u16 {
        /// Requestor Privilege Level
        const RPL_0 = 0b00,
        const RPL_1 = 0b01,
        const RPL_2 = 0b10,
        const RPL_3 = 0b11,

        /// Table Indicator (TI) 0 means GDT is used.
        const TI_GDT = 0 << 3,
        /// Table Indicator (TI) 1 means LDT is used.
        const TI_LDT = 1 << 3,
    }
}

impl SegmentSelector {
    /// Create a new SegmentSelector
    ///
    /// # Arguments
    ///  * `index` index in GDT or LDT array.
    ///
    pub fn new(index: u16) -> SegmentSelector {
        SegmentSelector{bits: index << 3}
    }
}

/// Entry in GDT or LDT. Provides size and location of a segment.
bitflags! {
    flags SegmentDescriptor: u64 {
        /// Descriptor type (0 = system; 1 = code or data).
        const DESC_S    = 1 << (32+12),
        /// Descriptor privilege level 0.
        const DESC_DPL0 = 0b00 << (32+13),
        /// Descriptor privilege level 1.
        const DESC_DPL1 = 0b01 << (32+13),
        /// Descriptor privilege level 2.
        const DESC_DPL2 = 0b10 << (32+13),
        /// Descriptor privilege level 3.
        const DESC_DPL3 = 0b11 << (32+13),
        /// Descriptor is Present.
        const DESC_P = 1 << (32+15),
        /// Available for use by system software.
        const DESC_AVL  = 1 << (32+20),
        /// 64-bit code segment (IA-32e mode only).
        const DESC_L    = 1 << (32+21),
        /// Default operation size (0 = 16-bit segment, 1 = 32-bit segment)
        const DESC_DB   = 1 << (32+22),
        ///  Granularity.
        const DESC_G    = 1 << (32+23),

        // System-Segment and Gate-Descriptor Types for IA32e mode.
        // When the S (descriptor type) flag in a segment descriptor is clear,
        // the descriptor type is a system descriptor.

        const TYPE_SYS_LDT = 0b0010 << (32+8),
        const TYPE_SYS_TSS_AVAILABLE = 0b1001 << (32+8),
        const TYPE_SYS_TSS_BUSY = 0b1011 << (32+8),
        const TYPE_SYS_CALL_GATE = 0b1100 << (32+8),
        const TYPE_SYS_INTERRUPT_GATE = 0b1110 << (32+8),
        const TYPE_SYS_TRAP_GATE = 0b1111 << (32+8),

        // Code- and Data-Segment Descriptor Types.
        // When the S (descriptor type) flag in a segment descriptor is set,
        // the descriptor is for either a code or a data segment.

        /// Data Read-Only
        const TYPE_D_RO = 0b0000 << (32+8),
        /// Data Read-Only, accessed
        const TYPE_D_ROA = 0b0001 << (32+8),
        /// Data Read/Write
        const TYPE_D_RW = 0b0010 << (32+8),
        /// Data Read/Write, accessed
        const TYPE_D_RWA = 0b0011 << (32+8),
        /// Data Read-Only, expand-down
        const TYPE_D_ROEXD = 0b0100 << (32+8),
        /// Data Read-Only, expand-down, accessed
        const TYPE_D_ROEXDA = 0b0101 << (32+8),
        /// Data Read/Write, expand-down
        const TYPE_D_RWEXD = 0b0110 << (32+8),
        /// Data Read/Write, expand-down, accessed
        const TYPE_D_RWEXDA = 0b0111 << (32+8),

        /// Code Execute-Only
        const TYPE_C_EO = 0b1000 << (32+8),
        /// Code Execute-Only, accessed
        const TYPE_C_EOA = 0b1001 << (32+8),
        /// Code Execute/Read
        const TYPE_C_ER = 0b1010 << (32+8),
        /// Code Execute/Read, accessed
        const TYPE_C_ERA = 0b1011 << (32+8),
        /// Code Execute-Only, conforming
        const TYPE_C_EOC = 0b1100 << (32+8),
        /// Code Execute-Only, conforming, accessed
        const TYPE_C_EOCA = 0b1101 << (32+8),
        /// Code Execute/Read, conforming
        const TYPE_C_ERC = 0b1110 << (32+8),
        /// Code Execute/Read, conforming, accessed
        const TYPE_C_ERCA = 0b1111 << (32+8),
    }
}

/// This is data-structure is a ugly mess thing so we provide some
/// convenience function to program it.
impl SegmentDescriptor {
    pub fn new(base: u32, limit: u32) -> SegmentDescriptor {
        let base_low: u64 = base as u64 & 0xffffff;
        let base_high: u64 = base as u64 & 0xff000000 >> 24;
        let limit_low: u64 = limit as u64 & 0xffff;
        let limit_high: u64 = (limit as u64 & (0b1111 << 16)) >> 16;

        SegmentDescriptor{
            bits: limit_low | base_low << 16 | limit_high << (32+16) | base_high << (32+24)
        }
    }
}

impl fmt::Debug for SegmentDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SD: 0x{:x}", self.bits)
    }
}

/// In 64-bit mode the TSS holds information that is not
/// directly related to the task-switch mechanism.
#[repr(C, packed)]
pub struct TaskStateSegement {
    reserved: u32,
    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
    rsp: [u64; 3],
    reserved2: u64,
    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
    ist: [u64; 7],
    reserved3: u64,
    reserved4: u16,
    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
    iomap_base: u16,
}

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
pub struct DescriptorTablePointer {
   /// Size of the DT.
   pub limit: u16,
   /// Pointer to the memory region containing the DT.
   pub base: u64
}

/// Load GDT table.
pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
    asm!("lgdt ($0)" :: "r" (gdt));
}

/// Load LDT table.
pub unsafe fn lldt(ldt: &DescriptorTablePointer) {
    asm!("lldt ($0)" :: "r" (ldt));
}
<commit_msg>Functions to reload segments.<commit_after>use core::fmt;

/// Specifies which element to load into a segment from
/// descriptor tables (LDT or GDT).
bitflags! {
    flags SegmentSelector: u16 {
        /// Requestor Privilege Level
        const RPL_0 = 0b00,
        const RPL_1 = 0b01,
        const RPL_2 = 0b10,
        const RPL_3 = 0b11,

        /// Table Indicator (TI) 0 means GDT is used.
        const TI_GDT = 0 << 3,
        /// Table Indicator (TI) 1 means LDT is used.
        const TI_LDT = 1 << 3,
    }
}

impl SegmentSelector {
    /// Create a new SegmentSelector
    ///
    /// # Arguments
    ///  * `index` index in GDT or LDT array.
    ///
    pub fn new(index: u16) -> SegmentSelector {
        SegmentSelector{bits: index << 3}
    }
}

/// Entry in GDT or LDT. Provides size and location of a segment.
bitflags! {
    flags SegmentDescriptor: u64 {
        /// Descriptor type (0 = system; 1 = code or data).
        const DESC_S    = 1 << (32+12),
        /// Descriptor privilege level 0.
        const DESC_DPL0 = 0b00 << (32+13),
        /// Descriptor privilege level 1.
        const DESC_DPL1 = 0b01 << (32+13),
        /// Descriptor privilege level 2.
        const DESC_DPL2 = 0b10 << (32+13),
        /// Descriptor privilege level 3.
        const DESC_DPL3 = 0b11 << (32+13),
        /// Descriptor is Present.
        const DESC_P = 1 << (32+15),
        /// Available for use by system software.
        const DESC_AVL  = 1 << (32+20),
        /// 64-bit code segment (IA-32e mode only).
        const DESC_L    = 1 << (32+21),
        /// Default operation size (0 = 16-bit segment, 1 = 32-bit segment)
        const DESC_DB   = 1 << (32+22),
        ///  Granularity.
        const DESC_G    = 1 << (32+23),

        // System-Segment and Gate-Descriptor Types for IA32e mode.
        // When the S (descriptor type) flag in a segment descriptor is clear,
        // the descriptor type is a system descriptor.

        const TYPE_SYS_LDT = 0b0010 << (32+8),
        const TYPE_SYS_TSS_AVAILABLE = 0b1001 << (32+8),
        const TYPE_SYS_TSS_BUSY = 0b1011 << (32+8),
        const TYPE_SYS_CALL_GATE = 0b1100 << (32+8),
        const TYPE_SYS_INTERRUPT_GATE = 0b1110 << (32+8),
        const TYPE_SYS_TRAP_GATE = 0b1111 << (32+8),

        // Code- and Data-Segment Descriptor Types.
        // When the S (descriptor type) flag in a segment descriptor is set,
        // the descriptor is for either a code or a data segment.

        /// Data Read-Only
        const TYPE_D_RO = 0b0000 << (32+8),
        /// Data Read-Only, accessed
        const TYPE_D_ROA = 0b0001 << (32+8),
        /// Data Read/Write
        const TYPE_D_RW = 0b0010 << (32+8),
        /// Data Read/Write, accessed
        const TYPE_D_RWA = 0b0011 << (32+8),
        /// Data Read-Only, expand-down
        const TYPE_D_ROEXD = 0b0100 << (32+8),
        /// Data Read-Only, expand-down, accessed
        const TYPE_D_ROEXDA = 0b0101 << (32+8),
        /// Data Read/Write, expand-down
        const TYPE_D_RWEXD = 0b0110 << (32+8),
        /// Data Read/Write, expand-down, accessed
        const TYPE_D_RWEXDA = 0b0111 << (32+8),

        /// Code Execute-Only
        const TYPE_C_EO = 0b1000 << (32+8),
        /// Code Execute-Only, accessed
        const TYPE_C_EOA = 0b1001 << (32+8),
        /// Code Execute/Read
        const TYPE_C_ER = 0b1010 << (32+8),
        /// Code Execute/Read, accessed
        const TYPE_C_ERA = 0b1011 << (32+8),
        /// Code Execute-Only, conforming
        const TYPE_C_EOC = 0b1100 << (32+8),
        /// Code Execute-Only, conforming, accessed
        const TYPE_C_EOCA = 0b1101 << (32+8),
        /// Code Execute/Read, conforming
        const TYPE_C_ERC = 0b1110 << (32+8),
        /// Code Execute/Read, conforming, accessed
        const TYPE_C_ERCA = 0b1111 << (32+8),
    }
}

/// This is data-structure is a ugly mess thing so we provide some
/// convenience function to program it.
impl SegmentDescriptor {
    pub fn new(base: u32, limit: u32) -> SegmentDescriptor {
        let base_low: u64 = base as u64 & 0xffffff;
        let base_high: u64 = base as u64 & 0xff000000 >> 24;
        let limit_low: u64 = limit as u64 & 0xffff;
        let limit_high: u64 = (limit as u64 & (0b1111 << 16)) >> 16;

        SegmentDescriptor{
            bits: limit_low | base_low << 16 | limit_high << (32+16) | base_high << (32+24)
        }
    }
}

impl fmt::Debug for SegmentDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SD: 0x{:x}", self.bits)
    }
}

/// In 64-bit mode the TSS holds information that is not
/// directly related to the task-switch mechanism.
#[repr(C, packed)]
pub struct TaskStateSegement {
    reserved: u32,
    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
    rsp: [u64; 3],
    reserved2: u64,
    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
    ist: [u64; 7],
    reserved3: u64,
    reserved4: u16,
    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
    iomap_base: u16,
}

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
pub struct DescriptorTablePointer {
   /// Size of the DT.
   pub limit: u16,
   /// Pointer to the memory region containing the DT.
   pub base: u64
}

/// Load GDT table.
pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
    asm!("lgdt ($0)" :: "r" (gdt));
}

/// Load LDT table.
pub unsafe fn lldt(ldt: &DescriptorTablePointer) {
    asm!("lldt ($0)" :: "r" (ldt));
}

/// Reload stack segment register.
pub unsafe fn reload_ss(sel: SegmentSelector) {
    asm!("movw $0, %ss " :: "r" (sel));
}

/// Reload data segment register.
pub unsafe fn reload_ds(sel: SegmentSelector) {
    asm!("movw $0, %ds " :: "r" (sel));
}

/// Reload fs segment register.
pub unsafe fn reload_es(sel: SegmentSelector) {
    asm!("movw $0, %es " :: "r" (sel));
}

/// Reload fs segment register.
pub unsafe fn reload_fs(sel: SegmentSelector) {
    asm!("movw $0, %fs " :: "r" (sel));
}

/// Reload gs segment register.
pub unsafe fn reload_gs(sel: SegmentSelector) {
    asm!("movw $0, %gs " :: "r" (sel));
}

/// Reload code segment register.
/// Note this is special since we can not directly move
/// to %cs. Instead we push the new segment selector
/// and return value on the stack and use lretq
/// to reload cs and continue at 1:.
pub unsafe fn reload_cs(sel: SegmentSelector) {
    asm!("pushq $0
         lea 1f(%rip), %rax
         pushq %rax
         lretq
         1:" :: "r" (sel.bits() as u64) : "{rax}");
}<|endoftext|>


<commit_before>use ::color::Color;
use ::powerline::*;
use ::part::*;
use std::process::Command;
use std::str;

pub struct GitInfo {
    untracked: u32,
    conflicted: u32,
    non_staged: u32,
    pub ahead: u32,
    pub behind: u32,
    staged: u32,
}

impl GitInfo{
    pub fn new() -> GitInfo{
        GitInfo{ untracked: 0, conflicted: 0, non_staged: 0, staged: 0, ahead: 0, behind: 0}
    }

    fn is_dirty(&self) -> bool {
        (self.untracked + self.conflicted + self.staged + self.non_staged) > 0
    }

    fn add_file(&mut self, begin: &str) -> Result<(), Error> {
        match begin{
            "??" => self.untracked += 1,
            "DD" => self.conflicted += 1,
            "AU" => self.conflicted += 1,
            "UD" => self.conflicted += 1,
            "UA" => self.conflicted += 1,
            "UU" => self.conflicted += 1,
            "DU" => self.conflicted += 1,
            "AA" => self.conflicted += 1,
            _ => {
                let mut chars = begin.chars();
                let a = chars.next().ok_or(Error::from_str("Invalid file status"))?;
                let b = chars.next().ok_or(Error::from_str("Invalid file status"))?;
                if b != ' '{ self.non_staged += 1; }
                if a != ' '{ self.staged += 1; }
            },
        };
        Ok(())
    }

}

fn get_detached_branch_name() -> Result<String, Error> {
    let child = Command::new("git").args(&["describe", "--tags", "--always"]).output().map_err(|e| Error::wrap(e, "Failed to run git"))?;
    Ok(if !child.status.success() {
        String::from("Big Bang")
    } else {
        let branch = str::from_utf8(&child.stdout)?.split("\n").next().ok_or(Error::from_str("Empty git output"))?;
        format!("\u{2693}{}", branch)
    })
}

fn quantity(val: u32) -> String{
    if val  > 1 {
        format!("{}",val)
    } else {
        String::from("")
    }
}

fn get_first_number(s: &str) -> u32 {
    let mut value = 0;
    for c in s.chars() {
        if let Some(x) = c.to_digit(10) {
            value = value * 10 + x;
        }
        else { return value; }
    }
    value
}

fn get_ahead_commits(s: &str) -> Option<u32> {
    if let Some(pos) = s.find("ahead") {
        let start = pos + 6;
        let rest = s.get(start..).unwrap();
        return Some(get_first_number(rest));
    }
    None
}

fn get_behind_commits(s: &str) -> Option<u32> {
    if let Some(pos) = s.find("behind") {
        let start = pos + 7;
        let rest = s.get(start..).unwrap();
        return Some(get_first_number(rest));
    }
    None
}

fn get_branch_name<'a>(s: &'a str) -> Option<&'a str> {
    if let Some(rest) = s.get(3..) {
        let mut end = 0usize;
        let mut dot_count = 0;
        let mut text = rest.chars();

        while let Some(c) = text.next() {
            end += 1;
            if c.is_whitespace() {
                if let Some(next) = text.next() {
                    if next != '[' { return None }
                }
                break;
            }
            if c == '.' {
                dot_count += 1;
                if dot_count == 3 { end -= 3; break; }
            }

        }
        rest.get(..end)
    }
    else {
        None
    }
}
impl Part for GitInfo {
    fn get_segments(mut self) -> Result<Vec<Segment>, Error> {
        let output = Command::new("git").args(&["status", "--porcelain", "-b"]).output().map_err(|e| Error::wrap(e, "Failed to run git"))?;

        let data = &output.stdout;
        if data.len() == 0 { return Ok(Vec::new()); }
        let mut lines = data.split(|x| *x == ('\n' as u8));

        let branch_line = str::from_utf8(lines.next().ok_or(Error::from_str("Empty git output"))?)?;

        let branch = {
            if let Some(branch_search) = get_branch_name(&branch_line) {
                if let Some(pos) = branch_line.find('[') {
                    let info = branch_line.get(pos..).unwrap();
                    self.ahead += get_ahead_commits(&info).unwrap_or(0);
                    self.behind += get_behind_commits(&info).unwrap_or(0);
                }
                String::from(branch_search)
            }
            else {
                 get_detached_branch_name()?
            }
        };

        for line in lines {
            if let Some(op) = line.get(..2) {
                self.add_file(str::from_utf8(op)?)?;
            }
        }

        let (branch_fg, branch_bg) = if self.is_dirty() {
            (Color::REPO_DIRTY_FG, Color::REPO_DIRTY_BG)
        } else {
            (Color::REPO_CLEAN_FG, Color::REPO_CLEAN_BG)
        };
        let mut segments = Vec::new();
        segments.push(Segment::simple(&format!(" {} ", branch), branch_fg, branch_bg));
        {
            let mut add_elem = |count, symbol, fg, bg| {
                if count > 0 {
                    let text = format!(" {}{} ", quantity(count), symbol);
                    segments.push(Segment::simple(&text, fg, bg));
                }
            };
            add_elem(self.ahead, '\u{2B06}', Color::GIT_AHEAD_FG, Color::GIT_AHEAD_BG);
            add_elem(self.behind, '\u{2B07}', Color::GIT_BEHIND_FG, Color::GIT_BEHIND_BG);
            add_elem(self.staged, '\u{2714}', Color::GIT_STAGED_FG, Color::GIT_STAGED_BG);
            add_elem(self.non_staged, '\u{270E}', Color::GIT_NOTSTAGED_FG, Color::GIT_NOTSTAGED_BG);
            add_elem(self.untracked, '\u{2753}', Color::GIT_UNTRACKED_FG, Color::GIT_UNTRACKED_BG);
            add_elem(self.conflicted, '\u{273C}', Color::GIT_CONFLICTED_FG, Color::GIT_CONFLICTED_BG);
        }
        Ok(segments)
    }
}
<commit_msg>Git proccess invocation reduction by manually checking path tree<commit_after>use ::color::Color;
use ::powerline::*;
use ::part::*;
use std::process::Command;
use std::str;
use std::env;

pub struct GitInfo {
    untracked: u32,
    conflicted: u32,
    non_staged: u32,
    pub ahead: u32,
    pub behind: u32,
    staged: u32,
}

impl GitInfo{
    pub fn new() -> GitInfo{
        GitInfo{ untracked: 0, conflicted: 0, non_staged: 0, staged: 0, ahead: 0, behind: 0}
    }

    fn is_dirty(&self) -> bool {
        (self.untracked + self.conflicted + self.staged + self.non_staged) > 0
    }

    fn add_file(&mut self, begin: &str) -> Result<(), Error> {
        match begin{
            "??" => self.untracked += 1,
            "DD" => self.conflicted += 1,
            "AU" => self.conflicted += 1,
            "UD" => self.conflicted += 1,
            "UA" => self.conflicted += 1,
            "UU" => self.conflicted += 1,
            "DU" => self.conflicted += 1,
            "AA" => self.conflicted += 1,
            _ => {
                let mut chars = begin.chars();
                let a = chars.next().ok_or(Error::from_str("Invalid file status"))?;
                let b = chars.next().ok_or(Error::from_str("Invalid file status"))?;
                if b != ' '{ self.non_staged += 1; }
                if a != ' '{ self.staged += 1; }
            },
        };
        Ok(())
    }

}

fn get_detached_branch_name() -> Result<String, Error> {
    let child = Command::new("git").args(&["describe", "--tags", "--always"]).output().map_err(|e| Error::wrap(e, "Failed to run git"))?;
    Ok(if !child.status.success() {
        String::from("Big Bang")
    } else {
        let branch = str::from_utf8(&child.stdout)?.split("\n").next().ok_or(Error::from_str("Empty git output"))?;
        format!("\u{2693}{}", branch)
    })
}

fn quantity(val: u32) -> String{
    if val  > 1 {
        format!("{}",val)
    } else {
        String::from("")
    }
}

fn get_first_number(s: &str) -> u32 {
    let mut value = 0;
    for c in s.chars() {
        if let Some(x) = c.to_digit(10) {
            value = value * 10 + x;
        }
        else { return value; }
    }
    value
}

fn get_ahead_commits(s: &str) -> Option<u32> {
    if let Some(pos) = s.find("ahead") {
        let start = pos + 6;
        let rest = s.get(start..).unwrap();
        return Some(get_first_number(rest));
    }
    None
}

fn get_behind_commits(s: &str) -> Option<u32> {
    if let Some(pos) = s.find("behind") {
        let start = pos + 7;
        let rest = s.get(start..).unwrap();
        return Some(get_first_number(rest));
    }
    None
}

fn get_branch_name<'a>(s: &'a str) -> Option<&'a str> {
    if let Some(rest) = s.get(3..) {
        let mut end = 0usize;
        let mut dot_count = 0;
        let mut text = rest.chars();

        while let Some(c) = text.next() {
            end += 1;
            if c.is_whitespace() {
                if let Some(next) = text.next() {
                    if next != '[' { return None }
                }
                break;
            }
            if c == '.' {
                dot_count += 1;
                if dot_count == 3 { end -= 3; break; }
            }

        }
        rest.get(..end)
    }
    else {
        None
    }
}

fn git_dir_exists() -> bool {
    let mut git_dir = env::current_dir().unwrap();
    loop {
        git_dir.push(".git/");

        if git_dir.exists() {
            return true;
        }

        git_dir.pop();
        if git_dir.pop() == false {
            return false;
        }
    }
}

impl Part for GitInfo {
    fn get_segments(mut self) -> Result<Vec<Segment>, Error> {
        if !git_dir_exists() {
            return Ok(Vec::new());
        }

        let output = Command::new("git").args(&["status", "--porcelain", "-b"]).output().map_err(|e| Error::wrap(e, "Failed to run git"))?;

        let data = &output.stdout;
        if data.len() == 0 { return Ok(Vec::new()); }
        let mut lines = data.split(|x| *x == ('\n' as u8));

        let branch_line = str::from_utf8(lines.next().ok_or(Error::from_str("Empty git output"))?)?;

        let branch = {
            if let Some(branch_search) = get_branch_name(&branch_line) {
                if let Some(pos) = branch_line.find('[') {
                    let info = branch_line.get(pos..).unwrap();
                    self.ahead += get_ahead_commits(&info).unwrap_or(0);
                    self.behind += get_behind_commits(&info).unwrap_or(0);
                }
                String::from(branch_search)
            }
            else {
                 get_detached_branch_name()?
            }
        };

        for line in lines {
            if let Some(op) = line.get(..2) {
                self.add_file(str::from_utf8(op)?)?;
            }
        }

        let (branch_fg, branch_bg) = if self.is_dirty() {
            (Color::REPO_DIRTY_FG, Color::REPO_DIRTY_BG)
        } else {
            (Color::REPO_CLEAN_FG, Color::REPO_CLEAN_BG)
        };
        let mut segments = Vec::new();
        segments.push(Segment::simple(&format!(" {} ", branch), branch_fg, branch_bg));
        {
            let mut add_elem = |count, symbol, fg, bg| {
                if count > 0 {
                    let text = format!(" {}{} ", quantity(count), symbol);
                    segments.push(Segment::simple(&text, fg, bg));
                }
            };
            add_elem(self.ahead, '\u{2B06}', Color::GIT_AHEAD_FG, Color::GIT_AHEAD_BG);
            add_elem(self.behind, '\u{2B07}', Color::GIT_BEHIND_FG, Color::GIT_BEHIND_BG);
            add_elem(self.staged, '\u{2714}', Color::GIT_STAGED_FG, Color::GIT_STAGED_BG);
            add_elem(self.non_staged, '\u{270E}', Color::GIT_NOTSTAGED_FG, Color::GIT_NOTSTAGED_BG);
            add_elem(self.untracked, '\u{2753}', Color::GIT_UNTRACKED_FG, Color::GIT_UNTRACKED_BG);
            add_elem(self.conflicted, '\u{273C}', Color::GIT_CONFLICTED_FG, Color::GIT_CONFLICTED_BG);
        }
        Ok(segments)
    }
}
<|endoftext|>