<commit_before>#![feature(test)]

#![feature(plugin)]
#![plugin(clippy)]

extern crate test;
extern crate rand;

use rand::distributions::{IndependentSample, Range};

pub struct Settings<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    pub min_max_pos: Vec<(f32, f32)>,

    pub cr_min: f32,
    pub cr_max: f32,
    pub cr_change_probability: f32,

    pub f_min: f32,
    pub f_max: f32,
    pub f_change_probability: f32,

    pub pop_size: usize,
    pub rng: R,

    pub cost_function: F,
}

impl<F, R> Settings<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    pub fn min_max_rng(min_max_pos: Vec<(f32, f32)>, cost_function: F, rng: R) -> Settings<F, R> {
        // create settings for the algorithm
        Settings {
            min_max_pos: min_max_pos,

            cr_min: 0.0,
            cr_max: 1.0,
            cr_change_probability: 0.1,

            f_min: 0.1,
            f_max: 1.0,
            f_change_probability: 0.1,

            pop_size: 50,
            rng: rng,

            cost_function: cost_function,
        }
    }
}

impl<F> Settings<F, rand::XorShiftRng>
    where F: Fn(&[f32]) -> f32
{
    pub fn new(min_max_pos: Vec<(f32, f32)>, cost_function: F) -> Settings<F, rand::XorShiftRng> {
        Settings::min_max_rng(min_max_pos, cost_function, rand::weak_rng())
    }
}

#[derive(Clone,Debug)]
pub struct Individual {
    pos: Vec<f32>,
    // the lower, the better.
    cost: Option<f32>,

    // control parameters
    cr: f32,
    f: f32,
}

pub struct Population<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    // TODO use a single vector for curr and best and controlparameters?
    curr: Vec<Individual>,
    best: Vec<Individual>,

    settings: Settings<F, R>,

    // index of global best individual. Might be in best or in curr.
    best_idx: Option<usize>,

    // cost value of the global best individual, for quick access
    best_cost_cache: Option<f32>,
    dim: usize,
    between_popsize: Range<usize>,
    between_dim: Range<usize>,
    between_cr: Range<f32>,
    between_f: Range<f32>,

    pop_countdown: usize,
}

// pub struct PopulationEvaluationIterator<R, F>
// where R: rand::Rng,
// F: Fn(&[f32]) -> f32
// {
// pop: &'a mut Population<R>,
// cost_function: F,
// it: Option<IterMut<'a, Individual>>,
// }
//
// impl<'a, R, F> Iterator for PopulationEvaluationIterator<'a, R, F>
// where R: 'a + rand::Rng,
// F: Fn(&[f32]) -> f32
// {
// type Item = bool;
//
// fn next(&mut self) -> Option<bool> {
// self.it = Some(self.pop.curr.iter_mut());
// Some(true)
// }
// }
//

impl<F, R> Iterator for Population<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    type Item = f32;

    /// Returns the cost value of the current best
    fn next(&mut self) -> Option<f32> {
        if 0 == self.pop_countdown {
            // if the whole pop has been evaluated, evolve it to update positions.
            // this also copies curr to best, if better.
            self.update_best();
            self.update_positions();
            self.pop_countdown = self.curr.len();
        }

        // perform a single fitness evaluation
        self.pop_countdown -= 1;
        let curr = &mut self.curr[self.pop_countdown];

        let cost = (self.settings.cost_function)(&curr.pos);
        curr.cost = Some(cost);

        // see if we have improved the global best
        if self.best_cost_cache.is_none() || cost < self.best_cost_cache.unwrap() {
            self.best_cost_cache = Some(cost);
            self.best_idx = Some(self.pop_countdown);
        }

        self.best_cost_cache
    }
}

impl<F> Population<F, rand::XorShiftRng>
    where F: Fn(&[f32]) -> f32
{
    pub fn new(min_max_pos: Vec<(f32, f32)>, cost_function: F) -> Population<F, rand::XorShiftRng> {
        Population::from_settings(Settings::new(min_max_pos, cost_function))
    }
}

