<commit_before>use std::f32::{NEG_INFINITY, INFINITY};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::thread;

use time;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};
use motion::CENTER_OF_THE_WORLD;
use space::Pinfield;

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0,
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let value = match agent.job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0,
    };
    orientation(agent.team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;

    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personæ(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
        // breadth of scholarship bonus
        if world.agent_to_pinfield_ref(Agent {
                    team: team,
                    job_description: JobDescription::Scholar,
                })
                .to_locales()
                .len() >= 2 {
            valuation += orientation(team) * 0.5
        }
    }

    // ponies and servants want to be in the center of the world's
    // action, maybe??
    let center = Pinfield(CENTER_OF_THE_WORLD);
    // cast to signed to avoid overflow
    let orange_centerism: i8 = world.orange_servants.union(
        world.orange_ponies).intersection(center).pincount() as i8;
    let blue_centerism: i8 = world.blue_servants.union(
        world.blue_ponies).intersection(center).pincount() as i8;
    valuation += (orange_centerism - blue_centerism) as f32 * 0.1;

    valuation
}

fn mmv_lva_heuristic(commit: &Commit) -> f32 {
    // https://chessprogramming.wikispaces.com/MVV-LVA
    match commit.hospitalization {
        Some(patient) => (
            figurine_valuation(patient) - figurine_valuation(commit.patch.star)),
        None => 0.0,
    }
}

fn order_moves(commits: &mut Vec<Commit>) {
    commits.sort_by(|a, b| {
        mmv_lva_heuristic(&b)
            .partial_cmp(&mmv_lva_heuristic(&a))
            .unwrap_or(Ordering::Equal)
    });
}

pub fn α_β_negamax_search(
    world: WorldState, depth: u8, mut α: f32, β: f32,
    /* déjà_vu_table: &mut HashMap<WorldState, f32> */) -> (Option<Commit>, f32) {
    let team = world.to_move;
    let potential_score = orientation(team) * score(world);
    let mut premonitions = world.reckless_lookahead();
    order_moves(&mut premonitions);
    if depth == 0 || premonitions.is_empty() {
        return (None, potential_score)
    };
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let mut value: f32;
        let cached: bool;
        {
            // let cached_value_maybe = déjà_vu_table.get(&premonition.tree);
            let cached_value_maybe = None;
            match cached_value_maybe {
                Some(&cached_value) => {
                    cached = true;
                    value = cached_value;
                }
                None => {
                    cached = false;
                    // XXX fake assignment to work around the compiler's
                    // "possibly uninitialized value" rules
                    value = NEG_INFINITY;
                }
            };
        }

        if !cached {
            let (_, acquired_value) = α_β_negamax_search(
                premonition.tree, depth - 1,
                -β, -α, /* déjà_vu_table */);
            value = -acquired_value;
            // déjà_vu_table.insert(premonition.tree, value);
        }

        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
        if value > α {
            α = value;
        }
        if α >= β {
            break;
        }
    }

    (optimand, optimum)
}

pub fn potentially_timebound_kickoff(world: &WorldState, depth: u8,
                                     nihilistically: bool,
                                     deadline_maybe: Option<time::Timespec>)
                                     -> Option<Vec<(Commit, f32)>> {
    // let mut déjà_vu_table: HashMap<WorldState, f32> = HashMap::new();
    let mut premonitions;
    if nihilistically {
        premonitions = world.reckless_lookahead();
    } else {
        premonitions = world.lookahead();
    }
    order_moves(&mut premonitions);
    let mut forecasts = Vec::new();
    for &premonition in &premonitions {
        if let Some(deadline) = deadline_maybe {
            if time::get_time() > deadline {
                return None;
            }
        }
        let thread_handle = thread::spawn(move || {
            α_β_negamax_search(
                premonition.tree, depth - 1,
                NEG_INFINITY, INFINITY,
                // &mut déjà_vu_table
                // TODO RESEARCH: how do we maintain a shared déjà vu
                // table while still doing work in a thread? Channels??
            )
        });
        let (_grandchild, mut value) = thread_handle.join().ok().unwrap();
        value = -value;
        forecasts.push((premonition, value));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    Some(forecasts)
}

pub fn kickoff(world: &WorldState, depth: u8,
               nihilistically: bool) -> Vec<(Commit, f32)> {
    potentially_timebound_kickoff(world, depth, nihilistically, None).unwrap()
}

pub fn iterative_deepening_kickoff(world: &WorldState, timeout: time::Duration,
                                   nihilistically: bool)
                                   -> (Vec<(Commit, f32)>, u8) {
    let deadline = time::get_time() + timeout;
    let mut depth = 1;
    let mut forecasts = potentially_timebound_kickoff(
        world, depth, nihilistically, None).unwrap();
    while let Some(prophecy) = potentially_timebound_kickoff(
            world, depth, nihilistically, Some(deadline)) {
        forecasts = prophecy;
        depth += 1;
    }
    (forecasts, depth)
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use time;
    use super::{kickoff, score};
    use space::Locale;
    use life::WorldState;
    use identity::Team;

    impl WorldState {
        fn no_castling_at_all(&mut self) {
            self.orange_east_service_eligibility = false;
            self.orange_west_service_eligibility = false;
            self.blue_east_service_eligibility = false;
            self.blue_west_service_eligibility = false;
        }
    }

    #[bench]
    fn benchmark_scoring(b: &mut Bencher) {
        b.iter(|| score(WorldState::new()));
    }

    #[bench]
    fn benchmark_kickoff_depth_1(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 1, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_arbys(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_carefully(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, false));
    }

    #[ignore]
    #[bench]
    fn benchmark_kickoff_depth_3(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 3, true));
    }

    #[test]
    #[ignore]  // more research is needed
    fn concerning_short_circuiting_upon_finding_critical_endangerment() {
        let ws = WorldState::reconstruct("7K/r7/1r6/8/8/8/8/7k b -".to_owned());
        let start = time::get_time();
        kickoff(&ws, 30, true);
        let duration = time::get_time() - start;
        assert!(duration.num_seconds() < 20);
    }

    #[test]
    #[allow(float_cmp)]
    fn concerning_fairness_of_the_initial_position() {
        // It's okay to assume this is really 0.0. Floats may be imprecise,
        // but they do have well-defined behavior.
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    fn concerning_servant_ascension_choices() {
        let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
        // looking ahead 3 moves allows the Leafline AI to catch the
        // split, whereby transforming into a pony (rather than
        // transitioning into a princess, as would usually be
        // expected) endangers both the blue princess and figurehead
        let (ref best_move, score) = kickoff(&ws, 3, true)[0];
        println!("{:?}", best_move);
        assert!(score > 0.0);
        assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
    }

    #[test]
    fn experimentally_about_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 });
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 });
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Blue has another servant sitting nowhere interesting
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 3, file: 6 });
        world.no_castling_at_all();

        let depth = 2;
        let advisory = kickoff(&world, depth, true);

        // taking the pony is the right thing to do
        assert_eq!(Locale { rank: 0, file: 0 }, advisory[0].0.patch.whither);

        // And, furthermore, the answer should be the same if we face the
        // same situation with the colors reversed
        //
        // XXX this would be tidier and less copy-pastey if I had more
        // general figurine-placing functions that were three rather than
        // two levels of abstraction above twiddling bits on an unsigned
        // int ... oh, well
        let mut negaworld = WorldState::new_except_empty();
        negaworld.to_move = Team::Blue;

        // scholar endangers pony
        negaworld.orange_ponies = negaworld.orange_ponies.alight(
            Locale { rank: 0, file: 0 });
        negaworld.blue_scholars = negaworld.blue_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 7, file: 1 });
        negaworld.blue_ponies = negaworld.blue_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Orange has another servant sitting nowhere interesting
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 3, file: 6 });
        negaworld.to_move = Team::Blue;

        negaworld.no_castling_at_all();

        let negadvisory = kickoff(&negaworld, depth, true);

        // taking the pony is still the right thing to do, even in the
        // negaworld
        assert_eq!(Locale { rank: 0, file: 0 },
                   negadvisory[0].0.patch.whither);
    }

}
<commit_msg>wrap the déjà vu table in a lock, wrapped in an atomic reference counter<commit_after>use std::f32::{NEG_INFINITY, INFINITY};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;

use time;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};
use motion::CENTER_OF_THE_WORLD;
use space::Pinfield;

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0,
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let value = match agent.job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0,
    };
    orientation(agent.team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;

    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personæ(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
        // breadth of scholarship bonus
        if world.agent_to_pinfield_ref(Agent {
                    team: team,
                    job_description: JobDescription::Scholar,
                })
                .to_locales()
                .len() >= 2 {
            valuation += orientation(team) * 0.5
        }
    }

    // ponies and servants want to be in the center of the world's
    // action, maybe??
    let center = Pinfield(CENTER_OF_THE_WORLD);
    // cast to signed to avoid overflow
    let orange_centerism: i8 = world.orange_servants.union(
        world.orange_ponies).intersection(center).pincount() as i8;
    let blue_centerism: i8 = world.blue_servants.union(
        world.blue_ponies).intersection(center).pincount() as i8;
    valuation += (orange_centerism - blue_centerism) as f32 * 0.1;

    valuation
}

fn mmv_lva_heuristic(commit: &Commit) -> f32 {
    // https://chessprogramming.wikispaces.com/MVV-LVA
    match commit.hospitalization {
        Some(patient) => (
            figurine_valuation(patient) - figurine_valuation(commit.patch.star)),
        None => 0.0,
    }
}

fn order_moves(commits: &mut Vec<Commit>) {
    commits.sort_by(|a, b| {
        mmv_lva_heuristic(&b)
            .partial_cmp(&mmv_lva_heuristic(&a))
            .unwrap_or(Ordering::Equal)
    });
}