impl<F, R> Population<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    // Creates a new population based on the given settings.
    pub fn from_settings(s: Settings<F, R>) -> Population<F, R> {
        assert!(s.min_max_pos.len() >= 1,
                "need at least one element to optimize");

        // create a vector of randomly initialized individuals for current.
        let dim = s.min_max_pos.len();

        // Empty individual, with no cost value (yet)
        let dummy_individual = Individual {
            pos: vec![0.0; dim],
            cost: None,
            cr: 0.0,
            f: 0.0,
        };

        // creates all the empty individuals
        let mut pop = Population {
            curr: vec![dummy_individual.clone(); s.pop_size],
            best: vec![dummy_individual; s.pop_size],
            best_idx: None,
            best_cost_cache: None,
            dim: dim,
            pop_countdown: s.pop_size,
            between_popsize: Range::new(0, s.pop_size),
            between_dim: Range::new(0, dim),
            between_cr: Range::new(s.cr_min, s.cr_max),
            between_f: Range::new(s.f_min, s.f_max),
            settings: s,
        };

        for ind in &mut pop.curr {
            // init control parameters
            ind.cr = pop.between_cr.ind_sample(&mut pop.settings.rng);
            ind.f = pop.between_f.ind_sample(&mut pop.settings.rng);

            // random range for each dimension
            for d in 0..dim {
                let between_min_max = Range::new(pop.settings.min_max_pos[d].0,
                                                 pop.settings.min_max_pos[d].1);
                ind.pos[d] = between_min_max.ind_sample(&mut pop.settings.rng);
            }
        }

        pop
    }

    fn update_best(&mut self) {
        for i in 0..self.curr.len() {
            let curr = &mut self.curr[i];
            let best = &mut self.best[i];

            // we use <= here, so that the individual moves even if the cost
            // stays the same.
            if best.cost.is_none() || curr.cost.unwrap() <= best.cost.unwrap() {
                // replace individual's best. swap is *much* faster than clone.
                std::mem::swap(curr, best);
            }
        }
    }

    fn update_positions(&mut self) {
        let global_best_pos = &self.best[self.best_idx.unwrap()].pos;
        let rng = &mut self.settings.rng;
        for i in 0..self.curr.len() {
            let mut id1 = self.between_popsize.ind_sample(rng);
            while id1 == i {
                id1 = self.between_popsize.ind_sample(rng);
            }

            let mut id2 = self.between_popsize.ind_sample(rng);
            while id2 == i || id2 == id1 {
                id2 = self.between_popsize.ind_sample(rng);
            }

            let curr = &mut self.curr[i];
            let best = &self.best[i];

            // see "Self-Adapting Control Parameters in Differential Evolution:
            // A Comparative Study on Numerical Benchmark Problems"
            if rng.gen::<f32>() < self.settings.cr_change_probability {
                curr.cr = self.between_cr.ind_sample(rng);
            } else {
                curr.cr = best.cr;
            }
            if rng.gen::<f32>() < self.settings.f_change_probability {
                curr.f = self.between_f.ind_sample(rng);
            } else {
                curr.f = best.f;
            }

            let curr_pos = &mut curr.pos;
            let best_pos = &best.pos;
            let best1_pos = &self.best[id1].pos;
            let best2_pos = &self.best[id2].pos;

            let forced_mutation_dim = self.between_dim.ind_sample(rng);

            // This implements the DE/1/best/bin algorithm.
            for d in 0..self.dim {
                if d == forced_mutation_dim || rng.gen::<f32>() < curr.cr {
                    curr_pos[d] = global_best_pos[d] + curr.f * (best1_pos[d] - best2_pos[d]);
                } else {
                    curr_pos[d] = best_pos[d];
                }
            }

            // reset cost, has to be updated by the user.
            curr.cost = None;
        }
    }

    pub fn best(&self) -> Option<(f32, &[f32])> {
        if let Some(bi) = self.best_idx {
            let curr = &self.curr[bi];
            let best = &self.best[bi];

            if curr.cost.is_none() {
                return Some((best.cost.unwrap(), &best.pos));
            }
            if best.cost.is_none() {
                return Some((curr.cost.unwrap(), &curr.pos));
            }
            if curr.cost.unwrap() < best.cost.unwrap() {
                return Some((curr.cost.unwrap(), &curr.pos));
            }
            return Some((best.cost.unwrap(), &best.pos));
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate rand;
    use super::*;
    use test::Bencher;
    use rand::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng, ChaChaRng};
    use rand::{OsRng, weak_rng};

    fn setup<R: rand::Rng>(dim: usize, rng: R) -> Population<R> {
        let settings = Settings::min_max_rng(vec![-20.0; dim], vec![20.0; dim], rng);
        Population::new(settings)
    }

    fn dummy_fitness(individuals: &mut Vec<Individual>) {
        for ind in individuals {
            ind.cost = Some(1.234);
        }
    }

    #[bench]
    fn bench_square_fitness_opt(b: &mut Bencher) {
        let rng: XorShiftRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            for ind in &mut pop.curr {
                let mut f = 0.0;
                for x in &ind.pos {
                    f += x * x;
                }
                ind.cost = Some(f);
            }
            pop.evolve();
        });
    }

    #[bench]
    fn rand_thread_rng(b: &mut Bencher) {
        let mut pop = setup(5, rand::thread_rng());
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_xor_shift(b: &mut Bencher) {
        let rng: XorShiftRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_chacha(b: &mut Bencher) {
        let rng: ChaChaRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_isaac(b: &mut Bencher) {
        let rng: IsaacRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_isaac64(b: &mut Bencher) {
        let rng: Isaac64Rng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_std(b: &mut Bencher) {
        let rng: StdRng = StdRng::new().unwrap();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_osrng(b: &mut Bencher) {
        let rng: OsRng = OsRng::new().unwrap();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

    #[bench]
    fn rand_weak_rng(b: &mut Bencher) {
        let rng = weak_rng();
        let mut pop = setup(5, rng);
        b.iter(|| {
            dummy_fitness(&mut pop.curr);
            pop.evolve();
        });
    }

}
<commit_msg>benchmark updated<commit_after>#![feature(test)]

#![feature(plugin)]
#![plugin(clippy)]

extern crate test;
extern crate rand;

use rand::distributions::{IndependentSample, Range};

pub struct Settings<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    pub min_max_pos: Vec<(f32, f32)>,

    pub cr_min: f32,
    pub cr_max: f32,
    pub cr_change_probability: f32,

    pub f_min: f32,
    pub f_max: f32,
    pub f_change_probability: f32,

    pub pop_size: usize,
    pub rng: R,

    pub cost_function: F,
}

impl<F, R> Settings<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    pub fn min_max_rng(min_max_pos: Vec<(f32, f32)>, cost_function: F, rng: R) -> Settings<F, R> {
        // create settings for the algorithm
        Settings {
            min_max_pos: min_max_pos,

            cr_min: 0.0,
            cr_max: 1.0,
            cr_change_probability: 0.1,

            f_min: 0.1,
            f_max: 1.0,
            f_change_probability: 0.1,

            pop_size: 50,
            rng: rng,

            cost_function: cost_function,
        }
    }
}

impl<F> Settings<F, rand::XorShiftRng>
    where F: Fn(&[f32]) -> f32
{
    pub fn new(min_max_pos: Vec<(f32, f32)>, cost_function: F) -> Settings<F, rand::XorShiftRng> {
        Settings::min_max_rng(min_max_pos, cost_function, rand::weak_rng())
    }
}

#[derive(Clone,Debug)]
pub struct Individual {
    pos: Vec<f32>,
    // the lower, the better.
    cost: Option<f32>,

    // control parameters
    cr: f32,
    f: f32,
}

pub struct Population<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    // TODO use a single vector for curr and best and controlparameters?
    curr: Vec<Individual>,
    best: Vec<Individual>,

    settings: Settings<F, R>,

    // index of global best individual. Might be in best or in curr.
    best_idx: Option<usize>,

    // cost value of the global best individual, for quick access
    best_cost_cache: Option<f32>,
    dim: usize,
    between_popsize: Range<usize>,
    between_dim: Range<usize>,
    between_cr: Range<f32>,
    between_f: Range<f32>,

    pop_countdown: usize,
}

// pub struct PopulationEvaluationIterator<R, F>
// where R: rand::Rng,
// F: Fn(&[f32]) -> f32
// {
// pop: &'a mut Population<R>,
// cost_function: F,
// it: Option<IterMut<'a, Individual>>,
// }
//
// impl<'a, R, F> Iterator for PopulationEvaluationIterator<'a, R, F>
// where R: 'a + rand::Rng,
// F: Fn(&[f32]) -> f32
// {
// type Item = bool;
//
// fn next(&mut self) -> Option<bool> {
// self.it = Some(self.pop.curr.iter_mut());
// Some(true)
// }
// }
//

impl<F, R> Iterator for Population<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    type Item = f32;

    /// Returns the cost value of the current best
    fn next(&mut self) -> Option<f32> {
        if 0 == self.pop_countdown {
            // if the whole pop has been evaluated, evolve it to update positions.
            // this also copies curr to best, if better.
            self.update_best();
            self.update_positions();
            self.pop_countdown = self.curr.len();
        }

        // perform a single fitness evaluation
        self.pop_countdown -= 1;
        let curr = &mut self.curr[self.pop_countdown];

        let cost = (self.settings.cost_function)(&curr.pos);
        curr.cost = Some(cost);

        // see if we have improved the global best
        if self.best_cost_cache.is_none() || cost < self.best_cost_cache.unwrap() {
            self.best_cost_cache = Some(cost);
            self.best_idx = Some(self.pop_countdown);
        }

        self.best_cost_cache
    }
}

impl<F> Population<F, rand::XorShiftRng>
    where F: Fn(&[f32]) -> f32
{
    pub fn new(min_max_pos: Vec<(f32, f32)>, cost_function: F) -> Population<F, rand::XorShiftRng> {
        Population::from_settings(Settings::new(min_max_pos, cost_function))
    }
}

impl<F, R> Population<F, R>
    where F: Fn(&[f32]) -> f32,
          R: rand::Rng
{
    // Creates a new population based on the given settings.
    pub fn from_settings(s: Settings<F, R>) -> Population<F, R> {
        assert!(s.min_max_pos.len() >= 1,
                "need at least one element to optimize");

        // create a vector of randomly initialized individuals for current.
        let dim = s.min_max_pos.len();

        // Empty individual, with no cost value (yet)
        let dummy_individual = Individual {
            pos: vec![0.0; dim],
            cost: None,
            cr: 0.0,
            f: 0.0,
        };

        // creates all the empty individuals
        let mut pop = Population {
            curr: vec![dummy_individual.clone(); s.pop_size],
            best: vec![dummy_individual; s.pop_size],
            best_idx: None,
            best_cost_cache: None,
            dim: dim,
            pop_countdown: s.pop_size,
            between_popsize: Range::new(0, s.pop_size),
            between_dim: Range::new(0, dim),
            between_cr: Range::new(s.cr_min, s.cr_max),
            between_f: Range::new(s.f_min, s.f_max),
            settings: s,
        };

        for ind in &mut pop.curr {
            // init control parameters
            ind.cr = pop.between_cr.ind_sample(&mut pop.settings.rng);
            ind.f = pop.between_f.ind_sample(&mut pop.settings.rng);

            // random range for each dimension
            for d in 0..dim {
                let between_min_max = Range::new(pop.settings.min_max_pos[d].0,
                                                 pop.settings.min_max_pos[d].1);
                ind.pos[d] = between_min_max.ind_sample(&mut pop.settings.rng);
            }
        }

        pop
    }

    fn update_best(&mut self) {
        for i in 0..self.curr.len() {
            let curr = &mut self.curr[i];
            let best = &mut self.best[i];

            // we use <= here, so that the individual moves even if the cost
            // stays the same.
            if best.cost.is_none() || curr.cost.unwrap() <= best.cost.unwrap() {
                // replace individual's best. swap is *much* faster than clone.
                std::mem::swap(curr, best);
            }
        }
    }

    fn update_positions(&mut self) {
        let global_best_pos = &self.best[self.best_idx.unwrap()].pos;
        let rng = &mut self.settings.rng;
        for i in 0..self.curr.len() {
            let mut id1 = self.between_popsize.ind_sample(rng);
            while id1 == i {
                id1 = self.between_popsize.ind_sample(rng);
            }

            let mut id2 = self.between_popsize.ind_sample(rng);
            while id2 == i || id2 == id1 {
                id2 = self.between_popsize.ind_sample(rng);
            }

            let curr = &mut self.curr[i];
            let best = &self.best[i];

            // see "Self-Adapting Control Parameters in Differential Evolution:
            // A Comparative Study on Numerical Benchmark Problems"
            if rng.gen::<f32>() < self.settings.cr_change_probability {
                curr.cr = self.between_cr.ind_sample(rng);
            } else {
                curr.cr = best.cr;
            }
            if rng.gen::<f32>() < self.settings.f_change_probability {
                curr.f = self.between_f.ind_sample(rng);
            } else {
                curr.f = best.f;
            }

            let curr_pos = &mut curr.pos;
            let best_pos = &best.pos;
            let best1_pos = &self.best[id1].pos;
            let best2_pos = &self.best[id2].pos;

            let forced_mutation_dim = self.between_dim.ind_sample(rng);

            // This implements the DE/1/best/bin algorithm.
            for d in 0..self.dim {
                if d == forced_mutation_dim || rng.gen::<f32>() < curr.cr {
                    curr_pos[d] = global_best_pos[d] + curr.f * (best1_pos[d] - best2_pos[d]);
                } else {
                    curr_pos[d] = best_pos[d];
                }
            }

            // reset cost, has to be updated by the user.
            curr.cost = None;
        }
    }

    pub fn best(&self) -> Option<(f32, &[f32])> {
        if let Some(bi) = self.best_idx {
            let curr = &self.curr[bi];
            let best = &self.best[bi];

            if curr.cost.is_none() {
                return Some((best.cost.unwrap(), &best.pos));
            }
            if best.cost.is_none() {
                return Some((curr.cost.unwrap(), &curr.pos));
            }
            if curr.cost.unwrap() < best.cost.unwrap() {
                return Some((curr.cost.unwrap(), &curr.pos));
            }
            return Some((best.cost.unwrap(), &best.pos));
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate rand;
    use super::*;
    use test::Bencher;
    use rand::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng, ChaChaRng};
    use rand::{OsRng, weak_rng};

    fn setup<F: Fn(&[f32]) -> f32, R: rand::Rng>(dim: usize, cost_fn: F, rng: R) -> Population<F, R> {
        let s = Settings::min_max_rng(vec![(-100.0, 100.0); dim], cost_fn, rng);
        Population::from_settings(s)
    }

    #[bench]
    fn bench_square_fitness_opt(b: &mut Bencher) {
        let rng: XorShiftRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, |_| 1.234, rng);
        b.iter(|| pop.next());
    }

    #[bench]
    fn rand_thread_rng(b: &mut Bencher) {
        let mut pop = setup(5, |_| 1.234, rand::thread_rng());
        b.iter(|| pop.next());
    }

    #[bench]
    fn rand_xor_shift(b: &mut Bencher) {
        let rng: XorShiftRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, |_| 1.234, rng);
        b.iter(|| pop.next());
    }

    #[bench]
    fn rand_chacha(b: &mut Bencher) {
        let rng: ChaChaRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, |_| 1.234, rng);
        b.iter(|| pop.next());
    }

    #[bench]
    fn rand_isaac(b: &mut Bencher) {
        let rng: IsaacRng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, |_| 1.234, rng);
        b.iter(|| pop.next());
    }

    #[bench]
    fn rand_isaac64(b: &mut Bencher) {
        let rng: Isaac64Rng = OsRng::new().unwrap().gen();
        let mut pop = setup(5, |_| 1.234, rng);
        b.iter(|| pop.next());
    }

    #[bench]
    fn rand_std(b: &mut Bencher) {
        let rng: StdRng = StdRng::new().unwrap();
        let mut pop = setup(5, |_| 1.234, rng);
        b.iter(|| pop.next());
    }

    #[bench]
    fn rand_osrng(b: &mut Bencher) {
        let rng: OsRng = OsRng::new().unwrap();
        let mut pop = setup(5, |_| 1.234, rng);
        b.iter(|| pop.next());
    }

    #[bench]
    fn rand_weak_rng(b: &mut Bencher) {
        let rng = weak_rng();
        let mut pop = setup(5, |_| 1.234, rng);
        b.iter(|| pop.next());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, deny(warnings))]

extern crate rustc_serialize;

extern crate conduit;
extern crate conduit_middleware as middleware;
extern crate conduit_utils as utils;

use std::any::Any;
use std::error::Error;
use std::io::prelude::*;
use std::marker;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};

use conduit::Request;
use middleware::Middleware;

pub struct BodyReader<T> {
    _marker: marker::PhantomData<fn() -> T>,
}

impl<T: Decodable + Any> BodyReader<T> {
    pub fn new() -> BodyReader<T> {
        BodyReader { _marker: marker::PhantomData }
    }
}

impl<T: Decodable + Any> Middleware for BodyReader<T> {
    fn before(&self, req: &mut Request) -> Result<(), Box<Error+Send>> {
        let json: T = try!(decode::<T>(req.body()));

        req.mut_extensions().insert(json);
        Ok(())
    }
}

#[allow(trivial_casts)]
fn decode<T: Decodable>(reader: &mut Read) -> Result<T, Box<Error+Send>> {
    let j = try!(Json::from_reader(reader).map_err(|e| Box::new(e) as Box<Error+Send>));
    let mut decoder = json::Decoder::new(j);
    Decodable::decode(&mut decoder).map_err(|e| Box::new(e) as Box<Error+Send>)
}

pub fn json_params<'a, T: Decodable + Any>(req: &'a Request) -> Option<&'a T> {
    req.extensions().find::<T>()
}

#[cfg(test)]
mod tests {
    extern crate conduit_test;

    use {json_params, BodyReader};

    use std::collections::HashMap;
    use std::io::{self, Cursor};
    use rustc_serialize::json;

    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    #[derive(PartialEq, RustcDecodable, RustcEncodable, Debug)]
    struct Person {
        name: String,
        location: String
    }

    fn handler(req: &mut Request) -> io::Result<Response> {
        let person = json_params::<Person>(req);
        let out = person.map(|p| json::encode(p).unwrap()).expect("No JSON");

        Ok(Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(Cursor::new(out.into_bytes()))
        })
    }

    #[test]
    fn test_body_params() {
        let mut req = conduit_test::MockRequest::new(Method::Get, "/");
        req.with_body(br#"{ "name": "Alex Crichton", "location": "San Francisco" }"#);

        let mut middleware = MiddlewareBuilder::new(handler);
        middleware.add(BodyReader::<Person>::new());

        let mut res = middleware.call(&mut req).ok().expect("No response");
        let person = super::decode::<Person>(&mut *res.body).ok().expect("No JSON response");
        assert_eq!(person, Person {
            name: "Alex Crichton".to_string(),
            location: "San Francisco".to_string()
        });
    }
}
<commit_msg>Fix tests<commit_after>#![cfg_attr(test, deny(warnings))]

extern crate rustc_serialize;

extern crate conduit;
extern crate conduit_middleware as middleware;
extern crate conduit_utils as utils;

use std::any::Any;
use std::error::Error;
use std::io::prelude::*;
use std::marker;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};

use conduit::Request;
use middleware::Middleware;

pub struct BodyReader<T> {
    _marker: marker::PhantomData<fn() -> T>,
}

impl<T: Decodable + Any> BodyReader<T> {
    pub fn new() -> BodyReader<T> {
        BodyReader { _marker: marker::PhantomData }
    }
}

impl<T: Decodable + Any> Middleware for BodyReader<T> {
    fn before(&self, req: &mut Request) -> Result<(), Box<Error+Send>> {
        let json: T = try!(decode::<T>(req.body()));

        req.mut_extensions().insert(json);
        Ok(())
    }
}

#[allow(trivial_casts)]
fn decode<T: Decodable>(reader: &mut Read) -> Result<T, Box<Error+Send>> {
    let j = try!(Json::from_reader(reader).map_err(|e| Box::new(e) as Box<Error+Send>));
    let mut decoder = json::Decoder::new(j);
    Decodable::decode(&mut decoder).map_err(|e| Box::new(e) as Box<Error+Send>)
}

pub fn json_params<'a, T: Decodable + Any>(req: &'a Request) -> Option<&'a T> {
    req.extensions().find::<T>()
}

#[cfg(test)]
mod tests {
    extern crate conduit_test;

    use {json_params, BodyReader};

    use std::collections::HashMap;
    use std::io::{self, Cursor};
    use rustc_serialize::json;

    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    #[derive(PartialEq, RustcDecodable, RustcEncodable, Debug)]
    struct Person {
        name: String,
        location: String
    }

    fn handler(req: &mut Request) -> io::Result<Response> {
        let person = json_params::<Person>(req);
        let out = person.map(|p| json::encode(p).unwrap()).expect("No JSON");

        Ok(Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(Cursor::new(out.into_bytes()))
        })
    }

    #[test]
    fn test_body_params() {
        let mut req = conduit_test::MockRequest::new(Method::Get, "/");
        req.with_body(br#"{ "name": "Alex Crichton", "location": "San Francisco" }"#);

        let mut middleware = MiddlewareBuilder::new(handler);
        middleware.add(BodyReader::<Person>::new());

        let mut res = middleware.call(&mut req).ok().expect("No response");
        let mut body = Vec::new();
        res.body.write_body(&mut body).unwrap();
        let person = super::decode::<Person>(&mut &body[..]).ok().expect("No JSON response");
        assert_eq!(person, Person {
            name: "Alex Crichton".to_string(),
            location: "San Francisco".to_string()
        });
    }
}
<|endoftext|>


<commit_before>#![feature(custom_derive, plugin, stmt_expr_attributes)]
#![plugin(serde_macros)]
#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces, unused_qualifications,
        warnings)]

//! Serializes and psudo-deserializes structs implementing the Error trait. This should only be done if you know you won't ever need an actual error value, only the description and causes.
//!
//! This crate assumes that the error descriptions are complete, and are indicative of the error going on.
//! There is also no way to get any values accoated with the error, since that would require real serialization of arbratrary structs, implementing a trait you didn't make.
//!
//! #Examples
//!
//! ```
//! use std::convert::From;
//! use std::fmt::Error;
//! use errorser::serialize_error_string;
//!
//! let error = Error;
//! let errser = serialize_error_string(&error);
//! assert_eq!(errser, "???");
//! ```

extern crate bincode;
extern crate serde;
extern crate serde_json;

mod real_error_impls;

use std::convert::{From, AsRef};
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};

use bincode::SizeLimit;
use bincode::serde::serialize as binser;
use serde_json::to_string as jser;

/// An error that can be serialized by serde or rustc_seralize.
#[derive(Serialize, Deserialize, Debug)]    // TODO: Add rustc_seralize compatibility.
pub enum SeralizableError {
    /// If the error is commonly used, such as something from std, some of it's fields may be preserved. This variant represents these kinds of errors.
    RealError(real_error_impls::RealError),
    /// If the error isn't in std or isn't common, it is automatically made a PseudoError, loosing it's fields.
    PseudoError(PseudoError),
}

/// An error that has been made seralization-capable, but has lost it's fields, due to incompatibility with the library or preserving fields being unnesacary.
///
/// See the crate root for more info.
#[derive(Serialize, Deserialize, Debug)]
pub struct PseudoError {
    cause: Option<Box<PseudoError>>,
    desc: String,
}

impl Display for PseudoError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.desc)
    }
}

impl<'a> From<&'a Error> for PseudoError {
    fn from(err: &Error) -> PseudoError {
        PseudoError {
            cause: err.cause().map(|cause| Box::new(PseudoError::from(cause))), /* In prevous versions of this line, it was almost lisp with the number of close perens here. */
            desc: err.description().to_string(),
        }
    }
}

impl Error for PseudoError {
    fn description(&self) -> &str {
        &self.desc
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|cause| &**cause as &Error)    // Good luck. Also &**cause looks like it's cencoring profanity. Kinda feels like it would too, with how complacated it is.
        // Actually, I'm not that mean, I'll try to explain.

        // So cause.as_ref is Option::as_ref, turning Option<Box<PseudoError>> into Option<&Box<PseudoError>>.
        // Mapping lets me take an &Box<_>.
        // &**cause is best read right to left. The transforms work like this:
        // &Box<_> -> Box<_> -> _ -> &PseudoError
        // From there it's just &PseudoError as &Error.
    }
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_bytes.
///
/// #Examples
///
/// ```
/// use std::convert::From;
/// use std::fmt::Error;
/// use errorser::serialize_error_bytes;
///
/// let error = Error;
/// let errser = serialize_error_bytes(&error);
/// assert_eq!(errser, [0, 1]);
/// ```
pub fn serialize_error_bytes<'a>(to_ser: &'a Error) -> Vec<u8> {
    binser(&PseudoError::from(to_ser), SizeLimit::Infinite).unwrap()
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_string.
///
/// #Examples
///
/// ```
/// use std::convert::From;
/// use std::fmt::Error;
/// use errorser::serialize_error_string;
///
/// let error = Error;
/// let errser = serialize_error_string(&error);
/// assert_eq!(errser, "???");
/// ```
pub fn serialize_error_string<'a>(to_ser: &'a Error) -> String {
    jser(&PseudoError::from(to_ser)).unwrap()
}

#[cfg(test)]
mod test {
    #[test]
    fn serialize_error_bytes() {}
}
<commit_msg>Make the names and signatures of certan things simpler<commit_after>#![feature(custom_derive, plugin, stmt_expr_attributes)]
#![plugin(serde_macros)]
#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces, unused_qualifications,
        warnings)]

//! Serializes and psudo-deserializes structs implementing the Error trait. This should only be done if you know you won't ever need an actual error value, only the description and causes.
//!
//! This crate assumes that the error descriptions are complete, and are indicative of the error going on.
//! There is also no way to get any values accoated with the error, since that would require real serialization of arbratrary structs, implementing a trait you didn't make.
//!
//! #Examples
//!
//! ```
//! use std::convert::From;
//! use std::fmt::Error;
//! use errorser::serialize_error_string;
//!
//! let error = Error;
//! let errser = serialize_error_string(&error);
//! assert_eq!(errser, "???");
//! ```

extern crate bincode;
extern crate serde;
extern crate serde_json;

mod real_error_impls;

use std::convert::{From, AsRef};
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};

use bincode::SizeLimit;
use bincode::serde::serialize as bin_serialize;
use serde_json::to_string as json_serialize;

/// An error that can be serialized by serde or rustc_seralize.
#[derive(Serialize, Deserialize, Debug)]    // TODO: Add rustc_seralize compatibility.
pub enum SeralizableError {
    /// If the error is commonly used, such as something from std, some of it's fields may be preserved. This variant represents these kinds of errors.
    RealError(real_error_impls::RealError),
    /// If the error isn't in std or isn't common, it is automatically made a PseudoError, loosing it's fields.
    PseudoError(PseudoError),
}

/// An error that has been made seralization-capable, but has lost it's fields, due to incompatibility with the library or preserving fields being unnesacary.
///
/// See the crate root for more info.
#[derive(Serialize, Deserialize, Debug)]
pub struct PseudoError {
    cause: Option<Box<PseudoError>>,
    desc: String,
}

impl Display for PseudoError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.desc)
    }
}