pub fn α_β_negamax_search(
    world: WorldState, depth: u8, mut α: f32, β: f32,
    memory_bank: Arc<Mutex<HashMap<WorldState, f32>>>) -> (Option<Commit>, f32) {
    let team = world.to_move;
    let potential_score = orientation(team) * score(world);
    let mut premonitions = world.reckless_lookahead();
    order_moves(&mut premonitions);
    if depth == 0 || premonitions.is_empty() {
        return (None, potential_score)
    };
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let mut value = NEG_INFINITY;  // can't hurt to be pessimistic
        let cached: bool;
        {
            let open_vault = memory_bank.lock().unwrap();
            let cached_value_maybe = open_vault.get(&premonition.tree);
            match cached_value_maybe {
                Some(&cached_value) => {
                    cached = true;
                    value = cached_value;
                }
                None => { cached = false; }
            };
        }

        if !cached {
            let (_, acquired_value) = α_β_negamax_search(
                premonition.tree, depth - 1,
                -β, -α, memory_bank.clone()
            );
            value = -acquired_value;
            memory_bank.lock().unwrap().insert(premonition.tree, value);
        }

        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
        if value > α {
            α = value;
        }
        if α >= β {
            break;
        }
    }

    (optimand, optimum)
}

pub fn potentially_timebound_kickoff(world: &WorldState, depth: u8,
                                     nihilistically: bool,
                                     deadline_maybe: Option<time::Timespec>)
                                     -> Option<Vec<(Commit, f32)>> {
    let déjà_vu_table: HashMap<WorldState, f32> = HashMap::new();
    let memory_bank = Arc::new(Mutex::new(déjà_vu_table));
    let mut premonitions;
    if nihilistically {
        premonitions = world.reckless_lookahead();
    } else {
        premonitions = world.lookahead();
    }
    order_moves(&mut premonitions);
    let mut forecasts = Vec::new();
    for &premonition in &premonitions {
        if let Some(deadline) = deadline_maybe {
            if time::get_time() > deadline {
                return None;
            }
        }
        let travel_bank = memory_bank.clone();
        let thread_handle = thread::spawn(move || {
            α_β_negamax_search(
                premonition.tree, depth - 1,
                NEG_INFINITY, INFINITY,
                travel_bank
            )
        });
        let (_grandchild, mut value) = thread_handle.join().ok().unwrap();
        value = -value;
        forecasts.push((premonition, value));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    Some(forecasts)
}

pub fn kickoff(world: &WorldState, depth: u8,
               nihilistically: bool) -> Vec<(Commit, f32)> {
    potentially_timebound_kickoff(world, depth, nihilistically, None).unwrap()
}

pub fn iterative_deepening_kickoff(world: &WorldState, timeout: time::Duration,
                                   nihilistically: bool)
                                   -> (Vec<(Commit, f32)>, u8) {
    let deadline = time::get_time() + timeout;
    let mut depth = 1;
    let mut forecasts = potentially_timebound_kickoff(
        world, depth, nihilistically, None).unwrap();
    while let Some(prophecy) = potentially_timebound_kickoff(
            world, depth, nihilistically, Some(deadline)) {
        forecasts = prophecy;
        depth += 1;
    }
    (forecasts, depth)
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use time;
    use super::{kickoff, score};
    use space::Locale;
    use life::WorldState;
    use identity::Team;

    impl WorldState {
        fn no_castling_at_all(&mut self) {
            self.orange_east_service_eligibility = false;
            self.orange_west_service_eligibility = false;
            self.blue_east_service_eligibility = false;
            self.blue_west_service_eligibility = false;
        }
    }

    #[bench]
    fn benchmark_scoring(b: &mut Bencher) {
        b.iter(|| score(WorldState::new()));
    }

    #[bench]
    fn benchmark_kickoff_depth_1(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 1, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_arbys(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_carefully(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, false));
    }

    #[ignore]
    #[bench]
    fn benchmark_kickoff_depth_3(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 3, true));
    }

    #[test]
    #[ignore]  // more research is needed
    fn concerning_short_circuiting_upon_finding_critical_endangerment() {
        let ws = WorldState::reconstruct("7K/r7/1r6/8/8/8/8/7k b -".to_owned());
        let start = time::get_time();
        kickoff(&ws, 30, true);
        let duration = time::get_time() - start;
        assert!(duration.num_seconds() < 20);
    }

    #[test]
    #[allow(float_cmp)]
    fn concerning_fairness_of_the_initial_position() {
        // It's okay to assume this is really 0.0. Floats may be imprecise,
        // but they do have well-defined behavior.
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    fn concerning_servant_ascension_choices() {
        let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
        // looking ahead 3 moves allows the Leafline AI to catch the
        // split, whereby transforming into a pony (rather than
        // transitioning into a princess, as would usually be
        // expected) endangers both the blue princess and figurehead
        let (ref best_move, score) = kickoff(&ws, 3, true)[0];
        println!("{:?}", best_move);
        assert!(score > 0.0);
        assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
    }

    #[test]
    fn experimentally_about_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 });
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 });
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Blue has another servant sitting nowhere interesting
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 3, file: 6 });
        world.no_castling_at_all();

        let depth = 2;
        let advisory = kickoff(&world, depth, true);

        // taking the pony is the right thing to do
        assert_eq!(Locale { rank: 0, file: 0 }, advisory[0].0.patch.whither);

        // And, furthermore, the answer should be the same if we face the
        // same situation with the colors reversed
        //
        // XXX this would be tidier and less copy-pastey if I had more
        // general figurine-placing functions that were three rather than
        // two levels of abstraction above twiddling bits on an unsigned
        // int ... oh, well
        let mut negaworld = WorldState::new_except_empty();
        negaworld.to_move = Team::Blue;

        // scholar endangers pony
        negaworld.orange_ponies = negaworld.orange_ponies.alight(
            Locale { rank: 0, file: 0 });
        negaworld.blue_scholars = negaworld.blue_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 7, file: 1 });
        negaworld.blue_ponies = negaworld.blue_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Orange has another servant sitting nowhere interesting
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 3, file: 6 });
        negaworld.to_move = Team::Blue;

        negaworld.no_castling_at_all();

        let negadvisory = kickoff(&negaworld, depth, true);

        // taking the pony is still the right thing to do, even in the
        // negaworld
        assert_eq!(Locale { rank: 0, file: 0 },
                   negadvisory[0].0.patch.whither);
    }

}
<|endoftext|>


<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//!
use std::io::{self, Read, Write};
use std::fmt;

use rand::{self, Rng, ThreadRng};

#[derive(Default, Debug)]
pub struct ClientRequest {
    boundary: Option<String>,
    content_len: Option<u64>,
}

#[cfg(feature = "client")]
impl ::client::HttpRequest for ClientRequest {
    type Stream = HttpBuffer;
    type Error = io::Error;

    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool {
        self.boundary = Some(boundary.into());
        self.content_len = content_len;
        true
    }

    /// ##Panics
    /// If `apply_headers()` was not called.
    fn open_stream(self) -> Result<HttpBuffer, io::Error> {
        debug!("MockClientRequest::open_stream called! {:?}", self);
        let boundary = self.boundary.expect("HttpRequest::set_headers() was not called!");

        Ok(HttpBuffer::new_empty(boundary, self.content_len))
    }
}

pub struct HttpBuffer {
    pub buf: Vec<u8>,
    pub boundary: String,
    pub content_len: Option<u64>,
    rng: ThreadRng,
}

impl HttpBuffer {
    pub fn new_empty(boundary: String, content_len: Option<u64>) -> HttpBuffer {
        Self::with_buf(Vec::new(), boundary, content_len)
    }

    pub fn with_buf(buf: Vec<u8>, boundary: String, content_len: Option<u64>) -> Self {
        HttpBuffer {
            buf: buf,
            boundary: boundary,
            content_len: content_len,
            rng: rand::thread_rng()
        }
    }

    pub fn for_server(&self) -> ServerRequest {
        ServerRequest {
            data: &self.buf,
            boundary: &self.boundary,
            content_len: self.content_len,
            rng: rand::thread_rng(),
        }
    }
}

impl Write for HttpBuffer {
    fn write(&mut self, out: &[u8]) -> io::Result<usize> {
        if out.len() == 0 {
            return Err(io::ErrorKind::WriteZero.into());
        }

        // Simulate the randomness of a network connection by not always reading everything
        let len = self.rng.gen_range(1, out.len());

        self.buf.write(&out[..len])
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buf.flush()
    }
}

#[cfg(feature = "client")]
impl ::client::HttpStream for HttpBuffer {
    type Request = ClientRequest;
    type Response = HttpBuffer;
    type Error = io::Error;

    fn finish(self) -> Result<Self, io::Error> { Ok(self) }
}

impl fmt::Debug for HttpBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("multipart::mock::HttpBuffer")
            .field("buf", &self.buf)
            .field("boundary", &self.boundary)
            .field("content_len", &self.content_len)
            .finish()
    }
}

pub struct ServerRequest<'a> {
    pub data: &'a [u8],
    pub boundary: &'a str,
    pub content_len: Option<u64>,
    rng: ThreadRng,
}

impl<'a> Read for ServerRequest<'a> {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        // Simulate the randomness of a network connection by not always reading everything
        let len = self.rng.gen_range(1, out.len());
        self.data.read(&mut out[..len])
    }
}

#[cfg(feature = "server")]
impl<'a> ::server::HttpRequest for ServerRequest<'a> {
    type Body = Self;

    fn multipart_boundary(&self) -> Option<&str> { Some(&self.boundary) }

    fn body(self) -> Self::Body {
        self
    }
}<commit_msg>Fix faulty assumption of `Rng::gen_range`<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//!
use std::io::{self, Read, Write};
use std::fmt;

use rand::{self, Rng, ThreadRng};

#[derive(Default, Debug)]
pub struct ClientRequest {
    boundary: Option<String>,
    content_len: Option<u64>,
}

#[cfg(feature = "client")]
impl ::client::HttpRequest for ClientRequest {
    type Stream = HttpBuffer;
    type Error = io::Error;

    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool {
        self.boundary = Some(boundary.into());
        self.content_len = content_len;
        true
    }

    /// ##Panics
    /// If `apply_headers()` was not called.
    fn open_stream(self) -> Result<HttpBuffer, io::Error> {
        debug!("MockClientRequest::open_stream called! {:?}", self);
        let boundary = self.boundary.expect("HttpRequest::set_headers() was not called!");

        Ok(HttpBuffer::new_empty(boundary, self.content_len))
    }
}

pub struct HttpBuffer {
    pub buf: Vec<u8>,
    pub boundary: String,
    pub content_len: Option<u64>,
    rng: ThreadRng,
}

impl HttpBuffer {
    pub fn new_empty(boundary: String, content_len: Option<u64>) -> HttpBuffer {
        Self::with_buf(Vec::new(), boundary, content_len)
    }