impl<'a> From<&'a Error> for PseudoError {
    fn from(err: &Error) -> PseudoError {
        PseudoError {
            cause: err.cause().map(|cause| Box::new(PseudoError::from(cause))), /* In prevous versions of this line, it was almost lisp with the number of close perens here. */
            desc: err.description().to_owned(),
        }
    }
}

impl Error for PseudoError {
    fn description(&self) -> &str {
        &self.desc
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|cause| &**cause as &Error)    // Good luck. Also &**cause looks like it's cencoring profanity. Kinda feels like it would too, with how complacated it is.
        // Actually, I'm not that mean, I'll try to explain.

        // So cause.as_ref is Option::as_ref, turning Option<Box<PseudoError>> into Option<&Box<PseudoError>>.
        // Mapping lets me take an &Box<_>.
        // &**cause is best read right to left. The transforms work like this:
        // &Box<_> -> Box<_> -> _ -> &PseudoError
        // From there it's just &PseudoError as &Error.
    }
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_bytes.
///
/// #Examples
///
/// ```
/// use std::convert::From;
/// use std::fmt::Error;
/// use errorser::serialize_error_bytes;
///
/// let error = Error;
/// let errser = serialize_error_bytes(&error);
/// assert_eq!(errser, [0, 1]);
/// ```
pub fn serialize_error_bytes(to_ser: &Error) -> Vec<u8> {
    bin_serialize(&PseudoError::from(to_ser), SizeLimit::Infinite).unwrap()
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_string.
///
/// #Examples
///
/// ```
/// use std::convert::From;
/// use std::fmt::Error;
/// use errorser::serialize_error_string;
///
/// let error = Error;
/// let errser = serialize_error_string(&error);
/// assert_eq!(errser, "???");
/// ```
pub fn serialize_error_string(to_ser: &Error) -> String {
    json_serialize(&PseudoError::from(to_ser)).unwrap()
}

#[cfg(test)]
mod test {
    #[test]
    fn serialize_error_bytes() {}
}
<|endoftext|>


<commit_before>//! A dependency free implementation of the Fletcher's checksum algorithm
//!
//! Fletcher's Checksum is a checksum algorithm that was developed to provide
//! nearly the same error checking capability as a CRC but with a faster
//! software implementation. This is not a cryptographically secure checksum,
//! it's only meant to be used for checking the integrity of data NOT the
//! authenticity.
//!
//! ### Algorithm Pros
//! This algorithm is faster to run in software than most CRCs. This is
//! because the CRC algorithm was originally designed to be simple to implement
//! in hardware, but not neccesarily in software. The Fletcher Checksum was
//! designed specifically to be suited for implementation in software.
//!
//! ### Algorithm Cons
//! This checksum algorithm does suffer from not being able to distinguish 0xFF
//! from 0x00. Meaning a block of data with all bits set to 1 will have the
//! exact same the same checksum as a block of data with all bits set to 0. This
//! comes from the fact that the algorithm uses one's complement math.
//!
//! Fletcher's checksum isn't quite as good at detecting bit errors in data as
//! a CRC with a well choosen polynomial.
//!
//! # How To Use
//! The checksum objects take in slices of data to process. There is no minimum
//! length required of the slices, all of the provided data will be processed
//! to completion. The type of the input data is dictated by the size of the
//! checksum value. i.e. a 64-bit checksum operates on 32-bit wide values.
//!
//! The checksum object can be queried for it's current checksum value as any
//! time with the `value()` function.
//!
//! # Example
//! ```
//! let data: [u8; 6] = [0xC1, 0x77, 0xE9, 0xC0, 0xAB, 0x1E];
//! let mut checksum = fletcher::Fletcher16::new();
//! checksum.update(&data);
//! assert_eq!(checksum.value(), 0x3FAD);
//! ```

#![no_std]

mod fletcher16;
mod fletcher32;
mod fletcher64;
pub mod generic_fletcher;

pub use fletcher16::Fletcher16;
pub use fletcher32::Fletcher32;
pub use fletcher64::Fletcher64;

#[cfg(test)]
#[macro_use]
extern crate std;

#[cfg(test)]
extern crate byteorder;
<commit_msg>Added helper functions for getting the checksum values in one go (#6)<commit_after>//! A dependency free implementation of the Fletcher's checksum algorithm
//!
//! Fletcher's Checksum is a checksum algorithm that was developed to provide
//! nearly the same error checking capability as a CRC but with a faster
//! software implementation. This is not a cryptographically secure checksum,
//! it's only meant to be used for checking the integrity of data NOT the
//! authenticity.
//!
//! ### Algorithm Pros
//! This algorithm is faster to run in software than most CRCs. This is
//! because the CRC algorithm was originally designed to be simple to implement
//! in hardware, but not neccesarily in software. The Fletcher Checksum was
//! designed specifically to be suited for implementation in software.
//!
//! ### Algorithm Cons
//! This checksum algorithm does suffer from not being able to distinguish 0xFF
//! from 0x00. Meaning a block of data with all bits set to 1 will have the
//! exact same the same checksum as a block of data with all bits set to 0. This
//! comes from the fact that the algorithm uses one's complement math.
//!
//! Fletcher's checksum isn't quite as good at detecting bit errors in data as
//! a CRC with a well choosen polynomial.
//!
//! # How To Use
//! The checksum objects take in slices of data to process. There is no minimum
//! length required of the slices, all of the provided data will be processed
//! to completion. The type of the input data is dictated by the size of the
//! checksum value. i.e. a 64-bit checksum operates on 32-bit wide values.
//!
//! The checksum object can be queried for it's current checksum value as any
//! time with the `value()` function.
//!
//! # Example
//! ```
//! let data: [u8; 6] = [0xC1, 0x77, 0xE9, 0xC0, 0xAB, 0x1E];
//! let mut checksum = fletcher::Fletcher16::new();
//! checksum.update(&data);
//! assert_eq!(checksum.value(), 0x3FAD);
//! ```

#![no_std]

mod fletcher16;
mod fletcher32;
mod fletcher64;
pub mod generic_fletcher;

pub use fletcher16::Fletcher16;
pub use fletcher32::Fletcher32;
pub use fletcher64::Fletcher64;

/// Get the 16-bit checksum in one shot
pub fn fletcher16(data: &[u8]) -> u16 {
    let mut checksum = Fletcher16::new();
    checksum.update(data);
    checksum.value()
}

/// Get the 32-bit checksum in one shot
pub fn fletcher32(data: &[u16]) -> u32 {
    let mut checksum = Fletcher32::new();
    checksum.update(data);
    checksum.value()
}

/// Get the 64-bit checksum in one shot
pub fn fletcher64(data: &[u32]) -> u64 {
    let mut checksum = Fletcher64::new();
    checksum.update(data);
    checksum.value()
}

#[cfg(test)]
#[macro_use]
extern crate std;

#[cfg(test)]
extern crate byteorder;
<|endoftext|>


<commit_before>//! which
//!
//! A Rust equivalent of Unix command `which(1)`.
//! # Example:
//!
//! To find which rustc executable binary is using:
//!
//! ``` norun
//! use which::which;
//!
//! let result = which::which("rustc").unwrap();
//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
//!
//! ```

extern crate libc;
#[cfg(test)]
extern crate tempdir;

use std::path::{Path,PathBuf};
use std::{env, fs};
#[cfg(unix)]
use std::ffi::CString;
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;

fn is_exist(bin_path: &Path) -> bool {

    match fs::metadata(bin_path).map(|metadata|{
        metadata.is_file()
    }) {
        Ok(true) => true,
        _ => false
    }
}

/// Return `true` if `path` is executable.
#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    CString::new(path.as_os_str().as_bytes())
        .and_then(|c| {
            Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 })
        })
        .unwrap_or(false)
}

#[cfg(not(unix))]
fn is_executable(_path: &Path) -> bool { true }

/// Like `Path::with_extension`, but don't replace an existing extension.
fn ensure_exe_extension<T: AsRef<Path>>(path: T) -> PathBuf {
    if env::consts::EXE_EXTENSION.is_empty() {
        // Nothing to do.
        path.as_ref().to_path_buf()
    } else {
        match path.as_ref().extension().map(|e| e == Path::new(env::consts::EXE_EXTENSION)) {
            // Already has the right extension.
            Some(true) => path.as_ref().to_path_buf(),
            _ => {
                // Append the extension.
                let mut s = path.as_ref().to_path_buf().into_os_string();
                s.push(".");
                s.push(env::consts::EXE_EXTENSION);
                PathBuf::from(s)
            }
        }
    }
}

/// Find a exectable binary's path by name.
///
/// If given an absolute path, returns it if the file exists and is executable.
///
/// If given a relative path, returns an absolute path to the file if
/// it exists and is executable.
///
/// If given a string without path separators, looks for a file named
/// `binary_name` at each directory in `$PATH` and if it finds an executable
/// file there, returns it.
///
/// # Example
///
/// ``` norun
/// use which::which;
/// use std::path::PathBuf;
///
/// let result = which::which("rustc").unwrap();
/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
///
/// ```
pub fn which<T: AsRef<OsStr>>(binary_name: T)
             -> Result<PathBuf, &'static str> {
    env::current_dir()
        .or_else(|_| Err("Couldn't get current directory"))
        .and_then(|cwd| which_in(binary_name, env::var_os("PATH"), &cwd))
}

/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V)
             -> Result<PathBuf, &'static str>
                where T: AsRef<OsStr>,
                      U: AsRef<OsStr>,
                      V: AsRef<Path> {
    // Does it have a path separator?
    let path = ensure_exe_extension(binary_name.as_ref());
    if path.components().count() > 1 {
        if path.is_absolute() {
            if is_exist(&path) && is_executable(&path) {
                // Already fine.
                Ok(path)
            } else {
                // Absolute path but it's not usable.
                Err("Bad absolute path")
            }
        } else {
            // Try to make it absolute.
            let mut new_path = PathBuf::from(cwd.as_ref());
            new_path.push(path);
            let new_path = ensure_exe_extension(new_path);
            if is_exist(&new_path) && is_executable(&new_path) {
                Ok(new_path)
            } else {
                // File doesn't exist or isn't executable.
                Err("Bad relative path")
            }
        }
    } else {
        // No separator, look it up in `paths`.
        paths.and_then(
            |paths|
            env::split_paths(paths.as_ref())
                .map(|p| ensure_exe_extension(p.join(binary_name.as_ref())))
                .skip_while(|p| !(is_exist(&p) && is_executable(&p)))
                .next())
            .ok_or("Cannot find binary path")
    }
}

#[test]
fn test_exe_extension() {
    let expected = PathBuf::from("foo").with_extension(env::consts::EXE_EXTENSION);
    assert_eq!(expected, ensure_exe_extension(PathBuf::from("foo")));
    let p = expected.clone();
    assert_eq!(expected, ensure_exe_extension(p));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension() {
    assert_eq!(PathBuf::from("foo.bar.exe"),
               ensure_exe_extension("foo.bar"));
}

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

    use std::env;
    use std::ffi::{OsStr,OsString};
    use std::fs;
    use std::io;
    use std::path::{Path,PathBuf};
    use tempdir::TempDir;

    struct TestFixture {
        /// Temp directory.
        pub tempdir: TempDir,
        /// $PATH
        pub paths: OsString,
        /// Binaries created in $PATH
        pub bins: Vec<PathBuf>,
    }

    const SUBDIRS: &'static [&'static str] = &["a", "b", "c"];
    const BIN_NAME: &'static str = "bin";

    #[cfg(unix)]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        use libc;
        use std::os::unix::fs::OpenOptionsExt;
        let bin = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::OpenOptions::new()
            .write(true)
            .create(true)
            .mode(0o666 | (libc::S_IXUSR as u32))
            .open(&bin)
            .and_then(|_f| bin.canonicalize())
    }

    fn touch(dir: &Path, path: &str) -> io::Result<PathBuf> {
        let b = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::File::create(&b)
            .and_then(|_f| b.canonicalize())
    }

    #[cfg(not(unix))]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        touch(dir, path)
    }

    impl TestFixture {
        pub fn new() -> TestFixture {
            let tempdir = TempDir::new("which_tests").unwrap();
            let mut builder = fs::DirBuilder::new();
            builder.recursive(true);
            let mut paths = vec!();
            let mut bins = vec!();
            for d in SUBDIRS.iter() {
                let p = tempdir.path().join(d);
                builder.create(&p).unwrap();
                bins.push(mk_bin(&p, &BIN_NAME).unwrap());
                paths.push(p);
            }
            TestFixture {
                tempdir: tempdir,
                paths: env::join_paths(paths).unwrap(),
                bins: bins,
            }
        }

        #[allow(dead_code)]
        pub fn touch(&self, path: &str) -> io::Result<PathBuf> {
            touch(self.tempdir.path(), &path)
        }

        pub fn mk_bin(&self, path: &str) -> io::Result<PathBuf> {
            mk_bin(self.tempdir.path(), &path)
        }
    }

    fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> Result<PathBuf, &'static str> {
        which_in(path, Some(f.paths.clone()), f.tempdir.path())
    }

    #[test]
    #[cfg(unix)]
    fn it_works() {
        use std::process::Command;
        let result = which("rustc");
        assert!(result.is_ok());

        let which_result = Command::new("which")
            .arg("rustc")
            .output();

        assert_eq!(String::from(result.unwrap().to_str().unwrap()),
                   String::from_utf8(which_result.unwrap().stdout).unwrap().trim());
    }

    #[test]
    fn test_which() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &BIN_NAME).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_extension() {
        let f = TestFixture::new();
        let b = Path::new(&BIN_NAME).with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_not_found() {
        let f = TestFixture::new();
        assert!(_which(&f, "a").is_err());
    }

    #[test]
    fn test_which_second() {
        let f = TestFixture::new();
        let b = f.mk_bin("b/another").unwrap();
        assert_eq!(_which(&f, "another").unwrap().canonicalize().unwrap(), b);
    }

    #[test]
    fn test_which_absolute() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &f.bins[1]).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_absolute_extension() {
        let f = TestFixture::new();
        // Don't append EXE_EXTENSION here.
        let b = f.bins[1].parent().unwrap().join(&BIN_NAME);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_extension() {
        // test_which_relative tests a relative path without an extension,
        // so test a relative path with an extension here.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_leading_dot() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "./b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "another").is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_absolute_non_executable() {
        // Shouldn't return non-executable files, even if given an absolute path.
        let f = TestFixture::new();
        let b = f.touch("b/another").unwrap();
        assert!(_which(&f, &b).is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_relative_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "b/another").is_err());
    }
}
<commit_msg>Fix handling of paths with uppercase EXE extension on Windows<commit_after>//! which
//!
//! A Rust equivalent of Unix command `which(1)`.
//! # Example:
//!
//! To find which rustc executable binary is using:
//!
//! ``` norun
//! use which::which;
//!
//! let result = which::which("rustc").unwrap();
//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
//!
//! ```

extern crate libc;
#[cfg(test)]
extern crate tempdir;

use std::ascii::AsciiExt;
use std::path::{Path,PathBuf};
use std::{env, fs};
#[cfg(unix)]
use std::ffi::CString;
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;

fn is_exist(bin_path: &Path) -> bool {

    match fs::metadata(bin_path).map(|metadata|{
        metadata.is_file()
    }) {
        Ok(true) => true,
        _ => false
    }
}

/// Return `true` if `path` is executable.
#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    CString::new(path.as_os_str().as_bytes())
        .and_then(|c| {
            Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 })
        })
        .unwrap_or(false)
}

#[cfg(not(unix))]
fn is_executable(_path: &Path) -> bool { true }

/// Like `Path::with_extension`, but don't replace an existing extension.
fn ensure_exe_extension<T: AsRef<Path>>(path: T) -> PathBuf {
    if env::consts::EXE_EXTENSION.is_empty() {
        // Nothing to do.
        path.as_ref().to_path_buf()
    } else {
        match path.as_ref().extension().and_then(|e| e.to_str()).map(|e| e.eq_ignore_ascii_case(env::consts::EXE_EXTENSION)) {
            // Already has the right extension.
            Some(true) => path.as_ref().to_path_buf(),
            _ => {
                // Append the extension.
                let mut s = path.as_ref().to_path_buf().into_os_string();
                s.push(".");
                s.push(env::consts::EXE_EXTENSION);
                PathBuf::from(s)
            }
        }
    }
}

/// Find a exectable binary's path by name.
///
/// If given an absolute path, returns it if the file exists and is executable.
///
/// If given a relative path, returns an absolute path to the file if
/// it exists and is executable.
///
/// If given a string without path separators, looks for a file named
/// `binary_name` at each directory in `$PATH` and if it finds an executable
/// file there, returns it.
///
/// # Example
///
/// ``` norun
/// use which::which;
/// use std::path::PathBuf;
///
/// let result = which::which("rustc").unwrap();
/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
///
/// ```
pub fn which<T: AsRef<OsStr>>(binary_name: T)
             -> Result<PathBuf, &'static str> {
    env::current_dir()
        .or_else(|_| Err("Couldn't get current directory"))
        .and_then(|cwd| which_in(binary_name, env::var_os("PATH"), &cwd))
}

/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V)
             -> Result<PathBuf, &'static str>
                where T: AsRef<OsStr>,
                      U: AsRef<OsStr>,
                      V: AsRef<Path> {
    // Does it have a path separator?
    let path = ensure_exe_extension(binary_name.as_ref());
    if path.components().count() > 1 {
        if path.is_absolute() {
            if is_exist(&path) && is_executable(&path) {
                // Already fine.
                Ok(path)
            } else {
                // Absolute path but it's not usable.
                Err("Bad absolute path")
            }
        } else {
            // Try to make it absolute.
            let mut new_path = PathBuf::from(cwd.as_ref());
            new_path.push(path);
            let new_path = ensure_exe_extension(new_path);
            if is_exist(&new_path) && is_executable(&new_path) {
                Ok(new_path)
            } else {
                // File doesn't exist or isn't executable.
                Err("Bad relative path")
            }
        }
    } else {
        // No separator, look it up in `paths`.
        paths.and_then(
            |paths|
            env::split_paths(paths.as_ref())
                .map(|p| ensure_exe_extension(p.join(binary_name.as_ref())))
                .skip_while(|p| !(is_exist(&p) && is_executable(&p)))
                .next())
            .ok_or("Cannot find binary path")
    }
}