    pub fn with_buf(buf: Vec<u8>, boundary: String, content_len: Option<u64>) -> Self {
        HttpBuffer {
            buf: buf,
            boundary: boundary,
            content_len: content_len,
            rng: rand::thread_rng()
        }
    }

    pub fn for_server(&self) -> ServerRequest {
        ServerRequest {
            data: &self.buf,
            boundary: &self.boundary,
            content_len: self.content_len,
            rng: rand::thread_rng(),
        }
    }
}

impl Write for HttpBuffer {
    fn write(&mut self, out: &[u8]) -> io::Result<usize> {
        if out.len() == 0 {
            return Err(io::ErrorKind::WriteZero.into());
        }

        // Simulate the randomness of a network connection by not always reading everything
        let len = self.rng.gen_range(1, out.len() + 1);

        self.buf.write(&out[..len])
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buf.flush()
    }
}

#[cfg(feature = "client")]
impl ::client::HttpStream for HttpBuffer {
    type Request = ClientRequest;
    type Response = HttpBuffer;
    type Error = io::Error;

    fn finish(self) -> Result<Self, io::Error> { Ok(self) }
}

impl fmt::Debug for HttpBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("multipart::mock::HttpBuffer")
            .field("buf", &self.buf)
            .field("boundary", &self.boundary)
            .field("content_len", &self.content_len)
            .finish()
    }
}

pub struct ServerRequest<'a> {
    pub data: &'a [u8],
    pub boundary: &'a str,
    pub content_len: Option<u64>,
    rng: ThreadRng,
}

impl<'a> Read for ServerRequest<'a> {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        if out.len() == 0 {
            return Err(io::ErrorKind::WriteZero.into());
        }

        // Simulate the randomness of a network connection by not always reading everything
        let len = self.rng.gen_range(1, out.len() + 1);
        self.data.read(&mut out[..len])
    }
}

#[cfg(feature = "server")]
impl<'a> ::server::HttpRequest for ServerRequest<'a> {
    type Body = Self;

    fn multipart_boundary(&self) -> Option<&str> { Some(&self.boundary) }

    fn body(self) -> Self::Body {
        self
    }
}<|endoftext|>


<commit_before>
use error::{NcclError, ErrorKind};
use value::Value;
use ::TryInto;

use std::ops::{Index, IndexMut};
use std::error::Error;

/// Struct that contains configuration information.
///
/// Examples:
///
/// ```
/// let p = nccl::parse_file("examples/config.nccl").unwrap();
/// let ports = p["server"]["port"].keys_as::<i64>().unwrap();
///
/// println!("Operating on ports:");
/// for port in ports.iter() {
///     println!("  {}", port);
/// }
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    key: Value,
    value: Vec<Pair>
}

impl Pair {
    /// Creates a new Pair.
    pub fn new<T: Into<Value>>(key: T) -> Self {
        Pair {
            key: key.into(),
            value: vec![]
        }
    }

    /// Adds a value to a Pair.
    ///
    /// Examples:
    ///
    /// ```
    /// let mut p = nccl::Pair::new("hello");
    /// p.add(true);
    /// p.add("world");
    /// ```
    pub fn add<T: Into<Value>>(&mut self, value: T) {
        self.value.push(Pair::new(value.into()));
    }

    /// Recursively adds a slice to a Pair.
    pub fn add_slice(&mut self, path: &[Value]) {
        let s = self.traverse_path(&path[0..path.len() - 1]);
        if !s.has_key(&path[path.len() - 1]) {
            s.add(&path[path.len() - 1]);
        }
    }

    /// Adds a Pair to a Pair.
    pub fn add_pair(&mut self, pair: Pair) {
        if !self.has_key(&pair.key) {
            self.value.push(pair);
        } else {
            self[&pair.key].value = pair.value;
        }
    }

    /// Test if a pair has a key.
    ///
    /// Examples:
    ///
    /// ```
    /// use nccl::NcclError;
    /// let mut p = nccl::parse_file("examples/config.nccl").unwrap();
    /// assert!(p.has_key("server"));
    /// assert!(p["server"]["port"].has_key(80));
    /// ```
    pub fn has_key<T>(&self, key: T) -> bool where Value: From<T> {
        let k = key.into();
        for item in &self.value {
            if item.key == k {
                return true;
            }
        }

        false
    }

    /// Test if a pair has a path of values. Use `vec_into!` to make
    /// this method easier to use.
    ///
    /// Examples:
    ///
    /// ```
    /// # #[macro_use] extern crate nccl; fn main() {
    /// let mut p = nccl::parse_file("examples/config.nccl").unwrap();
    /// assert!(p.has_path(vec_into!["server", "port", 80]));
    /// # }
    /// ```
    pub fn has_path(&self, path: Vec<Value>) -> bool {
        if path.len() == 0 {
            true
        } else {
            if self.has_key(path[0].clone()) {
                self[path[0].clone()].has_path(path[1..path.len()].to_vec())
            } else {
                false
            }
        }
    }

    /// Traverses a Pair using a slice, adding the item if it does not exist.
    pub fn traverse_path(&mut self, path: &[Value]) -> &mut Pair {
        if path.is_empty() {
            self
        } else {
            if !self.has_key(&path[0]) {
                self.add(&path[0]);
            }
            self.get(&path[0]).unwrap().traverse_path(&path[1..path.len()])
        }
    }

    /// Gets a child Pair from a Pair. Used by Pair's implementation of Index.
    ///
    /// ```
    /// let mut p = nccl::Pair::new("top_level");
    /// p.add("hello!");
    /// p.get("hello!").unwrap();
    /// ```
    pub fn get<T>(&mut self, value: T) -> Result<&mut Pair, Box<Error>> where Value: From<T> {
        let v = value.into();

        if self.value.is_empty() {
            return Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, &format!("Pair does not have key: {}", v), 0)));
        } else {
            for item in &mut self.value {
                if item.key == v {
                    return Ok(item);
                }
            }
        }

        Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, &format!("Could not find key: {}", v), 0)))
    }

    /// Gets a mutable child Pair from a Pair. Used by Pair's implementation of
    /// IndexMut.
    ///
    /// ```
    /// let mut p = nccl::Pair::new("top_level");
    /// p.add(32);
    /// p.get(32).unwrap();
    /// ```
    pub fn get_ref<T>(&self, value: T) -> Result<&Pair, Box<Error>> where Value: From<T> {
        let v = value.into();

        if self.value.is_empty() {
            return Ok(self);
        } else {
            for item in &self.value {
                if item.key == v {
                    return Ok(item);
                }
            }
        }

        Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, "Cound not find key", 0)))
    }

    fn value(&self) -> Option<Value>  {
        if self.value.len() == 1 {
            Some(self.value[0].key.clone())
        } else {
            None
        }
    }

    /// Gets the value of a key as a specified type, if there is only one.
    ///
    /// Examples:
    ///
    /// ```
    /// let p = nccl::parse_file("examples/long.nccl").unwrap();
    /// assert!(!p["bool too"].value_as::<bool>().unwrap());
    /// ```
    pub fn value_as<T>(&self) -> Result<T, Box<Error>> where Value: TryInto<T> {
        match self.value() {
            Some(v) => match v.try_into() {
                Ok(t) => Ok(t),
                Err(_) => return Err(Box::new(NcclError::new(ErrorKind::IntoError, "Could not convert to T", 0)))
            },
            None => Err(Box::new(NcclError::new(ErrorKind::MultipleValues, "Could not convert value: multiple values. Use keys() or keys_as()", 0)))
        }
    }

    fn keys(&self) -> Vec<Value> {
        self.value.clone().into_iter().map(|x| x.key).collect()
    }

    /// Gets keys of a value as a vector of T.
    ///
    /// Examples:
    ///
    /// ```
    /// let config = nccl::parse_file("examples/config.nccl").unwrap();
    /// let ports = config["server"]["port"].keys_as::<i64>().unwrap();
    /// assert_eq!(ports, vec![80, 443]);
    /// ```
    pub fn keys_as<T>(&self) -> Result<Vec<T>, Box<Error>> where Value: TryInto<T> {
        let mut v: Vec<T> = vec![];
        for key in self.keys() {
            match key.try_into() {
                Ok(k) => v.push(k),
                Err(_) => return Err(Box::new(NcclError::new(ErrorKind::IntoError, "Could not convert to T", 0)))
            }
        }
        Ok(v)
    }

    /// Pretty-prints a Pair.
    ///
    /// Examples:
    ///
    /// ```
    /// let config = nccl::parse_file("examples/config.nccl").unwrap();
    /// config.pretty_print();
    ///
    /// // String("__top_level__")
    /// //     String("server")
    /// //         String("domain")
    /// //             String("example.com")
    /// //             String("www.example.com")
    /// //         String("port")
    /// //             Integer(80)
    /// //             Integer(443)
    /// //         String("root")
    /// //             String("/var/www/html")
    /// ```
    ///
    pub fn pretty_print(&self) {
        self.pp_rec(0);
    }

    fn pp_rec(&self, indent: u32) {
        for _ in 0..indent {
            print!("    ");
        }
        println!("{}", self.key);
        for value in &self.value {
            value.pp_rec(indent + 1);
        }
    }
}

impl<T> Index<T> for Pair where Value: From<T> {
    type Output = Pair;
    fn index(&self, i: T) -> &Pair {
        self.get_ref(i).unwrap()
    }
}

impl<T> IndexMut<T> for Pair where Value: From<T> {
    fn index_mut(&mut self, i: T) -> &mut Pair {
        self.get(i).unwrap()
    }
}

<commit_msg>update pretty_print<commit_after>
use error::{NcclError, ErrorKind};
use value::Value;
use ::TryInto;

use std::ops::{Index, IndexMut};
use std::error::Error;

/// Struct that contains configuration information.
///
/// Examples:
///
/// ```
/// let p = nccl::parse_file("examples/config.nccl").unwrap();
/// let ports = p["server"]["port"].keys_as::<i64>().unwrap();
///
/// println!("Operating on ports:");
/// for port in ports.iter() {
///     println!("  {}", port);
/// }
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct Pair {
    key: Value,
    value: Vec<Pair>
}

impl Pair {
    /// Creates a new Pair.
    pub fn new<T: Into<Value>>(key: T) -> Self {
        Pair {
            key: key.into(),
            value: vec![]
        }
    }

    /// Adds a value to a Pair.
    ///
    /// Examples:
    ///
    /// ```
    /// let mut p = nccl::Pair::new("hello");
    /// p.add(true);
    /// p.add("world");
    /// ```
    pub fn add<T: Into<Value>>(&mut self, value: T) {
        self.value.push(Pair::new(value.into()));
    }

    /// Recursively adds a slice to a Pair.
    pub fn add_slice(&mut self, path: &[Value]) {
        let s = self.traverse_path(&path[0..path.len() - 1]);
        if !s.has_key(&path[path.len() - 1]) {
            s.add(&path[path.len() - 1]);
        }
    }

    /// Adds a Pair to a Pair.
    pub fn add_pair(&mut self, pair: Pair) {
        if !self.has_key(&pair.key) {
            self.value.push(pair);
        } else {
            self[&pair.key].value = pair.value;
        }
    }

    /// Test if a pair has a key.
    ///
    /// Examples:
    ///
    /// ```
    /// use nccl::NcclError;
    /// let mut p = nccl::parse_file("examples/config.nccl").unwrap();
    /// assert!(p.has_key("server"));
    /// assert!(p["server"]["port"].has_key(80));
    /// ```
    pub fn has_key<T>(&self, key: T) -> bool where Value: From<T> {
        let k = key.into();
        for item in &self.value {
            if item.key == k {
                return true;
            }
        }

        false
    }

    /// Test if a pair has a path of values. Use `vec_into!` to make
    /// this method easier to use.
    ///
    /// Examples:
    ///
    /// ```
    /// # #[macro_use] extern crate nccl; fn main() {
    /// let mut p = nccl::parse_file("examples/config.nccl").unwrap();
    /// assert!(p.has_path(vec_into!["server", "port", 80]));
    /// # }
    /// ```
    pub fn has_path(&self, path: Vec<Value>) -> bool {
        if path.len() == 0 {
            true
        } else {
            if self.has_key(path[0].clone()) {
                self[path[0].clone()].has_path(path[1..path.len()].to_vec())
            } else {
                false
            }
        }
    }

    /// Traverses a Pair using a slice, adding the item if it does not exist.
    pub fn traverse_path(&mut self, path: &[Value]) -> &mut Pair {
        if path.is_empty() {
            self
        } else {
            if !self.has_key(&path[0]) {
                self.add(&path[0]);
            }
            self.get(&path[0]).unwrap().traverse_path(&path[1..path.len()])
        }
    }

    /// Gets a child Pair from a Pair. Used by Pair's implementation of Index.
    ///
    /// ```
    /// let mut p = nccl::Pair::new("top_level");
    /// p.add("hello!");
    /// p.get("hello!").unwrap();
    /// ```
    pub fn get<T>(&mut self, value: T) -> Result<&mut Pair, Box<Error>> where Value: From<T> {
        let v = value.into();

        if self.value.is_empty() {
            return Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, &format!("Pair does not have key: {}", v), 0)));
        } else {
            for item in &mut self.value {
                if item.key == v {
                    return Ok(item);
                }
            }
        }

        Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, &format!("Could not find key: {}", v), 0)))
    }

    /// Gets a mutable child Pair from a Pair. Used by Pair's implementation of
    /// IndexMut.
    ///
    /// ```
    /// let mut p = nccl::Pair::new("top_level");
    /// p.add(32);
    /// p.get(32).unwrap();
    /// ```
    pub fn get_ref<T>(&self, value: T) -> Result<&Pair, Box<Error>> where Value: From<T> {
        let v = value.into();

        if self.value.is_empty() {
            return Ok(self);
        } else {
            for item in &self.value {
                if item.key == v {
                    return Ok(item);
                }
            }
        }

        Err(Box::new(NcclError::new(ErrorKind::KeyNotFound, "Cound not find key", 0)))
    }

    fn value(&self) -> Option<Value>  {
        if self.value.len() == 1 {
            Some(self.value[0].key.clone())
        } else {
            None
        }
    }

    /// Gets the value of a key as a specified type, if there is only one.
    ///
    /// Examples:
    ///
    /// ```
    /// let p = nccl::parse_file("examples/long.nccl").unwrap();
    /// assert!(!p["bool too"].value_as::<bool>().unwrap());
    /// ```
    pub fn value_as<T>(&self) -> Result<T, Box<Error>> where Value: TryInto<T> {
        match self.value() {
            Some(v) => match v.try_into() {
                Ok(t) => Ok(t),
                Err(_) => return Err(Box::new(NcclError::new(ErrorKind::IntoError, "Could not convert to T", 0)))
            },
            None => Err(Box::new(NcclError::new(ErrorKind::MultipleValues, "Could not convert value: multiple values. Use keys() or keys_as()", 0)))
        }
    }

    fn keys(&self) -> Vec<Value> {
        self.value.clone().into_iter().map(|x| x.key).collect()
    }

    /// Gets keys of a value as a vector of T.
    ///
    /// Examples:
    ///
    /// ```
    /// let config = nccl::parse_file("examples/config.nccl").unwrap();
    /// let ports = config["server"]["port"].keys_as::<i64>().unwrap();
    /// assert_eq!(ports, vec![80, 443]);
    /// ```
    pub fn keys_as<T>(&self) -> Result<Vec<T>, Box<Error>> where Value: TryInto<T> {
        let mut v: Vec<T> = vec![];
        for key in self.keys() {
            match key.try_into() {
                Ok(k) => v.push(k),
                Err(_) => return Err(Box::new(NcclError::new(ErrorKind::IntoError, "Could not convert to T", 0)))
            }
        }
        Ok(v)
    }

    /// Pretty-prints a Pair.
    ///
    /// Examples:
    ///
    /// ```
    /// let config = nccl::parse_file("examples/config.nccl").unwrap();
    /// config.pretty_print();
    ///
    /// // String("__top_level__")
    /// //     String("server")
    /// //         String("domain")
    /// //             String("example.com")
    /// //             String("www.example.com")
    /// //         String("port")
    /// //             Integer(80)
    /// //             Integer(443)
    /// //         String("root")
    /// //             String("/var/www/html")
    /// ```
    ///
    pub fn pretty_print(&self) {
        self.pp_rec(0);
    }

    fn pp_rec(&self, indent: u32) {
        for _ in 0..indent {
            print!("    ");
        }
        println!("{:?}", self.key);
        for value in &self.value {
            value.pp_rec(indent + 1);
        }
    }
}

impl<T> Index<T> for Pair where Value: From<T> {
    type Output = Pair;
    fn index(&self, i: T) -> &Pair {
        self.get_ref(i).unwrap()
    }
}

impl<T> IndexMut<T> for Pair where Value: From<T> {
    fn index_mut(&mut self, i: T) -> &mut Pair {
        self.get(i).unwrap()
    }
}

<|endoftext|>


<commit_before>//! A simple connection pool

use sync::MutexArc;

use {PostgresNotifications,
     PostgresCancelData,
     PostgresConnection,
     NormalPostgresStatement,
     PostgresTransaction,
     SslMode};
use error::{PostgresConnectError, PostgresError};
use types::ToSql;

struct InnerConnectionPool {
    url: ~str,
    ssl: SslMode,
    pool: ~[PostgresConnection],
}

impl InnerConnectionPool {
    fn new_connection(&mut self) -> Option<PostgresConnectError> {
        match PostgresConnection::try_connect(self.url, &self.ssl) {
            Ok(conn) => {
                self.pool.push(conn);
                None
            }
            Err(err) => Some(err)
        }
    }
}

/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
#[deriving(Clone)]
pub struct PostgresConnectionPool {
    priv pool: MutexArc<InnerConnectionPool>
}

impl PostgresConnectionPool {
    /// Attempts to create a new pool with the specified number of connections.
    ///
    /// Returns an error if the specified number of connections cannot be
    /// created.
    pub fn try_new(url: &str, ssl: SslMode, pool_size: uint)
            -> Result<PostgresConnectionPool, PostgresConnectError> {
        let mut pool = InnerConnectionPool {
            url: url.to_owned(),
            ssl: ssl,
            pool: ~[],
        };

        for _ in range(0, pool_size) {
            match pool.new_connection() {
                None => (),
                Some(err) => return Err(err)
            }
        }

        Ok(PostgresConnectionPool {
            pool: MutexArc::new(pool)
        })
    }

    /// A convenience function wrapping `try_new`.
    ///
    /// # Failure
    ///
    /// Fails if the pool cannot be created.
    pub fn new(url: &str, ssl: SslMode, pool_size: uint)
            -> PostgresConnectionPool {
        match PostgresConnectionPool::try_new(url, ssl, pool_size) {
            Ok(pool) => pool,
            Err(err) => fail!("Unable to initialize pool: {}", err.to_str())
        }
    }

    /// Retrieves a connection from the pool.
    ///
    /// If all connections are in use, blocks until one becomes available.
    pub fn get_connection(&self) -> PooledPostgresConnection {
        let conn = unsafe {
            self.pool.unsafe_access_cond(|pool, cvar| {
                while pool.pool.is_empty() {
                    cvar.wait();
                }

                pool.pool.pop().unwrap()
            })
        };

        PooledPostgresConnection {
            pool: self.clone(),
            conn: Some(conn)
        }
    }
}

/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
pub struct PooledPostgresConnection {
    priv pool: PostgresConnectionPool,
    // TODO remove the Option wrapper when drop takes self by value
    priv conn: Option<PostgresConnection>
}

impl Drop for PooledPostgresConnection {
    fn drop(&mut self) {
        unsafe {
            self.pool.pool.unsafe_access(|pool| {
                pool.pool.push(self.conn.take_unwrap());
            })
        }
    }
}