#[test]
fn test_exe_extension() {
    let expected = PathBuf::from("foo").with_extension(env::consts::EXE_EXTENSION);
    assert_eq!(expected, ensure_exe_extension(PathBuf::from("foo")));
    let p = expected.clone();
    assert_eq!(expected, ensure_exe_extension(p));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension() {
    assert_eq!(PathBuf::from("foo.bar.exe"),
               ensure_exe_extension("foo.bar"));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension_uppercase() {
    assert_eq!(PathBuf::from("foo.EXE"),
               ensure_exe_extension("foo.EXE"));
}

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

    use std::env;
    use std::ffi::{OsStr,OsString};
    use std::fs;
    use std::io;
    use std::path::{Path,PathBuf};
    use tempdir::TempDir;

    struct TestFixture {
        /// Temp directory.
        pub tempdir: TempDir,
        /// $PATH
        pub paths: OsString,
        /// Binaries created in $PATH
        pub bins: Vec<PathBuf>,
    }

    const SUBDIRS: &'static [&'static str] = &["a", "b", "c"];
    const BIN_NAME: &'static str = "bin";

    #[cfg(unix)]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        use libc;
        use std::os::unix::fs::OpenOptionsExt;
        let bin = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::OpenOptions::new()
            .write(true)
            .create(true)
            .mode(0o666 | (libc::S_IXUSR as u32))
            .open(&bin)
            .and_then(|_f| bin.canonicalize())
    }

    fn touch(dir: &Path, path: &str) -> io::Result<PathBuf> {
        let b = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::File::create(&b)
            .and_then(|_f| b.canonicalize())
    }

    #[cfg(not(unix))]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        touch(dir, path)
    }

    impl TestFixture {
        pub fn new() -> TestFixture {
            let tempdir = TempDir::new("which_tests").unwrap();
            let mut builder = fs::DirBuilder::new();
            builder.recursive(true);
            let mut paths = vec!();
            let mut bins = vec!();
            for d in SUBDIRS.iter() {
                let p = tempdir.path().join(d);
                builder.create(&p).unwrap();
                bins.push(mk_bin(&p, &BIN_NAME).unwrap());
                paths.push(p);
            }
            TestFixture {
                tempdir: tempdir,
                paths: env::join_paths(paths).unwrap(),
                bins: bins,
            }
        }

        #[allow(dead_code)]
        pub fn touch(&self, path: &str) -> io::Result<PathBuf> {
            touch(self.tempdir.path(), &path)
        }

        pub fn mk_bin(&self, path: &str) -> io::Result<PathBuf> {
            mk_bin(self.tempdir.path(), &path)
        }
    }

    fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> Result<PathBuf, &'static str> {
        which_in(path, Some(f.paths.clone()), f.tempdir.path())
    }

    #[test]
    #[cfg(unix)]
    fn it_works() {
        use std::process::Command;
        let result = which("rustc");
        assert!(result.is_ok());

        let which_result = Command::new("which")
            .arg("rustc")
            .output();

        assert_eq!(String::from(result.unwrap().to_str().unwrap()),
                   String::from_utf8(which_result.unwrap().stdout).unwrap().trim());
    }

    #[test]
    fn test_which() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &BIN_NAME).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_extension() {
        let f = TestFixture::new();
        let b = Path::new(&BIN_NAME).with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_not_found() {
        let f = TestFixture::new();
        assert!(_which(&f, "a").is_err());
    }

    #[test]
    fn test_which_second() {
        let f = TestFixture::new();
        let b = f.mk_bin("b/another").unwrap();
        assert_eq!(_which(&f, "another").unwrap().canonicalize().unwrap(), b);
    }

    #[test]
    fn test_which_absolute() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &f.bins[1]).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_absolute_path_case() {
        // Test that an absolute path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let p = f.bins[1].with_extension("EXE");
        assert_eq!(_which(&f, &p).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_absolute_extension() {
        let f = TestFixture::new();
        // Don't append EXE_EXTENSION here.
        let b = f.bins[1].parent().unwrap().join(&BIN_NAME);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_extension() {
        // test_which_relative tests a relative path without an extension,
        // so test a relative path with an extension here.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_relative_extension_case() {
        // Test that a relative path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension("EXE");
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_leading_dot() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "./b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "another").is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_absolute_non_executable() {
        // Shouldn't return non-executable files, even if given an absolute path.
        let f = TestFixture::new();
        let b = f.touch("b/another").unwrap();
        assert!(_which(&f, &b).is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_relative_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "b/another").is_err());
    }
}
<|endoftext|>


<commit_before>//! Simple time handling.
//!
//! ![rustc 1.38.0](https://img.shields.io/badge/rustc-1.38.0-blue)
//!
//! # Feature gates
//!
//! ## `#![no_std]`
//!
//! Currently, all structs except `Instant` can be used with `#![no_std]`. As
//! support for the standard library is enabled by default, you muse use
//! `default_features = false` in your `Cargo.toml` to enable this.
//!
//! ```toml
//! [dependencies]
//! time = { version = "0.2", default-features = false }
//! ```
//!
//! Of the structs that are usable, some methods may only be enabled due a
//! reliance on `Instant`. These will be documented alongside the method.
//!
//! ## Serde
//!
//! [Serde](https://github.com/serde-rs/serde) support is behind a feature flag.
//! To enable it, use the `serialization` feature. This is not enabled by
//! default. It _is_ compatible with `#![no_std]`, so long as an allocator is
//! present.
//!
//! ## Deprecated
//!
//! Using the `deprecated` feature allows using deprecated methods. Enabled by
//! default.
//!
//! ```toml
//! [dependencies]
//! time = { version = "0.2", features = ["serialization"] }
//! ```
//!
//! # Formatting
//!
//! Time's formatting behavior is based on `strftime` in C, though it is
//! explicitly _not_ compatible. Specifiers may be missing, added, or have
//! different behavior than in C. As such, you should use the table below, which
//! is an up-to-date reference on what each specifier does.
//!
//! | Specifier | Replaced by                                                            | Example                  |
//! |-----------|------------------------------------------------------------------------|--------------------------|
//! | `%a`      | Abbreviated weekday name                                               | Thu                      |
//! | `%A`      | Full weekday name                                                      | Thursday                 |
//! | `%b`      | Abbreviated month name                                                 | Aug                      |
//! | `%B`      | Full month name                                                        | August                   |
//! | `%c`      | Date and time representation, equivalent to `%a %b %-d %-H:%M:%S %-Y`  | Thu Aug 23 14:55:02 2001 |
//! | `%C`      | Year divided by 100 and truncated to integer (00-99)                   | 20                       |
//! | `%d`      | Day of the month, zero-padded (01-31)                                  | 23                       |
//! | `%D`      | Short MM/DD/YY date, equivalent to `%-m/%d/%y`                         | 8/23/01                  |
//! | `%e`      | Day of the month, space-padded ( 1-31)                                 | 23                       |
//! | `%F`      | Short YYYY-MM-DD date, equivalent to `%-Y-%m-%d`                       | 2001-08-23               |
//! | `%g`      | Week-based year, last two digits (00-99)                               | 01                       |
//! | `%G`      | Week-based year                                                        | 2001                     |
//! | `%H`      | Hour in 24h format (00-23)                                             | 14                       |
//! | `%I`      | Hour in 12h format (01-12)                                             | 02                       |
//! | `%j`      | Day of the year (001-366)                                              | 235                      |
//! | `%m`      | Month as a decimal number (01-12)                                      | 08                       |
//! | `%M`      | Minute (00-59)                                                         | 55                       |
//! | `%p`      | `am` or `pm` designation                                               | pm                       |
//! | `%P`      | `AM` or `PM` designation                                               | PM                       |
//! | `%r`      | 12-hour clock time, equivalent to `%-I:%M:%S %p`                       | 2:55:02 pm               |
//! | `%R`      | 24-hour HH:MM time, equivalent to `%-H:%M`                             | 14:55                    |
//! | `%S`      | Second (00-59)                                                         | 02                       |
//! | `%T`      | ISO 8601 time format (HH:MM:SS), equivalent to `%-H:%M:%S`             | 14:55:02                 |
//! | `%u`      | ISO 8601 weekday as number with Monday as 1 (1-7)                      | 4                        |
//! | `%U`      | Week number with the first Sunday as the first day of week one (00-53) | 33                       |
//! | `%V`      | ISO 8601 week number (01-53)                                           | 34                       |
//! | `%w`      | Weekday as a decimal number with Sunday as 0 (0-6)                     | 4                        |
//! | `%W`      | Week number with the first Monday as the first day of week one (00-53) | 34                       |
//! | `%y`      | Year, last two digits (00-99)                                          | 01                       |
//! | `%Y`      | Year                                                                   | 2001                     |
//! | `%z`      | ISO 8601 offset from UTC in timezone (+HHMM)                           | +0100                    |
//! | `%%`      | Literal `%`                                                            | %                        |
//!
//! ## Modifiers
//!
//! All specifiers that are strictly numerical have modifiers for formatting.
//! Adding a modifier to a non-supporting specifier is a no-op.
//!
//! | Modifier         | Behavior        | Example                       |
//! |------------------|-----------------|-------------------------------|
//! | `-` (dash)       | No padding      | `%-d` => `5` instead of `05`  |
//! | `_` (underscore) | Pad with spaces | `%_d` => ` 5` instead of `05` |
//! | `0`              | Pad with zeros  | `%0e` => `05` instead of ` 5` |

#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#![deny(
    anonymous_parameters,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    const_err,
    illegal_floating_point_literal_pattern,
    late_bound_lifetime_arguments,
    path_statements,
    patterns_in_fns_without_body,
    clippy::all
)]
#![warn(
    unused_extern_crates,
    box_pointers,
    missing_copy_implementations,
    missing_debug_implementations,
    single_use_lifetimes,
    unused_qualifications,
    variant_size_differences,
    clippy::pedantic,
    clippy::nursery,
    clippy::missing_docs_in_private_items,
    clippy::dbg_macro,
    clippy::decimal_literal_representation,
    clippy::get_unwrap,
    clippy::option_unwrap_used,
    clippy::print_stdout,
    clippy::result_unwrap_used
)]
#![allow(
    clippy::suspicious_arithmetic_impl,
    clippy::inline_always,
    // TODO Remove once rust-lang/rust-clippy#4605 is resolved in stable.
    clippy::cast_sign_loss,
    clippy::cast_possible_wrap,
    clippy::cast_lossless,
    clippy::module_name_repetitions
)]

#[macro_use]
extern crate alloc;

macro_rules! format_conditional {
    ($conditional:ident) => {
        format!(concat!(stringify!($conditional), "={}"), $conditional)
    };

    ($first_conditional:ident, $($conditional:ident),*) => {{
        let mut s = alloc::string::String::new();
        s.push_str(&format_conditional!($first_conditional));
        $(s.push_str(&format!(concat!(", ", stringify!($conditional), "={}"), $conditional));)*
        s
    }}
}

macro_rules! assert_value_in_range {
    ($value:ident in $start:expr => $end:expr) => {
        if !($start..=$end).contains(&$value) {
            panic!(
                concat!(stringify!($value), " must be in the range {}..={} (was {})"),
                $start,
                $end,
                $value,
            );
        }
    };

    ($value:ident in $start:expr => exclusive $end:expr) => {
        if !($start..$end).contains(&$value) {
            panic!(
                concat!(stringify!($value), " must be in the range {}..{} (was {})"),
                $start,
                $end,
                $value,
            );
        }
    };

    ($value:ident in $start:expr => $end:expr, given $($conditional:ident),+ $(,)?) => {
        if !($start..=$end).contains(&$value) {
            panic!(
                concat!(stringify!($value), " must be in the range {}..={} given{} (was {})"),
                $start,
                $end,
                &format_conditional!($($conditional),+),
                $value,
            );
        };
    };
}

/// The `Date` struct and its associated `impl`s.
mod date;
/// The `DateTime` struct and its associated `impl`s.
mod date_time;
/// The `Duration` struct and its associated `impl`s.
mod duration;
mod format;
/// The `Instant` struct and its associated `impl`s.
#[cfg(feature = "std")]
mod instant;
/// A collection of traits extending built-in numerical types.
mod numerical_traits;
/// The `OffsetDateTime` struct and its associated `impl`s.
mod offset_date_time;
/// Ensure certain methods are present on all types.
mod shim;
/// The `Sign` struct and its associated `impl`s.
mod sign;
/// The `Time` struct and its associated `impl`s.
mod time;
/// The `UtcOffset` struct and its associated `impl`s.
mod utc_offset;
/// Days of the week.
mod weekday;

pub use self::time::Time;
use core::fmt;
pub use date::{days_in_year, is_leap_year, weeks_in_year, Date};
pub use date_time::DateTime;
pub use duration::Duration;
pub use format::DeferredFormat;
pub use format::Language;
pub use format::ParseError;
#[cfg(feature = "std")]
pub use instant::Instant;
pub use numerical_traits::{NumericalDuration, NumericalStdDuration};
pub use offset_date_time::OffsetDateTime;
pub(crate) use shim::NumberExt;
pub use sign::Sign;
pub use utc_offset::UtcOffset;
pub use weekday::Weekday;

/// A collection of traits (and possibly types, enums, etc.) that are useful to
/// import. Unlike the standard library, this must be explicitly included.
///
/// ```rust,no_run
/// use time::prelude::*;
/// ```
///
/// The prelude may grow in minor releases. Any removals will only occur in
/// major releases.
pub mod prelude {
    pub use crate::{NumericalDuration, NumericalStdDuration};
}

/// A stable alternative to [`alloc::v1::prelude`](https://doc.rust-lang.org/stable/alloc/prelude/v1/index.html).
/// Should be used anywhere `#![no_std]` is allowed.
#[cfg(not(feature = "std"))]
mod no_std_prelude {
    #![allow(unused_imports)]
    pub(crate) use alloc::borrow::ToOwned;
    pub(crate) use alloc::boxed::Box;
    pub(crate) use alloc::string::{String, ToString};
    pub(crate) use alloc::vec::Vec;
}

/// An error type indicating that a conversion failed because the target type
/// could not store the initial value.
///
/// ```rust
/// # use time::{Duration, OutOfRangeError};
/// # use core::time::Duration as StdDuration;
/// # use core::{any::Any, convert::TryFrom};
/// // "Construct" an `OutOfRangeError`.
/// let error = StdDuration::try_from(Duration::seconds(-1)).unwrap_err();
/// assert!(Any::is::<OutOfRangeError>(&error));
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OutOfRangeError {
    /// Include zero-sized field so users can't construct this explicitly. This
    /// ensures forwards-compatibility, as anyone matching on this type has to
    /// explicitly discard the fields.
    unused: (),
}

impl OutOfRangeError {
    /// Create an new `OutOfRangeError`.
    #[inline(always)]
    pub(crate) const fn new() -> Self {
        Self { unused: () }
    }
}

impl fmt::Display for OutOfRangeError {
    #[inline(always)]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
        f.write_str("Source value is out of range for the target type")
    }
}

#[cfg(feature = "std")]
impl std::error::Error for OutOfRangeError {}

// For some back-compatibility, we're also implementing some deprecated types.

#[cfg(all(feature = "std", feature = "deprecated"))]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(since = "0.2.0", note = "Use `Instant`")]
pub type PreciseTime = Instant;

#[cfg(all(feature = "std", feature = "deprecated"))]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(since = "0.2.0", note = "Use `Instant`")]
pub type SteadyTime = Instant;
<commit_msg>Correct placement of example in docs<commit_after>//! Simple time handling.
//!
//! ![rustc 1.38.0](https://img.shields.io/badge/rustc-1.38.0-blue)
//!
//! # Feature gates
//!
//! ## `#![no_std]`
//!
//! Currently, all structs except `Instant` can be used with `#![no_std]`. As
//! support for the standard library is enabled by default, you muse use
//! `default_features = false` in your `Cargo.toml` to enable this.
//!
//! ```toml
//! [dependencies]
//! time = { version = "0.2", default-features = false }
//! ```
//!
//! Of the structs that are usable, some methods may only be enabled due a
//! reliance on `Instant`. These will be documented alongside the method.
//!
//! ## Serde
//!
//! [Serde](https://github.com/serde-rs/serde) support is behind a feature flag.
//! To enable it, use the `serialization` feature. This is not enabled by
//! default. It _is_ compatible with `#![no_std]`, so long as an allocator is
//! present.
//!
//! ```toml
//! [dependencies]
//! time = { version = "0.2", features = ["serialization"] }
//! ```
//!
//! ## Deprecated
//!
//! Using the `deprecated` feature allows using deprecated methods. Enabled by
//! default.
//!
//! # Formatting
//!
//! Time's formatting behavior is based on `strftime` in C, though it is
//! explicitly _not_ compatible. Specifiers may be missing, added, or have
//! different behavior than in C. As such, you should use the table below, which
//! is an up-to-date reference on what each specifier does.
//!
//! | Specifier | Replaced by                                                            | Example                  |
//! |-----------|------------------------------------------------------------------------|--------------------------|
//! | `%a`      | Abbreviated weekday name                                               | Thu                      |
//! | `%A`      | Full weekday name                                                      | Thursday                 |
//! | `%b`      | Abbreviated month name                                                 | Aug                      |
//! | `%B`      | Full month name                                                        | August                   |
//! | `%c`      | Date and time representation, equivalent to `%a %b %-d %-H:%M:%S %-Y`  | Thu Aug 23 14:55:02 2001 |
//! | `%C`      | Year divided by 100 and truncated to integer (00-99)                   | 20                       |
//! | `%d`      | Day of the month, zero-padded (01-31)                                  | 23                       |
//! | `%D`      | Short MM/DD/YY date, equivalent to `%-m/%d/%y`                         | 8/23/01                  |
//! | `%e`      | Day of the month, space-padded ( 1-31)                                 | 23                       |
//! | `%F`      | Short YYYY-MM-DD date, equivalent to `%-Y-%m-%d`                       | 2001-08-23               |
//! | `%g`      | Week-based year, last two digits (00-99)                               | 01                       |
//! | `%G`      | Week-based year                                                        | 2001                     |
//! | `%H`      | Hour in 24h format (00-23)                                             | 14                       |
//! | `%I`      | Hour in 12h format (01-12)                                             | 02                       |
//! | `%j`      | Day of the year (001-366)                                              | 235                      |
//! | `%m`      | Month as a decimal number (01-12)                                      | 08                       |
//! | `%M`      | Minute (00-59)                                                         | 55                       |
//! | `%p`      | `am` or `pm` designation                                               | pm                       |
//! | `%P`      | `AM` or `PM` designation                                               | PM                       |
//! | `%r`      | 12-hour clock time, equivalent to `%-I:%M:%S %p`                       | 2:55:02 pm               |
//! | `%R`      | 24-hour HH:MM time, equivalent to `%-H:%M`                             | 14:55                    |
//! | `%S`      | Second (00-59)                                                         | 02                       |
//! | `%T`      | ISO 8601 time format (HH:MM:SS), equivalent to `%-H:%M:%S`             | 14:55:02                 |
//! | `%u`      | ISO 8601 weekday as number with Monday as 1 (1-7)                      | 4                        |
//! | `%U`      | Week number with the first Sunday as the first day of week one (00-53) | 33                       |
//! | `%V`      | ISO 8601 week number (01-53)                                           | 34                       |
//! | `%w`      | Weekday as a decimal number with Sunday as 0 (0-6)                     | 4                        |
//! | `%W`      | Week number with the first Monday as the first day of week one (00-53) | 34                       |
//! | `%y`      | Year, last two digits (00-99)                                          | 01                       |
//! | `%Y`      | Year                                                                   | 2001                     |
//! | `%z`      | ISO 8601 offset from UTC in timezone (+HHMM)                           | +0100                    |
//! | `%%`      | Literal `%`                                                            | %                        |
//!
//! ## Modifiers
//!
//! All specifiers that are strictly numerical have modifiers for formatting.
//! Adding a modifier to a non-supporting specifier is a no-op.
//!
//! | Modifier         | Behavior        | Example                       |
//! |------------------|-----------------|-------------------------------|
//! | `-` (dash)       | No padding      | `%-d` => `5` instead of `05`  |
//! | `_` (underscore) | Pad with spaces | `%_d` => ` 5` instead of `05` |
//! | `0`              | Pad with zeros  | `%0e` => `05` instead of ` 5` |

#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#![deny(
    anonymous_parameters,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    const_err,
    illegal_floating_point_literal_pattern,
    late_bound_lifetime_arguments,
    path_statements,
    patterns_in_fns_without_body,
    clippy::all
)]
#![warn(
    unused_extern_crates,
    box_pointers,
    missing_copy_implementations,
    missing_debug_implementations,
    single_use_lifetimes,
    unused_qualifications,
    variant_size_differences,
    clippy::pedantic,
    clippy::nursery,
    clippy::missing_docs_in_private_items,
    clippy::dbg_macro,
    clippy::decimal_literal_representation,
    clippy::get_unwrap,
    clippy::option_unwrap_used,
    clippy::print_stdout,
    clippy::result_unwrap_used
)]
#![allow(
    clippy::suspicious_arithmetic_impl,
    clippy::inline_always,
    // TODO Remove once rust-lang/rust-clippy#4605 is resolved in stable.
    clippy::cast_sign_loss,
    clippy::cast_possible_wrap,
    clippy::cast_lossless,
    clippy::module_name_repetitions
)]

#[macro_use]
extern crate alloc;

macro_rules! format_conditional {
    ($conditional:ident) => {
        format!(concat!(stringify!($conditional), "={}"), $conditional)
    };

    ($first_conditional:ident, $($conditional:ident),*) => {{
        let mut s = alloc::string::String::new();
        s.push_str(&format_conditional!($first_conditional));
        $(s.push_str(&format!(concat!(", ", stringify!($conditional), "={}"), $conditional));)*
        s
    }}
}

macro_rules! assert_value_in_range {
    ($value:ident in $start:expr => $end:expr) => {
        if !($start..=$end).contains(&$value) {
            panic!(
                concat!(stringify!($value), " must be in the range {}..={} (was {})"),
                $start,
                $end,
                $value,
            );
        }
    };

    ($value:ident in $start:expr => exclusive $end:expr) => {
        if !($start..$end).contains(&$value) {
            panic!(
                concat!(stringify!($value), " must be in the range {}..{} (was {})"),
                $start,
                $end,
                $value,
            );
        }
    };

    ($value:ident in $start:expr => $end:expr, given $($conditional:ident),+ $(,)?) => {
        if !($start..=$end).contains(&$value) {
            panic!(
                concat!(stringify!($value), " must be in the range {}..={} given{} (was {})"),
                $start,
                $end,
                &format_conditional!($($conditional),+),
                $value,
            );
        };
    };
}

/// The `Date` struct and its associated `impl`s.
mod date;
/// The `DateTime` struct and its associated `impl`s.
mod date_time;
/// The `Duration` struct and its associated `impl`s.
mod duration;
mod format;
/// The `Instant` struct and its associated `impl`s.
#[cfg(feature = "std")]
mod instant;
/// A collection of traits extending built-in numerical types.
mod numerical_traits;
/// The `OffsetDateTime` struct and its associated `impl`s.
mod offset_date_time;
/// Ensure certain methods are present on all types.
mod shim;
/// The `Sign` struct and its associated `impl`s.
mod sign;
/// The `Time` struct and its associated `impl`s.
mod time;
/// The `UtcOffset` struct and its associated `impl`s.
mod utc_offset;
/// Days of the week.
mod weekday;