impl PooledPostgresConnection {
    /// Like `PostgresConnection::try_prepare`.
    pub fn try_prepare<'a>(&'a self, query: &str)
            -> Result<NormalPostgresStatement<'a>, PostgresError> {
        self.conn.get_ref().try_prepare(query)
    }

    /// Like `PostgresConnection::prepare`.
    pub fn prepare<'a>(&'a self, query: &str) -> NormalPostgresStatement<'a> {
        self.conn.get_ref().prepare(query)
    }

    /// Like `PostgresConnection::try_execute`.
    pub fn try_execute(&self, query: &str, params: &[&ToSql])
            -> Result<uint, PostgresError> {
        self.conn.get_ref().try_execute(query, params)
    }

    /// Like `PostgresConnection::execute`.
    pub fn execute(&self, query: &str, params: &[&ToSql]) -> uint {
        self.conn.get_ref().execute(query, params)
    }

    /// Like `PostgresConnection::try_transaction`.
    pub fn try_transaction<'a>(&'a self)
            -> Result<PostgresTransaction<'a>, PostgresError> {
        self.conn.get_ref().try_transaction()
    }

    /// Like `PostgresConnection::transaction`.
    pub fn transaction<'a>(&'a self) -> PostgresTransaction<'a> {
        self.conn.get_ref().transaction()
    }

    /// Like `PostgresConnection::notifications`.
    pub fn notifications<'a>(&'a self) -> PostgresNotifications<'a> {
        self.conn.get_ref().notifications()
    }

    /// Like `PostgresConnection::cancel_data`.
    pub fn cancel_data(&self) -> PostgresCancelData {
        self.conn.get_ref().cancel_data()
    }

    /// Like `PostgresConnection::is_desynchronized`.
    pub fn is_desynchronized(&self) -> bool {
        self.conn.get_ref().is_desynchronized()
    }
}
<commit_msg>Update for closure changes<commit_after>//! A simple connection pool

use std::cell::RefCell;
use sync::MutexArc;

use {PostgresNotifications,
     PostgresCancelData,
     PostgresConnection,
     NormalPostgresStatement,
     PostgresTransaction,
     SslMode};
use error::{PostgresConnectError, PostgresError};
use types::ToSql;

struct InnerConnectionPool {
    url: ~str,
    ssl: SslMode,
    pool: ~[PostgresConnection],
}

impl InnerConnectionPool {
    fn new_connection(&mut self) -> Option<PostgresConnectError> {
        match PostgresConnection::try_connect(self.url, &self.ssl) {
            Ok(conn) => {
                self.pool.push(conn);
                None
            }
            Err(err) => Some(err)
        }
    }
}

/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
#[deriving(Clone)]
pub struct PostgresConnectionPool {
    priv pool: MutexArc<InnerConnectionPool>
}

impl PostgresConnectionPool {
    /// Attempts to create a new pool with the specified number of connections.
    ///
    /// Returns an error if the specified number of connections cannot be
    /// created.
    pub fn try_new(url: &str, ssl: SslMode, pool_size: uint)
            -> Result<PostgresConnectionPool, PostgresConnectError> {
        let mut pool = InnerConnectionPool {
            url: url.to_owned(),
            ssl: ssl,
            pool: ~[],
        };

        for _ in range(0, pool_size) {
            match pool.new_connection() {
                None => (),
                Some(err) => return Err(err)
            }
        }

        Ok(PostgresConnectionPool {
            pool: MutexArc::new(pool)
        })
    }

    /// A convenience function wrapping `try_new`.
    ///
    /// # Failure
    ///
    /// Fails if the pool cannot be created.
    pub fn new(url: &str, ssl: SslMode, pool_size: uint)
            -> PostgresConnectionPool {
        match PostgresConnectionPool::try_new(url, ssl, pool_size) {
            Ok(pool) => pool,
            Err(err) => fail!("Unable to initialize pool: {}", err.to_str())
        }
    }

    /// Retrieves a connection from the pool.
    ///
    /// If all connections are in use, blocks until one becomes available.
    pub fn get_connection(&self) -> PooledPostgresConnection {
        let conn = unsafe {
            self.pool.unsafe_access_cond(|pool, cvar| {
                while pool.pool.is_empty() {
                    cvar.wait();
                }

                pool.pool.pop().unwrap()
            })
        };

        PooledPostgresConnection {
            pool: self.clone(),
            conn: Some(conn)
        }
    }
}

/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
pub struct PooledPostgresConnection {
    priv pool: PostgresConnectionPool,
    // TODO remove the Option wrapper when drop takes self by value
    priv conn: Option<PostgresConnection>
}

impl Drop for PooledPostgresConnection {
    fn drop(&mut self) {
        unsafe {
            let conn = RefCell::new(self.conn.take());
            self.pool.pool.unsafe_access(|pool| {
                pool.pool.push(conn.with_mut(|r| r.take_unwrap()));
            })
        }
    }
}

impl PooledPostgresConnection {
    /// Like `PostgresConnection::try_prepare`.
    pub fn try_prepare<'a>(&'a self, query: &str)
            -> Result<NormalPostgresStatement<'a>, PostgresError> {
        self.conn.get_ref().try_prepare(query)
    }

    /// Like `PostgresConnection::prepare`.
    pub fn prepare<'a>(&'a self, query: &str) -> NormalPostgresStatement<'a> {
        self.conn.get_ref().prepare(query)
    }

    /// Like `PostgresConnection::try_execute`.
    pub fn try_execute(&self, query: &str, params: &[&ToSql])
            -> Result<uint, PostgresError> {
        self.conn.get_ref().try_execute(query, params)
    }

    /// Like `PostgresConnection::execute`.
    pub fn execute(&self, query: &str, params: &[&ToSql]) -> uint {
        self.conn.get_ref().execute(query, params)
    }

    /// Like `PostgresConnection::try_transaction`.
    pub fn try_transaction<'a>(&'a self)
            -> Result<PostgresTransaction<'a>, PostgresError> {
        self.conn.get_ref().try_transaction()
    }

    /// Like `PostgresConnection::transaction`.
    pub fn transaction<'a>(&'a self) -> PostgresTransaction<'a> {
        self.conn.get_ref().transaction()
    }

    /// Like `PostgresConnection::notifications`.
    pub fn notifications<'a>(&'a self) -> PostgresNotifications<'a> {
        self.conn.get_ref().notifications()
    }

    /// Like `PostgresConnection::cancel_data`.
    pub fn cancel_data(&self) -> PostgresCancelData {
        self.conn.get_ref().cancel_data()
    }

    /// Like `PostgresConnection::is_desynchronized`.
    pub fn is_desynchronized(&self) -> bool {
        self.conn.get_ref().is_desynchronized()
    }
}
<|endoftext|>


<commit_before>use super::{do_the_thing, parse_expressions};

use ast;
use env::Environment;
use error::{handle_error, REPLError, ParseError};
use parser;

use lalrpop_util::ParseError as PopParseError;

use rustyline;
use rustyline::error::ReadlineError;
use rustyline::Editor;
use rustyline::completion::{extract_word, Completer};

use std::collections::BTreeSet;
use std::process;

pub fn start() {
    let mut rl = Editor::<ParseCompleter>::new();

    rl.set_completer(Some(ParseCompleter::default()));

    if let Err(_) = rl.load_history("history.txt") {
        println!("No previous history.");
    }

    let mut bindings = Environment::new();

    loop {
        let readline = rl.readline("input> ");

        match readline {
            Ok(line) => {
                match parse_expressions(line.as_str()) {
                    Ok(exprs) => {
                        rl.add_history_entry(&line);
                        if let Err(err) = do_the_thing(exprs, &mut bindings) {
                            handle_error("<command-line>", Box::new(err));
                        }
                    }

                    Err(ParseError::UnrecognizedToken { token: None, expected: _ }) => {
                        let mut partial_input = line.clone();
                        match multiline_loop(&mut rl, &mut partial_input) {
                            Ok(exprs) => {
                                if let Err(err) = do_the_thing(exprs, &mut bindings) {
                                    handle_error("<command-line>", Box::new(err));
                                }
                                // Restore the default completer.
                                rl.set_completer(Some(ParseCompleter::default()));
                            }
                            Err(REPLError::Readline(ReadlineError::Eof)) => {}
                            Err(err) => handle_error("<command-line>", Box::new(err)),
                        }
                    }

                    Err(thing) => {
                        handle_error("<command-line>", Box::new(thing));
                        process::exit(1);
                    }
                }

            }
            Err(ReadlineError::Interrupted) => continue,
            Err(ReadlineError::Eof) => break,
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
        rl.save_history("history.txt").unwrap();
    }
}

fn multiline_loop<'a>(mut rl: &mut Editor<ParseCompleter>,
                      mut partial_input: &'a mut String)
                      -> Result<ast::Exprs, REPLError<'a>> {
    loop {
        *partial_input += "\n";
        rl.set_completer(Some(ParseCompleter::from_context(partial_input.clone())));

        match rl.readline("  ...> ") {
            Ok(line) => {
                *partial_input += line.as_str();

                match parse_expressions(partial_input) {
                    Ok(expr) => return Ok(expr),
                    Err(ParseError::UnrecognizedToken { token: None, expected: _ }) => (),
                    Err(err) => {
                        handle_error("<command-line>", Box::new(err));
                        process::exit(1);
                        // See: https://github.com/rust-lang/rust/issues/40307
                        //return Err(REPLError::Parse(err));
                    }
                }

            }

            Err(ReadlineError::Interrupted) => continue,
            Err(ReadlineError::Eof) => return Err(REPLError::Readline(ReadlineError::Eof)),
            Err(err) => return Err(REPLError::Readline(err)),
        }
    }
}

//================
//== Completion ==
//================

const BREAKS: [char; 12] = [' ', '\t', '\n', '(', ')', ',', '+', '-', '*', '/', '<', '>'];

struct ParseCompleter {
    context: String,
    breaks: BTreeSet<char>,
}

impl ParseCompleter {
    pub fn new() -> Self {
        ParseCompleter {
            context: "".to_string(),
            breaks: BREAKS.iter().cloned().collect(),
        }
    }

    pub fn from_context(context: String) -> Self {
        ParseCompleter {
            context: context,
            breaks: BREAKS.iter().cloned().collect(),
        }
    }
}

impl Default for ParseCompleter {
    fn default() -> Self {
        ParseCompleter::new()
    }
}

impl Completer for ParseCompleter {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {

        fn begins_with(input: &String, prefix: String) -> bool {
            let input_len = input.len();
            let prefix_len = prefix.len();

            if input_len < prefix_len {
                false
            } else {
                input[0..prefix.len()] == prefix
            }
        }

        let (start, word) = extract_word(line, pos, &self.breaks);

        let partial_input = self.context.clone() + &line[0..start];

        match parser::parse_Expressions(partial_input.as_str()) {
            Ok(_) => Ok((0, vec![])),
            Err(PopParseError::UnrecognizedToken {
                    token: None,
                    expected: candidates,
                }) => {
                let candidates = candidates
                    .into_iter()
                    .filter_map(|mut candidate| {
                        if candidate.chars().nth(0) == Some('\"') {
                            // Remove quotes
                            candidate.remove(0);
                            candidate.pop();
                            if begins_with(&candidate, String::from(word)) {
                                Some(candidate)
                            } else {
                                None
                            }
                        } else {
                            // Cannot extrapolate candidates from Regex
                            None
                        }
                    })
                    .collect();
                Ok((start, candidates))
            }
            _ => Ok((0, vec![])),

        }
    }
}
<commit_msg>Better error flow in REPL<commit_after>use super::{do_the_thing, parse_expressions};

use ast;
use env::Environment;
use error::{handle_error, REPLError, ParseError};
use parser;

use lalrpop_util::ParseError as PopParseError;

use rustyline;
use rustyline::error::ReadlineError;
use rustyline::Editor;
use rustyline::completion::{extract_word, Completer};

use std::collections::BTreeSet;

pub fn start() {
    let mut rl = Editor::<ParseCompleter>::new();

    rl.set_completer(Some(ParseCompleter::default()));

    if let Err(_) = rl.load_history("history.txt") {
        println!("No previous history.");
    }

    let mut bindings = Environment::new();

    loop {
        let readline = rl.readline("input> ");

        match readline {
            Ok(line) => {
                match parse_expressions(line.as_str()) {
                    Ok(exprs) => {
                        rl.add_history_entry(&line);
                        if let Err(err) = do_the_thing(exprs, &mut bindings) {
                            handle_error("<command-line>", Box::new(err));
                        }
                    }

                    Err(ParseError::UnrecognizedToken { token: None, expected: _ }) => {
                        let mut partial_input = line.clone();
                        match multiline_loop(&mut rl, &mut partial_input) {
                            Ok(exprs) => {
                                if let Err(err) = do_the_thing(exprs, &mut bindings) {
                                    handle_error("<command-line>", Box::new(err));
                                }
                                // Restore the default completer.
                                rl.set_completer(Some(ParseCompleter::default()));
                            }
                            Err(REPLError::Readline(ReadlineError::Eof)) => {}
                            Err(err) => handle_error("<command-line>", Box::new(err)),
                        }
                    }

                    Err(thing) => {
                        handle_error("<command-line>", Box::new(thing));
                    }
                }

            }
            Err(ReadlineError::Interrupted) => continue,
            Err(ReadlineError::Eof) => break,
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
        rl.save_history("history.txt").unwrap();
    }
}

fn multiline_loop<'a>(mut rl: &mut Editor<ParseCompleter>,
                      mut partial_input: &'a mut String)
                      -> Result<ast::Exprs, REPLError<'a>> {
    loop {
        *partial_input += "\n";
        rl.set_completer(Some(ParseCompleter::from_context(partial_input.clone())));

        match rl.readline("  ...> ") {
            Ok(line) => {
                let previous_attempt_len = partial_input.len();
                *partial_input += line.as_str();

                match parse_expressions(partial_input) {
                    Ok(expr) => return Ok(expr),
                    Err(ParseError::UnrecognizedToken { token: None, expected: _ }) => continue,
                    Err(err) => {
                        // See: https://github.com/rust-lang/rust/issues/40307
                        //return Err(REPLError::Parse(err));

                        handle_error("<command-line>", Box::new(err));
                    }
                }

                // Restore previous attempt to prevent further errors.
                // Cannot do it inside the match above because partial_input
                // would be still borrowed.
                partial_input.truncate(previous_attempt_len);
            }

            Err(ReadlineError::Interrupted) => continue,
            Err(ReadlineError::Eof) => return Err(REPLError::Readline(ReadlineError::Eof)),
            Err(err) => return Err(REPLError::Readline(err)),
        }
    }
}

//================
//== Completion ==
//================

const BREAKS: [char; 12] = [' ', '\t', '\n', '(', ')', ',', '+', '-', '*', '/', '<', '>'];

struct ParseCompleter {
    context: String,
    breaks: BTreeSet<char>,
}

impl ParseCompleter {
    pub fn new() -> Self {
        ParseCompleter {
            context: "".to_string(),
            breaks: BREAKS.iter().cloned().collect(),
        }
    }

    pub fn from_context(context: String) -> Self {
        ParseCompleter {
            context: context,
            breaks: BREAKS.iter().cloned().collect(),
        }
    }
}

impl Default for ParseCompleter {
    fn default() -> Self {
        ParseCompleter::new()
    }
}

impl Completer for ParseCompleter {
    fn complete(&self, line: &str, pos: usize) -> rustyline::Result<(usize, Vec<String>)> {

        fn begins_with(input: &String, prefix: String) -> bool {
            let input_len = input.len();
            let prefix_len = prefix.len();

            if input_len < prefix_len {
                false
            } else {
                input[0..prefix.len()] == prefix
            }
        }

        let (start, word) = extract_word(line, pos, &self.breaks);

        let partial_input = self.context.clone() + &line[0..start];

        match parser::parse_Expressions(partial_input.as_str()) {
            Ok(_) => Ok((0, vec![])),
            Err(PopParseError::UnrecognizedToken {
                    token: None,
                    expected: candidates,
                }) => {
                let candidates = candidates
                    .into_iter()
                    .filter_map(|mut candidate| {
                        if candidate.chars().nth(0) == Some('\"') {
                            // Remove quotes
                            candidate.remove(0);
                            candidate.pop();
                            if begins_with(&candidate, String::from(word)) {
                                Some(candidate)
                            } else {
                                None
                            }
                        } else {
                            // Cannot extrapolate candidates from Regex
                            None
                        }
                    })
                    .collect();
                Ok((start, candidates))
            }
            _ => Ok((0, vec![])),

        }
    }
}
<|endoftext|>


<commit_before>//! Useful stuff for finding points in a ring

use std::collections::HashSet;

use point::Point;
use travel::{Direction, travel};

/// Find points at the same height in a ring of a provided radius
///
/// # Example
///
/// ```
/// use hex_math::{Point, ring};
/// use std::collections::HashSet;
///
/// let point: Point = Point::new(1, 2, 5);
/// let set: HashSet<Point> = ring(&point, 2);
///
/// assert!(set.contains(&Point::new(1, 0, 5)));
/// assert!(set.contains(&Point::new(2, 0, 5)));
/// assert!(set.contains(&Point::new(3, 0, 5)));
/// assert!(set.contains(&Point::new(3, 1, 5)));
/// assert!(set.contains(&Point::new(3, 2, 5)));
/// assert!(set.contains(&Point::new(2, 3, 5)));
/// assert!(set.contains(&Point::new(1, 4, 5)));
/// assert!(set.contains(&Point::new(0, 4, 5)));
/// assert!(set.contains(&Point::new(-1, 4, 5)));
/// assert!(set.contains(&Point::new(-1, 3, 5)));
/// assert!(set.contains(&Point::new(-1, 2, 5)));
/// assert!(set.contains(&Point::new(0, 1, 5)));
///
/// assert!(set.contains(&Point::new(1, 1, 6)));
/// assert!(set.contains(&Point::new(2, 1, 6)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(1, 3, 6)));
/// assert!(set.contains(&Point::new(0, 3, 6)));
/// assert!(set.contains(&Point::new(0, 2, 6)));
///
/// assert!(set.contains(&Point::new(1, 1, 4)));
/// assert!(set.contains(&Point::new(2, 1, 4)));
/// assert!(set.contains(&Point::new(2, 2, 4)));
/// assert!(set.contains(&Point::new(1, 3, 4)));
/// assert!(set.contains(&Point::new(0, 3, 4)));
/// assert!(set.contains(&Point::new(0, 2, 4)));
///
/// assert!(set.contains(&Point::new(1, 2, 7)));
/// assert!(set.contains(&Point::new(1, 2, 3)));
///
/// assert_eq!(set.len(), 26);
/// ```
pub fn ring(point: &Point, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = ring_2d(&point, range);

  for index in 1..range + 1 {
    let diff = range - index;
    let up: Point = travel(point, Direction::Up, index);
    let down: Point = travel(point, Direction::Down, index);
    let up_ring: HashSet<Point> = ring_2d(&up, diff);
    let down_ring: HashSet<Point> = ring_2d(&down, diff);

    set.extend(up_ring);
    set.extend(down_ring);
  }

  set.insert(travel(point, Direction::Up, range));
  set.insert(travel(point, Direction::Down, range));

  set
}

/// Find points at the same height in a ring of a provided radius
///
/// # Example
///
/// ```
/// use hex_math::{Point, ring_2d};
/// use std::collections::HashSet;
///
/// let point: Point = Point::new(1, 2, 5);
/// let set: HashSet<Point> = ring_2d(&point, 1);
///
/// assert_eq!(set.len(), 6);
/// assert!(set.contains(&Point::new(1, 1, 5)));
/// assert!(set.contains(&Point::new(2, 1, 5)));
/// assert!(set.contains(&Point::new(2, 2, 5)));
/// assert!(set.contains(&Point::new(1, 3, 5)));
/// assert!(set.contains(&Point::new(0, 3, 5)));
/// assert!(set.contains(&Point::new(0, 2, 5)));
/// ```
pub fn ring_2d(point: &Point, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = HashSet::new();
  let mut position: Point = travel(point, Direction::Northwest, range);

  for direction in 0..6 {
    for _ in 0..range {

      let direction: Direction = match direction {
        0 => Direction::East,
        1 => Direction::Southeast,
        2 => Direction::Southwest,
        3 => Direction::West,
        4 => Direction::Northwest,
        5 => Direction::Northeast,
        _ => break,
      };

      set.insert(position);
      position = travel(&position, direction, 1);
    }
  }

  set
}

<commit_msg>Issue #7: generic ring<commit_after>//! Useful stuff for finding points in a ring

use std::collections::HashSet;

use traits::has_values::HasValues;
use point::Point;
use travel::{Direction, travel};