pub use self::time::Time;
use core::fmt;
pub use date::{days_in_year, is_leap_year, weeks_in_year, Date};
pub use date_time::DateTime;
pub use duration::Duration;
pub use format::DeferredFormat;
pub use format::Language;
pub use format::ParseError;
#[cfg(feature = "std")]
pub use instant::Instant;
pub use numerical_traits::{NumericalDuration, NumericalStdDuration};
pub use offset_date_time::OffsetDateTime;
pub(crate) use shim::NumberExt;
pub use sign::Sign;
pub use utc_offset::UtcOffset;
pub use weekday::Weekday;

/// A collection of traits (and possibly types, enums, etc.) that are useful to
/// import. Unlike the standard library, this must be explicitly included.
///
/// ```rust,no_run
/// use time::prelude::*;
/// ```
///
/// The prelude may grow in minor releases. Any removals will only occur in
/// major releases.
pub mod prelude {
    pub use crate::{NumericalDuration, NumericalStdDuration};
}

/// A stable alternative to [`alloc::v1::prelude`](https://doc.rust-lang.org/stable/alloc/prelude/v1/index.html).
/// Should be used anywhere `#![no_std]` is allowed.
#[cfg(not(feature = "std"))]
mod no_std_prelude {
    #![allow(unused_imports)]
    pub(crate) use alloc::borrow::ToOwned;
    pub(crate) use alloc::boxed::Box;
    pub(crate) use alloc::string::{String, ToString};
    pub(crate) use alloc::vec::Vec;
}

/// An error type indicating that a conversion failed because the target type
/// could not store the initial value.
///
/// ```rust
/// # use time::{Duration, OutOfRangeError};
/// # use core::time::Duration as StdDuration;
/// # use core::{any::Any, convert::TryFrom};
/// // "Construct" an `OutOfRangeError`.
/// let error = StdDuration::try_from(Duration::seconds(-1)).unwrap_err();
/// assert!(Any::is::<OutOfRangeError>(&error));
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OutOfRangeError {
    /// Include zero-sized field so users can't construct this explicitly. This
    /// ensures forwards-compatibility, as anyone matching on this type has to
    /// explicitly discard the fields.
    unused: (),
}

impl OutOfRangeError {
    /// Create an new `OutOfRangeError`.
    #[inline(always)]
    pub(crate) const fn new() -> Self {
        Self { unused: () }
    }
}

impl fmt::Display for OutOfRangeError {
    #[inline(always)]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
        f.write_str("Source value is out of range for the target type")
    }
}

#[cfg(feature = "std")]
impl std::error::Error for OutOfRangeError {}

// For some back-compatibility, we're also implementing some deprecated types.

#[cfg(all(feature = "std", feature = "deprecated"))]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(since = "0.2.0", note = "Use `Instant`")]
pub type PreciseTime = Instant;

#[cfg(all(feature = "std", feature = "deprecated"))]
#[allow(clippy::missing_docs_in_private_items)]
#[deprecated(since = "0.2.0", note = "Use `Instant`")]
pub type SteadyTime = Instant;
<|endoftext|>


<commit_before>extern crate hyper;
extern crate hyper_native_tls;
extern crate pbr;
extern crate regex;

use pbr::ProgressBar;
use std::{process,str};
use std::collections::HashMap;
use hyper::client::response::Response;
use hyper::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use hyper::header::ContentLength;
use std::io::Read;
use std::io::prelude::*;
use std::fs::File;
use regex::Regex;

pub struct Rafy {
    pub url: String,
    pub title: String,
    pub rating: String,
    pub viewcount: u32,
    pub author: String,
    pub length: u32,
    //pub duration: String,
    //pub likes: u32,
    //pub dislikes: u32,
    //pub description: String,
    //pub streams: ,
    //pub audiostreams: ,
    //pub allstreams: ,
}

impl Rafy {
    pub fn new(url: &str) -> Rafy {
        //Regex for youtube URLs.
        let url_regex = Regex::new(r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*").unwrap();
        let mut vid = url;

        if url_regex.is_match(vid) {
            let vid_split = url_regex.captures(vid).unwrap();
            vid = vid_split.get(1).unwrap().as_str();
        }

        let url_info = format!("https://youtube.com/get_video_info?video_id={}", vid);

        let mut response = Self::send_request(&url_info);
        let mut response_str = String::new();
        response.read_to_string(&mut response_str).unwrap();
        let hq = Self::parse_url(&response_str);

        if hq["status"] != "ok" {
            println!("Video not found!");
            process::exit(1);
        }

        let title = &hq["title"];
        let rating = &hq["avg_rating"];
        let viewcount = &hq["view_count"];
        let author = &hq["author"];
        let length = &hq["length_seconds"];

        //Self::download(hq);

        Rafy {
            url: url.to_string(),
            title: title.to_string(),
            rating: rating.to_string(),
            viewcount: viewcount.trim()
                        .parse::<u32>()
                        .unwrap(),
            author: author.to_string(),
            length: length.trim()
                        .parse::<u32>()
                        .unwrap(),
        }
    }

    fn download(hq: HashMap<String, String>) {
        // get streams
        let streams: Vec<&str> = hq["url_encoded_fmt_stream_map"]
            .split(',')
            .collect();

        // list of available qualities
        let mut qualities: HashMap<i32, (String, String)> = HashMap::new();
        for (i, url) in streams.iter().enumerate() {
            let quality = Self::parse_url(url);
            let extension = quality["type"]
                .split('/')
                .nth(1)
                .unwrap()
                .split(';')
                .next()
                .unwrap();
            qualities.insert(i as i32,
                             (quality["url"].to_string(), extension.to_owned()));
            println!("{}- {} {}",
                     i,
                     quality["quality"],
                     quality["type"]);
        }
    }

    fn send_request(url: &str) -> Response {
        let ssl = NativeTlsClient::new().unwrap();
        let connector = HttpsConnector::new(ssl);
        let client = Client::with_connector(connector);
        client.get(url).send().unwrap_or_else(|e| {
            println!("Network request failed: {}", e);
            process::exit(1);
        })
    }

    fn parse_url(query: &str) -> HashMap<String, String> {
        let u = format!("{}{}", "http://e.com?", query);
        let parsed_url = hyper::Url::parse(&u).unwrap();
        parsed_url.query_pairs().into_owned().collect()
    }
}
<commit_msg>Add ability to extract streams<commit_after>extern crate hyper;
extern crate hyper_native_tls;
extern crate pbr;
extern crate regex;

use pbr::ProgressBar;
use std::{process,str};
use std::collections::HashMap;
use hyper::client::response::Response;
use hyper::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use hyper::header::ContentLength;
use std::io::Read;
use std::io::prelude::*;
use std::fs::File;
use regex::Regex;

pub struct Rafy {
    pub url: String,
    pub title: String,
    pub rating: String,
    pub viewcount: u32,
    pub author: String,
    pub length: u32,
    //pub duration: String,
    //pub likes: u32,
    //pub dislikes: u32,
    //pub description: String,
    pub streams: Vec<Stream>,
    //pub audiostreams: ,
    //pub allstreams: ,
}

pub struct Stream {
    pub extension: String,
    pub quality: String,
    pub url: String,
}

impl Rafy {
    pub fn new(url: &str) -> Rafy {
        //Regex for youtube URLs.
        let url_regex = Regex::new(r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*").unwrap();
        let mut vid = url;

        if url_regex.is_match(vid) {
            let vid_split = url_regex.captures(vid).unwrap();
            vid = vid_split.get(1)
                    .unwrap()
                    .as_str();
        }

        let url_info = format!("https://youtube.com/get_video_info?video_id={}", vid);
        //println!("{}", url_info);

        let mut response = Self::send_request(&url_info);
        let mut response_str = String::new();
        response.read_to_string(&mut response_str).unwrap();
        let mut hq = Self::parse_url(&response_str);

        if hq["status"] != "ok" {
            println!("Video not found!");
            process::exit(1);
        }

        let title = &hq["title"];
        let rating = &hq["avg_rating"];
        let viewcount = &hq["view_count"];
        let author = &hq["author"];
        let length = &hq["length_seconds"];
        /*let streams: Vec<String> = hq["url_encoded_fmt_stream_map"]
                                    .split(',')
                                    .map(|s| Self::parse_url(s)["url"].to_string())
                                    .collect();*/

        let streams = Self::get_streams(&hq);

        //Self::download(hq);

        Rafy {
            url: url.to_string(),
            title: title.to_string(),
            rating: rating.to_string(),
            viewcount: viewcount.trim()
                        .parse::<u32>()
                        .unwrap(),
            author: author.to_string(),
            length: length.trim()
                        .parse::<u32>()
                        .unwrap(),
            streams: streams,
        }
    }

    fn get_streams(hq: &HashMap<String, String>) -> Vec<Stream> {
        let mut parsed_streams: Vec<Stream> = Vec::new();

        let streams: Vec<&str> = hq["url_encoded_fmt_stream_map"]
            .split(',')
            .collect();

        for url in streams.iter() {
            let parsed = Self::parse_url(url);

            let extension = &parsed["type"]
                .split('/')
                .nth(1)
                .unwrap()
                .split(';')
                .next()
                .unwrap();
            let quality = &parsed["quality"];
            let stream_url = &parsed["url"];

            let parsed_stream = Stream {
                        extension: extension.to_string(),
                        quality: quality.to_string(),
                        url: stream_url.to_string()
                    };

            parsed_streams.push(parsed_stream);
        }

        parsed_streams
    }

    fn download(hq: HashMap<String, String>) {
        // get streams
        let streams: Vec<&str> = hq["url_encoded_fmt_stream_map"]
            .split(',')
            .collect();

        // list of available qualities
        let mut qualities: HashMap<i32, (String, String)> = HashMap::new();
        for (i, url) in streams.iter().enumerate() {
            let quality = Self::parse_url(url);
            let extension = quality["type"]
                .split('/')
                .nth(1)
                .unwrap()
                .split(';')
                .next()
                .unwrap();
            qualities.insert(i as i32,
                             (quality["url"].to_string(), extension.to_owned()));
            println!("{}- {} {}",
                     i,
                     quality["quality"],
                     quality["type"]);
        }
    }

    fn send_request(url: &str) -> Response {
        let ssl = NativeTlsClient::new().unwrap();
        let connector = HttpsConnector::new(ssl);
        let client = Client::with_connector(connector);
        client.get(url).send().unwrap_or_else(|e| {
            println!("Network request failed: {}", e);
            process::exit(1);
        })
    }

    fn parse_url(query: &str) -> HashMap<String, String> {
        let u = format!("{}{}", "http://e.com?", query);
        let parsed_url = hyper::Url::parse(&u).unwrap();
        parsed_url.query_pairs().into_owned().collect()
    }
}
<|endoftext|>