/// Find points at the same height in a ring of a provided radius
///
/// # Example
///
/// ```
/// use hex_math::{Point, ring};
/// use std::collections::HashSet;
///
/// let point: Point = Point::new(1, 2, 5);
/// let set: HashSet<Point> = ring(&point, 2);
///
/// assert!(set.contains(&Point::new(1, 0, 5)));
/// assert!(set.contains(&Point::new(2, 0, 5)));
/// assert!(set.contains(&Point::new(3, 0, 5)));
/// assert!(set.contains(&Point::new(3, 1, 5)));
/// assert!(set.contains(&Point::new(3, 2, 5)));
/// assert!(set.contains(&Point::new(2, 3, 5)));
/// assert!(set.contains(&Point::new(1, 4, 5)));
/// assert!(set.contains(&Point::new(0, 4, 5)));
/// assert!(set.contains(&Point::new(-1, 4, 5)));
/// assert!(set.contains(&Point::new(-1, 3, 5)));
/// assert!(set.contains(&Point::new(-1, 2, 5)));
/// assert!(set.contains(&Point::new(0, 1, 5)));
///
/// assert!(set.contains(&Point::new(1, 1, 6)));
/// assert!(set.contains(&Point::new(2, 1, 6)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(1, 3, 6)));
/// assert!(set.contains(&Point::new(0, 3, 6)));
/// assert!(set.contains(&Point::new(0, 2, 6)));
///
/// assert!(set.contains(&Point::new(1, 1, 4)));
/// assert!(set.contains(&Point::new(2, 1, 4)));
/// assert!(set.contains(&Point::new(2, 2, 4)));
/// assert!(set.contains(&Point::new(1, 3, 4)));
/// assert!(set.contains(&Point::new(0, 3, 4)));
/// assert!(set.contains(&Point::new(0, 2, 4)));
///
/// assert!(set.contains(&Point::new(1, 2, 7)));
/// assert!(set.contains(&Point::new(1, 2, 3)));
///
/// assert_eq!(set.len(), 26);
/// ```
pub fn ring<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = ring_2d(point, range);

  for index in 1..range + 1 {
    let diff = range - index;
    let up: Point = travel(point, Direction::Up, index);
    let down: Point = travel(point, Direction::Down, index);
    let up_ring: HashSet<Point> = ring_2d(&up, diff);
    let down_ring: HashSet<Point> = ring_2d(&down, diff);

    set.extend(up_ring);
    set.extend(down_ring);
  }

  set.insert(travel(point, Direction::Up, range));
  set.insert(travel(point, Direction::Down, range));

  set
}

/// Find points at the same height in a ring of a provided radius
///
/// # Example
///
/// ```
/// use hex_math::{Point, ring_2d};
/// use std::collections::HashSet;
///
/// let point: Point = Point::new(1, 2, 5);
/// let set: HashSet<Point> = ring_2d(&point, 1);
///
/// assert_eq!(set.len(), 6);
/// assert!(set.contains(&Point::new(1, 1, 5)));
/// assert!(set.contains(&Point::new(2, 1, 5)));
/// assert!(set.contains(&Point::new(2, 2, 5)));
/// assert!(set.contains(&Point::new(1, 3, 5)));
/// assert!(set.contains(&Point::new(0, 3, 5)));
/// assert!(set.contains(&Point::new(0, 2, 5)));
/// ```
pub fn ring_2d<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = HashSet::new();
  let mut position: Point = travel(point, Direction::Northwest, range);

  for direction in 0..6 {
    for _ in 0..range {

      let direction: Direction = match direction {
        0 => Direction::East,
        1 => Direction::Southeast,
        2 => Direction::Southwest,
        3 => Direction::West,
        4 => Direction::Northwest,
        5 => Direction::Northeast,
        _ => break,
      };

      set.insert(position);
      position = travel(&position, direction, 1);
    }
  }

  set
}

<|endoftext|>


<commit_before>use {ffi, FswSession, FswError, FswMonitorType, FswMonitorFilter, FswFilterType, FswEventFlag};

fn get_default_session() -> FswSession {
  FswSession::default().unwrap()
}

fn create_sample_filter() -> FswMonitorFilter {
  FswMonitorFilter::new("\\w+\\.txt$", FswFilterType::Include, false, false)
}

#[test]
fn create_and_destroy_session() {
  let handle = {
    let session = get_default_session();
    session.handle
  };
  // Check that the handle was created successfully.
  assert!(handle != ffi::FSW_INVALID_HANDLE);
  // Check that trying to destroy the handle after the session wrapper goes out of scope fails.
  // This should fail because the wrapper going out of scope should automatically destroy the
  // session.
  assert!(unsafe { ffi::fsw_destroy_session(handle) } != ffi::FSW_OK);
}

#[test]
fn create_session_from_builder() {
  FswSession::builder()
    .add_path("./")
    .property("test_name", "test_value")
    .overflow(Some(true))
    .monitor(FswMonitorType::SystemDefault)
    .latency(Some(1.0))
    .recursive(Some(true))
    .directory_only(Some(false))
    .follow_symlinks(Some(true))
    .add_event_filter(FswEventFlag::Created)
    .add_filter(create_sample_filter())
    .build_callback(|events| println!("{:#?}", events))
    .unwrap();
}

#[test]
fn start_empty() {
  assert_eq!(Err(FswError::MissingRequiredParameters), get_default_session().start_monitor());
}

#[test]
fn start_without_callback() {
  let session = get_default_session();
  session.add_path("./").unwrap();
  assert_eq!(Err(FswError::MissingRequiredParameters), session.start_monitor());
}

#[test]
fn start_without_path() {
  let session = get_default_session();
  session.set_callback(|_| println!("Hello")).unwrap();
  assert_eq!(Err(FswError::MissingRequiredParameters), session.start_monitor());
}
<commit_msg>test: add callback and invalid handle tests<commit_after>use std;
use std::sync::{Arc, Mutex, Condvar};
use {ffi, FswSession, FswStatus, FswError, FswMonitorType, FswMonitorFilter, FswFilterType,
     FswEventFlag, FswEvent};

fn get_default_session() -> FswSession {
  FswSession::default().unwrap()
}

fn create_sample_filter() -> FswMonitorFilter {
  FswMonitorFilter::new("\\w+\\.txt$", FswFilterType::Include, false, false)
}

#[test]
fn create_and_destroy_session() {
  let handle = {
    let session = get_default_session();
    session.handle
  };
  // Check that the handle was created successfully.
  assert!(handle != ffi::FSW_INVALID_HANDLE);
  // Check that trying to destroy the handle after the session wrapper goes out of scope fails.
  // This should fail because the wrapper going out of scope should automatically destroy the
  // session.
  assert!(unsafe { ffi::fsw_destroy_session(handle) } != ffi::FSW_OK);
}

#[test]
fn create_session_from_builder() {
  FswSession::builder()
    .add_path("./")
    .property("test_name", "test_value")
    .overflow(Some(true))
    .monitor(FswMonitorType::SystemDefault)
    .latency(Some(1.0))
    .recursive(Some(true))
    .directory_only(Some(false))
    .follow_symlinks(Some(true))
    .add_event_filter(FswEventFlag::Created)
    .add_filter(create_sample_filter())
    .build_callback(|events| println!("{:#?}", events))
    .unwrap();
}

#[test]
fn start_empty() {
  assert_eq!(Err(FswError::MissingRequiredParameters), get_default_session().start_monitor());
}

#[test]
fn start_without_callback() {
  let session = get_default_session();
  session.add_path("./").unwrap();
  assert_eq!(Err(FswError::MissingRequiredParameters), session.start_monitor());
}

#[test]
fn start_without_path() {
  let session = get_default_session();
  session.set_callback(|_| println!("Hello")).unwrap();
  assert_eq!(Err(FswError::MissingRequiredParameters), session.start_monitor());
}

#[test]
fn invalid_path() {
  let session = get_default_session();
  unsafe {
    assert!(ffi::fsw_add_path(session.handle, ::std::ptr::null()) == ffi::FSW_ERR_INVALID_PATH);
  }
}

#[test]
fn invalid_handle_add_path() {
  let mut session = get_default_session();
  // Set handle to the invalid handle before trying to call methods.
  session.handle = ffi::FSW_INVALID_HANDLE;
  let res = session.add_path("./");
  let expected_error = Err(FswError::FromFsw(FswStatus::SessionUnknown));
  assert_eq!(expected_error, res);
  assert!(!session.path_added.get());
}

#[test]
fn invalid_handle_set_callback() {
  let mut session = get_default_session();
  // Set handle to the invalid handle before trying to call methods.
  session.handle = ffi::FSW_INVALID_HANDLE;
  let res = session.set_callback(|_| {});
  let expected_error = Err(FswError::FromFsw(FswStatus::SessionUnknown));
  assert_eq!(expected_error, res);
  assert!(!session.callback_set.get());
}

#[test]
fn run_callback() {
  // Define the file name for this test.
  let file_name = "fsw_test_file";

  // Create new condvar for waiting.
  let pair = Arc::new((Mutex::new(false), Condvar::new()));
  // Create clone for thread.
  let pair2 = pair.clone();

  // Get a handle to this thread.
  let handle = std::thread::spawn(move || {
    // Extract our pair.
    let &(ref lock, ref cvar) = &*pair2;
    // Create a session.
    let session = FswSession::builder_paths(vec!["./"])
      // Filter for only our file name.
      .add_filter(FswMonitorFilter::new(file_name, FswFilterType::Include, true, false))
      // Reject all other files.
      .add_filter(FswMonitorFilter::new(".*", FswFilterType::Exclude, false, false))
      .build().unwrap();
    // Use the iterator pattern but immediately break out of it. This will leave the monitor running
    // and accumulating events (as the C API provides no way to stop a monitor).
    for event in session {
      // Once we get an event, notify our waiting condvar and return the event.
      let mut started = lock.lock().unwrap();
      *started = true;
      cvar.notify_one();
      return event;
    }
    // This should be unreachable code, so panic if we get here.
    unreachable!();
  });

  // Create the file for the thread to find the event for.
  let file_path = format!("./{}", file_name);
  std::fs::File::create(&file_path).unwrap();

  // Wait for the thread for up to five seconds.
  let &(ref lock, ref cvar) = &*pair;
  let mut started = lock.lock().unwrap();
  while !*started {
    let (s, timeout) = cvar.wait_timeout(started, std::time::Duration::from_secs(5)).unwrap();
    started = s;
    // Assert that we didn't time out waiting. This prevents the test from infinitely blocking.
    assert!(!timeout.timed_out());
  }

  // Get the event from the thread.
  let event: FswEvent = handle.join().unwrap();

  // Remove the file.
  std::fs::remove_file(&file_path).unwrap();

  let path = std::path::PathBuf::from(event.path);
  let event_file_name = path.file_name().unwrap().to_string_lossy();
  // Assert that the created file name matches the event's file name.
  assert_eq!(file_name, event_file_name);
  // Assert that the IsFile flag is present in the event flags. Note that we cannot assert that the
  // Created flag is present due to how fswatch works.
  assert!(event.flags.contains(&FswEventFlag::IsFile));
}
<|endoftext|>


<commit_before>/// unit creates a type representing a single unit.
///
/// # Examples
///
/// ```
/// #[macro_use(unit)]
/// extern crate fiz_math;
/// use std::fmt::Debug;
///
/// // GoldCoins are golden!
/// unit!(GoldCoins);
///
/// // SilverCoins are like gold coins, only worse!
/// unit!(SilverCoins);
///
/// fn collect<T: Debug>(coins: GoldCoins<T>) {
///     println!("We've collected {:?} golden coins!", coins.0);
/// }
///
/// fn main() {
///     let x = GoldCoins(5);
///     collect(x);
///
///     let y = SilverCoins(6);
///
///     // Try uncommenting the line below and see:
///     //
///     // error: mismatched types: expected `GoldCoins<_>`, found `SilverCoins<_>`"
///     //
///     //collect(y);
///
///     // add, subtract, multiply, divide:
///     assert_eq!(y + SilverCoins(4), SilverCoins(10));
///     assert_eq!(y - SilverCoins(3), SilverCoins(3));
///     assert_eq!(y * SilverCoins(3), SilverCoins(18));
///     assert_eq!(y / SilverCoins(2), SilverCoins(3));
///
///     // ordering and equality:
///     assert!(y < SilverCoins(7));
///     assert!(y > SilverCoins(5));
///     assert!(y <= SilverCoins(6));
///     assert!(y >= SilverCoins(6));
///     assert!(y == SilverCoins(6));
/// }
/// ```
///
#[macro_export]
macro_rules! unit {
    ( $ident:ident ) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $ident<T>(pub T);

        // addition
        impl<T: ::std::ops::Add<Output = T>> ::std::ops::Add for $ident<T> {
            type Output = Self;

            fn add(self, _rhs: Self) -> Self {
                $ident(self.0 + _rhs.0)
            }
        }

        // subtraction
        impl<T: ::std::ops::Sub<Output = T>> ::std::ops::Sub for $ident<T> {
            type Output = Self;

            fn sub(self, _rhs: Self) -> Self {
                $ident(self.0 - _rhs.0)
            }
        }

        // multiplication
        impl<T: ::std::ops::Mul<Output = T>> ::std::ops::Mul for $ident<T> {
            type Output = Self;

            fn mul(self, _rhs: Self) -> Self {
                $ident(self.0 * _rhs.0)
            }
        }

        // division
        impl<T: ::std::ops::Div<Output = T>> ::std::ops::Div for $ident<T> {
            type Output = Self;

            fn div(self, _rhs: Self) -> Self {
                $ident(self.0 / _rhs.0)
            }
        }

        // remainder
        impl<T: ::std::ops::Rem<Output = T>> ::std::ops::Rem for $ident<T> {
            type Output = Self;

            fn rem(self, rhs: Self) -> Self { $ident(self.0 % rhs.0) }
        }

        // negation
        impl<T: ::std::ops::Neg<Output = T>> ::std::ops::Neg for $ident<T> {
            type Output = Self;

            fn neg(self) -> Self::Output { $ident(-self.0) }
        }

        // not
        impl<T: ::std::ops::Not<Output = T>> ::std::ops::Not for $ident<T> {
            type Output = Self;

            fn not(self) -> Self::Output { $ident(!self.0) }
        }

        // bitwise and
        impl<T: ::std::ops::BitAnd<Output = T>> ::std::ops::BitAnd for $ident<T> {
            type Output = Self;

            fn bitand(self, rhs: Self) -> Self::Output { $ident(self.0 & rhs.0) }
        }

        // partial equality
        impl<T: ::std::cmp::PartialEq> ::std::cmp::PartialEq for $ident<T> {
            fn eq(&self, _rhs: &Self) -> bool {
                self.0 == _rhs.0
            }
        }

        // equality
        impl<T: ::std::cmp::Eq> ::std::cmp::Eq for $ident<T> {}

        // partial ordering
        impl<T: ::std::cmp::PartialOrd> ::std::cmp::PartialOrd for $ident<T> {
            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
                if self.0 < other.0 {
                    Some(::std::cmp::Ordering::Less)
                } else if self.0 > other.0 {
                    Some(::std::cmp::Ordering::Greater)
                } else if self == other {
                    Some(::std::cmp::Ordering::Equal)
                } else {
                    None
                }
            }
        }

        // total ordering
        impl<T: ::std::cmp::Ord> ::std::cmp::Ord for $ident<T> {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                if self.0 < other.0 {
                    ::std::cmp::Ordering::Less
                } else if self.0 > other.0 {
                    ::std::cmp::Ordering::Greater
                } else {
                    ::std::cmp::Ordering::Equal
                }
            }
        }
    };
}
<commit_msg>unit! implement bitwise or operator<commit_after>/// unit creates a type representing a single unit.
///
/// # Examples
///
/// ```
/// #[macro_use(unit)]
/// extern crate fiz_math;
/// use std::fmt::Debug;
///
/// // GoldCoins are golden!
/// unit!(GoldCoins);
///
/// // SilverCoins are like gold coins, only worse!
/// unit!(SilverCoins);
///
/// fn collect<T: Debug>(coins: GoldCoins<T>) {
///     println!("We've collected {:?} golden coins!", coins.0);
/// }
///
/// fn main() {
///     let x = GoldCoins(5);
///     collect(x);
///
///     let y = SilverCoins(6);
///
///     // Try uncommenting the line below and see:
///     //
///     // error: mismatched types: expected `GoldCoins<_>`, found `SilverCoins<_>`"
///     //
///     //collect(y);
///
///     // add, subtract, multiply, divide:
///     assert_eq!(y + SilverCoins(4), SilverCoins(10));
///     assert_eq!(y - SilverCoins(3), SilverCoins(3));
///     assert_eq!(y * SilverCoins(3), SilverCoins(18));
///     assert_eq!(y / SilverCoins(2), SilverCoins(3));
///
///     // ordering and equality:
///     assert!(y < SilverCoins(7));
///     assert!(y > SilverCoins(5));
///     assert!(y <= SilverCoins(6));
///     assert!(y >= SilverCoins(6));
///     assert!(y == SilverCoins(6));
/// }
/// ```
///
#[macro_export]
macro_rules! unit {
    ( $ident:ident ) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $ident<T>(pub T);

        // addition
        impl<T: ::std::ops::Add<Output = T>> ::std::ops::Add for $ident<T> {
            type Output = Self;

            fn add(self, _rhs: Self) -> Self {
                $ident(self.0 + _rhs.0)
            }
        }

        // subtraction
        impl<T: ::std::ops::Sub<Output = T>> ::std::ops::Sub for $ident<T> {
            type Output = Self;

            fn sub(self, _rhs: Self) -> Self {
                $ident(self.0 - _rhs.0)
            }
        }

        // multiplication
        impl<T: ::std::ops::Mul<Output = T>> ::std::ops::Mul for $ident<T> {
            type Output = Self;

            fn mul(self, _rhs: Self) -> Self {
                $ident(self.0 * _rhs.0)
            }
        }

        // division
        impl<T: ::std::ops::Div<Output = T>> ::std::ops::Div for $ident<T> {
            type Output = Self;

            fn div(self, _rhs: Self) -> Self {
                $ident(self.0 / _rhs.0)
            }
        }

        // remainder
        impl<T: ::std::ops::Rem<Output = T>> ::std::ops::Rem for $ident<T> {
            type Output = Self;

            fn rem(self, rhs: Self) -> Self { $ident(self.0 % rhs.0) }
        }

        // negation
        impl<T: ::std::ops::Neg<Output = T>> ::std::ops::Neg for $ident<T> {
            type Output = Self;

            fn neg(self) -> Self::Output { $ident(-self.0) }
        }

        // not
        impl<T: ::std::ops::Not<Output = T>> ::std::ops::Not for $ident<T> {
            type Output = Self;

            fn not(self) -> Self::Output { $ident(!self.0) }
        }

        // bitwise and
        impl<T: ::std::ops::BitAnd<Output = T>> ::std::ops::BitAnd for $ident<T> {
            type Output = Self;

            fn bitand(self, rhs: Self) -> Self::Output { $ident(self.0 & rhs.0) }
        }

        // bitwise or
        impl<T: ::std::ops::BitOr<Output = T>> ::std::ops::BitOr for $ident<T> {
            type Output = Self;

            fn bitor(self, rhs: Self) -> Self::Output { $ident(self.0 | rhs.0) }
        }

        // partial equality
        impl<T: ::std::cmp::PartialEq> ::std::cmp::PartialEq for $ident<T> {
            fn eq(&self, _rhs: &Self) -> bool {
                self.0 == _rhs.0
            }
        }

        // equality
        impl<T: ::std::cmp::Eq> ::std::cmp::Eq for $ident<T> {}

        // partial ordering
        impl<T: ::std::cmp::PartialOrd> ::std::cmp::PartialOrd for $ident<T> {
            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
                if self.0 < other.0 {
                    Some(::std::cmp::Ordering::Less)
                } else if self.0 > other.0 {
                    Some(::std::cmp::Ordering::Greater)
                } else if self == other {
                    Some(::std::cmp::Ordering::Equal)
                } else {
                    None
                }
            }
        }

        // total ordering
        impl<T: ::std::cmp::Ord> ::std::cmp::Ord for $ident<T> {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                if self.0 < other.0 {
                    ::std::cmp::Ordering::Less
                } else if self.0 > other.0 {
                    ::std::cmp::Ordering::Greater
                } else {
                    ::std::cmp::Ordering::Equal
                }
            }
        }
    };
}
<|endoftext|>