<commit_before>// Extern crates.
use graphics::*;
use input::keyboard;
use current::{ Usage, UseCurrent };

// Local crate.
use action;
use settings;
use object;
use object::Object;
use text;
use game_state;

pub fn current_app() -> Usage<'static, SnakeApp> { UseCurrent }
pub fn current_cam() -> Usage<'static, Cam> { UseCurrent }
pub fn current_game_state()
    -> Usage<'static, game_state::GameState> { UseCurrent }

pub fn app(f: ||) {
    use std::cell::RefCell;
    use current::Current;

    let app = SnakeApp::new();
    let cam = Cam([0.0, 0.0]);
    let game_state = game_state::Play;

    let app = RefCell::new(app);
    let cam = RefCell::new(cam);
    let game_state = RefCell::new(game_state);

    let app_guard = app.set_current();
    let cam_guard = cam.set_current();
    let game_state_guard = game_state.set_current();

    f();

    drop(game_state_guard);
    drop(app_guard);
    drop(cam_guard);
}

pub struct Cam(pub [f64, ..2]);

impl Cam {
    fn pos(&self) -> [f64, ..2] {
        let Cam(pos) = *self;
        pos
    }

    fn set(&mut self, val: [f64, ..2]) {
        *self = Cam(val);
    }
}

pub struct SnakeApp {
    // Tells where the surface is.
    surface_y: Option<f64>,
    camera_follow_percentage: Option<f64>,
    player_index: Option<uint>,
    blood_bar_index: Option<uint>,
    air_bar_index: Option<uint>,
    // Contains the game objects.
    objects: Vec<Object>,
}

impl SnakeApp {
    pub fn render<B: BackEnd<I>, I: ImageSize>(
        &self, c: &Context, gl: &mut B
    ) {
        let c = &c.reset();

        // Get camera coordinates.
        let [cam_x, mut cam_y] = current_cam().pos();
        cam_y += 0.4;

        // Render surface.
        let surface_y = self.surface_y.unwrap();
        c.rect(-1.0, surface_y - cam_y, 2.0, 0.05).color(settings::BLUE).draw(gl);

        // Render objects in layers.
        let cam = &c.trans(-cam_x, -cam_y);
        for i in range(0u, settings::NUMBER_OF_LAYERS) {
            for obj in self.objects.iter() {
                if obj.layer == i { obj.render(cam, c, gl); }
            }
        }

        let text_c = c.flip_v();
        let text_c = text_c.zoom(0.0025);
        match *current_game_state() {
            game_state::Win => {
                let pos = settings::YOU_WIN_POS;
                text::text(settings::YOU_WIN_TEXT,
                    &text_c
                    .trans(pos[0], pos[1])
                    .color(settings::YOU_WIN_TEXT_COLOR)
                , gl);
            },
            game_state::Lose => {
                let pos = settings::YOU_LOSE_POS;
                text::text(settings::YOU_LOSE_TEXT,
                    &text_c
                    .trans(pos[0], pos[1])
                    .color(settings::YOU_LOSE_TEXT_COLOR)
                , gl);
            },
            game_state::Play => {

            },
        }
    }

    pub fn update(&mut self, dt: f64) {
        self.update_objects(dt);
        self.fill_air();
        self.win();
        self.lose();
        self.show_blood();
        self.show_air();
        self.follow_player(dt);
    }

    pub fn load(&mut self) {
        self.camera_follow_percentage = Some(settings::CAMERA_FOLLOW_PERCENTAGE);
        current_cam().set(settings::INITIAL_CAMERA_POS);
        self.surface_y = Some(settings::SURFACE_Y);
        *current_game_state() = settings::INITIAL_GAME_STATE;

        // Add player.
        self.objects.push(Object::player(
            settings::ORIGIN,
            settings::BLUE,
            settings::PLAYER_INITIAL_BLOOD,
            settings::PLAYER_INITIAL_AIR,
            [settings::PLAYER_ACCELERATION_LEFT, settings::PLAYER_ACCELERATION_RIGHT],
            [settings::PLAYER_ACCELERATION_UP, settings::PLAYER_ACCELERATION_DOWN]
        ));
        self.objects.push(Object::bar_background());
        self.player_index = Some(0);

        // Add blood and air bar.
        self.add_bars();

        // Add air bottles.
        self.add_air_bottles();

        // Add snakes.
        self.add_snakes();
    }

    pub fn key_press(&mut self, key: keyboard::Key) {
        if *current_game_state() != game_state::Play { return; }

        match (key, self.player_index) {
            (keyboard::Right, Some(player_index)) => {
                self.objects[player_index].move_right();
            },
            (keyboard::Up, Some(player_index)) => {
                self.objects[player_index].move_up();
            },
            (keyboard::Left, Some(player_index)) => {
                self.objects[player_index].move_left();
            },
            (keyboard::Down, Some(player_index)) => {
                self.objects[player_index].move_down();
            },
            _ => {},
        }
    }

    pub fn key_release(&mut self, key: keyboard::Key) {
        if key == keyboard::Return || key == keyboard::Space {
            match *current_game_state() {
                game_state::Win | game_state::Lose => self.restart(),
                _ => {},
            }
        }
    }

    pub fn new() -> SnakeApp {
        SnakeApp {
            camera_follow_percentage: None,
            surface_y: None,
            objects: Vec::new(),
            player_index: None,
            blood_bar_index: None,
            air_bar_index: None,
        }
    }

    pub fn add_bars(&mut self) {
        self.objects.push(Object::bar(
            settings::AIR_BAR_POS,
            "air",
            settings::AIR_BAR_TEXT_COLOR,
            settings::AIR_BAR_BACKGROUND_COLOR,
            settings::AIR_BAR_BAR_COLOR,
            settings::AIR_BAR_INITIAL_VALUE
        ));
        self.air_bar_index = Some(self.objects.len() - 1);
        self.objects.push(Object::bar(
            settings::BLOOD_BAR_POS,
            "blood",
            settings::BLOOD_BAR_TEXT_COLOR,
            settings::BLOOD_BAR_BACKGROUND_COLOR,
            settings::BLOOD_BAR_BAR_COLOR,
            settings::BLOOD_BAR_INITIAL_VALUE
        ));
        self.blood_bar_index = Some(self.objects.len() - 1);
    }

    pub fn add_snakes(&mut self) {
        if settings::SNAKE_1_ADD { self.objects.push(Object::snake(settings::SNAKE_1_POS, settings::SNAKE_1_SETTINGS)); }
        if settings::SNAKE_2_ADD { self.objects.push(Object::snake(settings::SNAKE_2_POS, settings::SNAKE_2_SETTINGS)); }
    }

    pub fn add_air_bottles(&mut self) {
        let air_bottles = settings::AIR_BOTTLE_POS;
        let n = air_bottles.len() / 2;
        for i in range(0, n) {
            self.objects.push(Object::air_bottle([air_bottles[i * 2], air_bottles[i * 2 + 1]]));
        }
    }

    fn follow_player(&mut self, dt: f64) {
        // Make camera follow player.
        let camera_pos = current_cam().pos();
        let camera_follow_percentage = self.camera_follow_percentage.unwrap();
        let player_pos = self.player_pos();
        let (dx, dy) = (player_pos[0] - camera_pos[0], player_pos[1] - camera_pos[1]);
        let dx = camera_follow_percentage * dt * dx;
        let dy = camera_follow_percentage * dt * dy;
        current_cam().set([camera_pos[0] + dx, camera_pos[1] + dy]);
    }

    fn show_blood(&mut self) {
        if self.blood_bar_index == None { return; }
        // Show blood.
        let player_blood = self.player_blood();
        let blood_bar_index = self.blood_bar_index.unwrap();
        let blood_bar = self.objects.get_mut(blood_bar_index).unwrap();
        match blood_bar.data {
            object::BarData(ref mut bar) => {
                bar.value = player_blood;
            },
            _ => {},
        }
    }

    fn show_air(&mut self) {
        if self.air_bar_index == None { return; }
        // Show air.
        let player_air = self.player_air();
        let air_bar_index = self.air_bar_index.unwrap();
        let air_bar = self.objects.get_mut(air_bar_index).unwrap();
        match air_bar.data {
            object::BarData(ref mut bar) => {
                bar.value = player_air;
            },
            _ => {},
        }
    }

    fn win(&mut self) {
        let player_pos = self.player_pos();
        // When player reaches surface, win.
        if player_pos[1] >= self.surface_y.unwrap() {
            *current_game_state() = game_state::Win;
            return;
        }
    }

    fn lose(&mut self) {
        let blood = self.player_blood();
        let air = self.player_air();
        if blood < 0.0 || air < 0.0 {
            *current_game_state() = game_state::Lose;
            return;
        }
    }

    fn restart(&mut self) {
        *self = SnakeApp::new();
        self.load();
    }

    fn update_objects(&mut self, dt: f64) {
        if *current_game_state() != game_state::Play { return; }

        // Update states of objects.
        let player_pos = self.player_pos();
        let mut attack_damage: f64 = 0.0;
        for obj in self.objects.iter_mut() {
            match obj.update(dt, player_pos) {
                action::Passive => {},
                action::Attack(attack) => { attack_damage += attack; },
            }
        }
        // Bite player.
        self.bite_player(attack_damage);

        // Decrease the player's air with time.
        let air = self.player_air();
        self.set_player_air(air - dt * settings::PLAYER_LOSE_AIR_SPEED);
    }

    fn player_pos(&self) -> [f64, ..2] {
        let player_index = self.player_index.unwrap();
        self.objects[player_index].pos
    }

    fn player_blood(&self) -> f64 {
        let player_index = self.player_index.unwrap();
        self.objects[player_index].blood().unwrap()
    }

    fn player_air(&self) -> f64 {
        let player_index = self.player_index.unwrap();
        self.objects[player_index].air().unwrap()
    }

    fn set_player_air(&mut self, val: f64) {
        let player_index = self.player_index.unwrap();
        *self.objects[player_index].air_mut().unwrap() = val;
    }

    fn bite_player(&mut self, damage: f64) {
        let player_index = self.player_index.unwrap();
        self.objects[player_index].player_mut().unwrap().bite(damage);
    }

    fn fill_air(&mut self) {
        let player_pos = self.player_pos();
        let mut air = self.player_air();
        for obj in self.objects.iter_mut() {
            let pos = obj.pos;
            match obj.air_bottle_mut() {
                None => {},
                Some(air_bottle) => {
                    let dx = pos[0] - player_pos[0];
                    let dy = pos[1] - player_pos[1];
                    let d = dx * dx + dy * dy;
                    if d <= settings::AIR_BOTTLE_RADIUS * settings::AIR_BOTTLE_RADIUS {
                        air += air_bottle.fill_up;
                        air_bottle.fill_up = 0.0;
                    }
                },
            }
        }

        air = if air > 1.0 { 1.0 } else { air };
        self.set_player_air(air);
    }
}
<commit_msg>Made objects current object<commit_after>// Extern crates.
use graphics::*;
use input::keyboard;
use current::{ Usage, UseCurrent };

// Local crate.
use action;
use settings;
use object;
use object::Object;
use text;
use game_state;

pub fn current_app() -> Usage<'static, SnakeApp> { UseCurrent }
pub fn current_cam() -> Usage<'static, Cam> { UseCurrent }
pub fn current_game_state()
    -> Usage<'static, game_state::GameState> { UseCurrent }
pub fn current_objects() -> Usage<'static, Vec<Object>> { UseCurrent }

pub fn app(f: ||) {
    use std::cell::RefCell;
    use current::Current;

    let app = SnakeApp::new();
    let cam = Cam([0.0, 0.0]);
    let game_state = game_state::Play;
    let objects: Vec<Object> = Vec::new();

    let app = RefCell::new(app);
    let cam = RefCell::new(cam);
    let game_state = RefCell::new(game_state);
    let objects = RefCell::new(objects);

    let app_guard = app.set_current();
    let cam_guard = cam.set_current();
    let game_state_guard = game_state.set_current();
    let objects_guard = objects.set_current();

    f();

    drop(objects_guard);
    drop(game_state_guard);
    drop(app_guard);
    drop(cam_guard);
}

pub struct Cam(pub [f64, ..2]);

impl Cam {
    fn pos(&self) -> [f64, ..2] {
        let Cam(pos) = *self;
        pos
    }

    fn set(&mut self, val: [f64, ..2]) {
        *self = Cam(val);
    }
}

pub struct SnakeApp {
    // Tells where the surface is.
    surface_y: Option<f64>,
    camera_follow_percentage: Option<f64>,
    player_index: Option<uint>,
    blood_bar_index: Option<uint>,
    air_bar_index: Option<uint>,
}

impl SnakeApp {
    pub fn render<B: BackEnd<I>, I: ImageSize>(
        &self, c: &Context, gl: &mut B
    ) {
        let c = &c.reset();

        // Get camera coordinates.
        let [cam_x, mut cam_y] = current_cam().pos();
        cam_y += 0.4;

        // Render surface.
        let surface_y = self.surface_y.unwrap();
        c.rect(-1.0, surface_y - cam_y, 2.0, 0.05).color(settings::BLUE).draw(gl);

        // Render objects in layers.
        let cam = &c.trans(-cam_x, -cam_y);
        for i in range(0u, settings::NUMBER_OF_LAYERS) {
            for obj in current_objects().iter() {
                if obj.layer == i { obj.render(cam, c, gl); }
            }
        }

        let text_c = c.flip_v();
        let text_c = text_c.zoom(0.0025);
        match *current_game_state() {
            game_state::Win => {
                let pos = settings::YOU_WIN_POS;
                text::text(settings::YOU_WIN_TEXT,
                    &text_c
                    .trans(pos[0], pos[1])
                    .color(settings::YOU_WIN_TEXT_COLOR)
                , gl);
            },
            game_state::Lose => {
                let pos = settings::YOU_LOSE_POS;
                text::text(settings::YOU_LOSE_TEXT,
                    &text_c
                    .trans(pos[0], pos[1])
                    .color(settings::YOU_LOSE_TEXT_COLOR)
                , gl);
            },
            game_state::Play => {

            },
        }
    }

    pub fn update(&mut self, dt: f64) {
        self.update_objects(dt);
        self.fill_air();
        self.win();
        self.lose();
        self.show_blood();
        self.show_air();
        self.follow_player(dt);
    }

    pub fn load(&mut self) {
        self.camera_follow_percentage = Some(settings::CAMERA_FOLLOW_PERCENTAGE);
        current_cam().set(settings::INITIAL_CAMERA_POS);
        self.surface_y = Some(settings::SURFACE_Y);
        *current_game_state() = settings::INITIAL_GAME_STATE;

        // Add player.
        current_objects().push(Object::player(
            settings::ORIGIN,
            settings::BLUE,
            settings::PLAYER_INITIAL_BLOOD,
            settings::PLAYER_INITIAL_AIR,
            [settings::PLAYER_ACCELERATION_LEFT, settings::PLAYER_ACCELERATION_RIGHT],
            [settings::PLAYER_ACCELERATION_UP, settings::PLAYER_ACCELERATION_DOWN]
        ));
        current_objects().push(Object::bar_background());
        self.player_index = Some(0);

        // Add blood and air bar.
        self.add_bars();

        // Add air bottles.
        self.add_air_bottles();

        // Add snakes.
        self.add_snakes();
    }

    pub fn key_press(&mut self, key: keyboard::Key) {
        if *current_game_state() != game_state::Play { return; }

        match (key, self.player_index) {
            (keyboard::Right, Some(player_index)) => {
                current_objects()[player_index].move_right();
            },
            (keyboard::Up, Some(player_index)) => {
                current_objects()[player_index].move_up();
            },
            (keyboard::Left, Some(player_index)) => {
                current_objects()[player_index].move_left();
            },
            (keyboard::Down, Some(player_index)) => {
                current_objects()[player_index].move_down();
            },
            _ => {},
        }
    }

    pub fn key_release(&mut self, key: keyboard::Key) {
        if key == keyboard::Return || key == keyboard::Space {
            match *current_game_state() {
                game_state::Win | game_state::Lose => self.restart(),
                _ => {},
            }
        }
    }

    pub fn new() -> SnakeApp {
        SnakeApp {
            camera_follow_percentage: None,
            surface_y: None,
            player_index: None,
            blood_bar_index: None,
            air_bar_index: None,
        }
    }

    pub fn add_bars(&mut self) {
        let objects = &mut *current_objects();
        objects.push(Object::bar(
            settings::AIR_BAR_POS,
            "air",
            settings::AIR_BAR_TEXT_COLOR,
            settings::AIR_BAR_BACKGROUND_COLOR,
            settings::AIR_BAR_BAR_COLOR,
            settings::AIR_BAR_INITIAL_VALUE
        ));
        self.air_bar_index = Some(objects.len() - 1);
        objects.push(Object::bar(
            settings::BLOOD_BAR_POS,
            "blood",
            settings::BLOOD_BAR_TEXT_COLOR,
            settings::BLOOD_BAR_BACKGROUND_COLOR,
            settings::BLOOD_BAR_BAR_COLOR,
            settings::BLOOD_BAR_INITIAL_VALUE
        ));
        self.blood_bar_index = Some(objects.len() - 1);
    }

    pub fn add_snakes(&mut self) {
        if settings::SNAKE_1_ADD { current_objects().push(
            Object::snake(settings::SNAKE_1_POS, settings::SNAKE_1_SETTINGS)); }
        if settings::SNAKE_2_ADD { current_objects().push(
            Object::snake(settings::SNAKE_2_POS, settings::SNAKE_2_SETTINGS)); }
    }

    pub fn add_air_bottles(&mut self) {
        let air_bottles = settings::AIR_BOTTLE_POS;
        let n = air_bottles.len() / 2;
        let objects = &mut *current_objects();
        for i in range(0, n) {
            objects.push(Object::air_bottle([air_bottles[i * 2], air_bottles[i * 2 + 1]]));
        }
    }

    fn follow_player(&mut self, dt: f64) {
        // Make camera follow player.
        let camera_pos = current_cam().pos();
        let camera_follow_percentage = self.camera_follow_percentage.unwrap();
        let player_pos = self.player_pos();
        let (dx, dy) = (player_pos[0] - camera_pos[0], player_pos[1] - camera_pos[1]);
        let dx = camera_follow_percentage * dt * dx;
        let dy = camera_follow_percentage * dt * dy;
        current_cam().set([camera_pos[0] + dx, camera_pos[1] + dy]);
    }

    fn show_blood(&mut self) {
        if self.blood_bar_index == None { return; }
        // Show blood.
        let player_blood = self.player_blood();
        let blood_bar_index = self.blood_bar_index.unwrap();
        let objects = &mut *current_objects();
        let blood_bar = objects.get_mut(blood_bar_index).unwrap();
        match blood_bar.data {
            object::BarData(ref mut bar) => {
                bar.value = player_blood;
            },
            _ => {},
        }
    }

    fn show_air(&mut self) {
        if self.air_bar_index == None { return; }
        // Show air.
        let player_air = self.player_air();
        let air_bar_index = self.air_bar_index.unwrap();
        let objects = &mut *current_objects();
        let ref mut air_bar = objects.get_mut(air_bar_index).unwrap();
        match air_bar.data {
            object::BarData(ref mut bar) => {
                bar.value = player_air;
            },
            _ => {},
        }
    }

    fn win(&mut self) {
        let player_pos = self.player_pos();
        // When player reaches surface, win.
        if player_pos[1] >= self.surface_y.unwrap() {
            *current_game_state() = game_state::Win;
            return;
        }
    }

    fn lose(&mut self) {
        let blood = self.player_blood();
        let air = self.player_air();
        if blood < 0.0 || air < 0.0 {
            *current_game_state() = game_state::Lose;
            return;
        }
    }

    fn restart(&mut self) {
        *self = SnakeApp::new();
        self.load();
    }

    fn update_objects(&mut self, dt: f64) {
        if *current_game_state() != game_state::Play { return; }

        // Update states of objects.
        let player_pos = self.player_pos();
        let mut attack_damage: f64 = 0.0;
        for obj in current_objects().iter_mut() {
            match obj.update(dt, player_pos) {
                action::Passive => {},
                action::Attack(attack) => { attack_damage += attack; },
            }
        }
        // Bite player.
        self.bite_player(attack_damage);

        // Decrease the player's air with time.
        let air = self.player_air();
        self.set_player_air(air - dt * settings::PLAYER_LOSE_AIR_SPEED);
    }

    fn player_pos(&self) -> [f64, ..2] {
        let player_index = self.player_index.unwrap();
        current_objects()[player_index].pos
    }

    fn player_blood(&self) -> f64 {
        let player_index = self.player_index.unwrap();
        current_objects()[player_index].blood().unwrap()
    }

    fn player_air(&self) -> f64 {
        let player_index = self.player_index.unwrap();
        current_objects()[player_index].air().unwrap()
    }

    fn set_player_air(&mut self, val: f64) {
        let player_index = self.player_index.unwrap();
        *current_objects()[player_index].air_mut().unwrap() = val;
    }

    fn bite_player(&mut self, damage: f64) {
        let player_index = self.player_index.unwrap();
        current_objects()[player_index].player_mut().unwrap().bite(damage);
    }

    fn fill_air(&mut self) {
        let player_pos = self.player_pos();
        let mut air = self.player_air();
        for obj in current_objects().iter_mut() {
            let pos = obj.pos;
            match obj.air_bottle_mut() {
                None => {},
                Some(air_bottle) => {
                    let dx = pos[0] - player_pos[0];
                    let dy = pos[1] - player_pos[1];
                    let d = dx * dx + dy * dy;
                    if d <= settings::AIR_BOTTLE_RADIUS * settings::AIR_BOTTLE_RADIUS {
                        air += air_bottle.fill_up;
                        air_bottle.fill_up = 0.0;
                    }
                },
            }
        }

        air = if air > 1.0 { 1.0 } else { air };
        self.set_player_air(air);
    }
}
<|endoftext|>


<commit_before>use serde::Deserialize;
use std::fmt::{self, Display, Formatter};
use std::fs::{remove_file};
use std::path::{PathBuf};
use std::process::{self, Command, Output};

const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];

fn temp_file() -> String {
    format!("./temp_{}", process::id())
}

#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Mode {
    Compile,
    Test,
}

#[derive(Deserialize)]
pub struct ExerciseList {
    pub exercises: Vec<Exercise>,
}

#[derive(Deserialize)]
pub struct Exercise {
    pub path: PathBuf,
    pub mode: Mode,
}

impl Exercise {
    pub fn compile(&self) -> Output {
        match self.mode {
            Mode::Compile => Command::new("rustc")
                .args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
                .args(RUSTC_COLOR_ARGS)
                .output(),
            Mode::Test => Command::new("rustc")
                .args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
                .args(RUSTC_COLOR_ARGS)
                .output(),
        }
        .expect("Failed to run 'compile' command.")
    }

    pub fn run(&self) -> Output {
        Command::new(&temp_file())
            .args(&["--", "--nocapture"])
            .output()
            .expect("Failed to run 'run' command")
    }

    pub fn clean(&self) {
        let _ignored = remove_file(&temp_file());
    }
}

impl Display for Exercise {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", self.path.to_str().unwrap())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::path::Path;
    use std::fs::File;

    #[test]
    fn test_clean() {
        File::create(&temp_file()).unwrap();
        let exercise = Exercise {
            path: PathBuf::from("example.rs"),
            mode: Mode::Test,
        };
        exercise.clean();
        assert!(!Path::new(&temp_file()).exists());
    }
}
<commit_msg>Revert --nocapture flag<commit_after>use serde::Deserialize;
use std::fmt::{self, Display, Formatter};
use std::fs::{remove_file};
use std::path::{PathBuf};
use std::process::{self, Command, Output};

const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];

fn temp_file() -> String {
    format!("./temp_{}", process::id())
}

#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Mode {
    Compile,
    Test,
}

#[derive(Deserialize)]
pub struct ExerciseList {
    pub exercises: Vec<Exercise>,
}

#[derive(Deserialize)]
pub struct Exercise {
    pub path: PathBuf,
    pub mode: Mode,
}

impl Exercise {
    pub fn compile(&self) -> Output {
        match self.mode {
            Mode::Compile => Command::new("rustc")
                .args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
                .args(RUSTC_COLOR_ARGS)
                .output(),
            Mode::Test => Command::new("rustc")
                .args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
                .args(RUSTC_COLOR_ARGS)
                .output(),
        }
        .expect("Failed to run 'compile' command.")
    }

    pub fn run(&self) -> Output {
        Command::new(&temp_file())
            .output()
            .expect("Failed to run 'run' command")
    }

    pub fn clean(&self) {
        let _ignored = remove_file(&temp_file());
    }
}

impl Display for Exercise {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", self.path.to_str().unwrap())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::path::Path;
    use std::fs::File;

    #[test]
    fn test_clean() {
        File::create(&temp_file()).unwrap();
        let exercise = Exercise {
            path: PathBuf::from("example.rs"),
            mode: Mode::Test,
        };
        exercise.clean();
        assert!(!Path::new(&temp_file()).exists());
    }
}
<|endoftext|>


<commit_before>
use imp_prelude::*;
use error::{ShapeError, ErrorKind, from_kind};

/// Stack arrays along the given axis.
pub fn stack<'a, A, D>(arrays: &[ArrayView<'a, A, D>], axis: Axis)
    -> Result<OwnedArray<A, D>, ShapeError>
    where A: Copy,
          D: Dimension + RemoveAxis
{
    let mut res_dim = arrays[0].dim().clone();
    if axis.axis() >= res_dim.slice().len() {
        return Err(from_kind(ErrorKind::OutOfBounds));
    }
    if arrays.len() == 0 {
        return Err(from_kind(ErrorKind::Unsupported));
    }
    let common_dim = res_dim.remove_axis(axis);
    if arrays.iter().any(|a| a.dim().remove_axis(axis) != common_dim) {
        return Err(from_kind(ErrorKind::IncompatibleShape));
    }

    let stacked_dim = arrays.iter()
                            .fold(0, |acc, a| acc + a.dim().index(axis));
    *res_dim.index_mut(axis) = stacked_dim;

    // we can safely use uninitialized values here because they are Copy
    // and we will only ever write to them
    let size = res_dim.size();
    let mut v = Vec::with_capacity(size);
    unsafe {
        v.set_len(size);
    }
    let mut res = try!(OwnedArray::from_vec_dim(res_dim, v));

    {
        let mut assign_view = res.view_mut();
        for array in arrays {
            let len = *array.dim().index(axis);
            let (mut front, rest) = assign_view.split_at(axis, len);
            front.assign(array);
            assign_view = rest;
        }
    }
    Ok(res)
}

#[macro_export]
macro_rules! stack {
    ($axis:expr, $( $a:expr ),+ ) => {
        ndarray::stack(&[ $($a.view() ),* ], $axis).unwrap()
    }
}
<commit_msg>clean some contrvied implemntation points<commit_after>
use imp_prelude::*;
use error::{ShapeError, ErrorKind, from_kind};

/// Stack arrays along the given axis.
pub fn stack<'a, A, D>(arrays: &[ArrayView<'a, A, D>], axis: Axis)
    -> Result<OwnedArray<A, D>, ShapeError>
    where A: Copy,
          D: Dimension + RemoveAxis
{
    let mut res_dim = arrays[0].dim();
    if axis.axis() >= res_dim.ndim() {
        return Err(from_kind(ErrorKind::OutOfBounds));
    }
    if arrays.len() == 0 {
        return Err(from_kind(ErrorKind::Unsupported));
    }
    let common_dim = res_dim.remove_axis(axis);
    if arrays.iter().any(|a| a.dim().remove_axis(axis) != common_dim) {
        return Err(from_kind(ErrorKind::IncompatibleShape));
    }

    let stacked_dim = arrays.iter()
                            .fold(0, |acc, a| acc + a.dim().index(axis));
    *res_dim.index_mut(axis) = stacked_dim;

    // we can safely use uninitialized values here because they are Copy
    // and we will only ever write to them
    let size = res_dim.size();
    let mut v = Vec::with_capacity(size);
    unsafe {
        v.set_len(size);
    }
    let mut res = try!(OwnedArray::from_vec_dim(res_dim, v));

    {
        let mut assign_view = res.view_mut();
        for array in arrays {
            let len = *array.dim().index(axis);
            let (mut front, rest) = assign_view.split_at(axis, len);
            front.assign(array);
            assign_view = rest;
        }
    }
    Ok(res)
}

#[macro_export]
macro_rules! stack {
    ($axis:expr, $( $a:expr ),+ ) => {
        ndarray::stack(&[ $($a.view() ),* ], $axis).unwrap()
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::sync::{Once, ONCE_INIT};
use std::mem;
use std::collections::HashMap;
use std::slice;
use libc::{self, c_int, c_long, c_double, size_t};
use super::{consts, err, info, opt};
use super::err::ErrCode;
use http::body::Body;
use http::{header, Response};

use curl_ffi as ffi;

pub type ProgressCb<'a> = FnMut(usize, usize, usize, usize) + 'a;

pub struct Easy {
    curl: *mut ffi::CURL
}

impl Easy {
    pub fn new() -> Easy {
        // Ensure that curl is globally initialized
        global_init();

        let handle = unsafe {
            let p = ffi::curl_easy_init();
            ffi::curl_easy_setopt(p, opt::NOPROGRESS, 0);
            p
        };

        Easy { curl: handle }
    }

    #[inline]
    pub fn setopt<T: opt::OptVal>(&mut self, option: opt::Opt, val: T) -> Result<(), err::ErrCode> {
        // TODO: Prevent setting callback related options
        let mut res = err::ErrCode(err::OK);

        unsafe {
            val.with_c_repr(|repr| {
                res = err::ErrCode(ffi::curl_easy_setopt(self.curl, option, repr));
            })
        }

        if res.is_success() { Ok(()) } else { Err(res) }
    }

    pub fn perform(&mut self,
                   body: Option<&mut Body>,
                   progress: Option<Box<ProgressCb>>)
                   -> Result<Response, err::ErrCode> {
        let mut builder = ResponseBuilder::new();

        unsafe {
            let resp_p: usize = mem::transmute(&builder);
            let body_p: usize = match body {
                Some(b) => mem::transmute(b),
                None => 0
            };

            let progress_p: usize = match progress.as_ref() {
                Some(cb) => mem::transmute(cb),
                None => 0
            };

            // Set callback options
            ffi::curl_easy_setopt(self.curl, opt::READFUNCTION, curl_read_fn);
            ffi::curl_easy_setopt(self.curl, opt::READDATA, body_p);

            ffi::curl_easy_setopt(self.curl, opt::WRITEFUNCTION, curl_write_fn);
            ffi::curl_easy_setopt(self.curl, opt::WRITEDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::HEADERFUNCTION, curl_header_fn);
            ffi::curl_easy_setopt(self.curl, opt::HEADERDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::PROGRESSFUNCTION, curl_progress_fn);
            ffi::curl_easy_setopt(self.curl, opt::PROGRESSDATA, progress_p);
        }

        let err = err::ErrCode(unsafe { ffi::curl_easy_perform(self.curl) });

        // If the request failed, abort here
        if !err.is_success() {
            return Err(err);
        }

        // Try to get the response code
        builder.code = try!(self.get_response_code());

        Ok(builder.build())
    }

    pub fn get_response_code(&self) -> Result<u32, err::ErrCode> {
        Ok(try!(self.get_info_long(info::RESPONSE_CODE)) as u32)
    }

    pub fn get_total_time(&self) -> Result<usize, err::ErrCode> {
        Ok(try!(self.get_info_long(info::TOTAL_TIME)) as usize)
    }

    fn get_info_long(&self, key: info::Key) -> Result<c_long, err::ErrCode> {
        let v: c_long = 0;
        let res = err::ErrCode(unsafe {
            ffi::curl_easy_getinfo(self.curl as *const _, key, &v)
        });

        if !res.is_success() {
            return Err(res);
        }

        Ok(v)
    }
}

#[inline]
fn global_init() {
    // Schedule curl to be cleaned up after we're done with this whole process
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| unsafe {
        assert_eq!(libc::atexit(cleanup), 0);
    });

    extern fn cleanup() {
        unsafe { ffi::curl_global_cleanup() }
    }
}

impl Drop for Easy {
    fn drop(&mut self) {
        unsafe { ffi::curl_easy_cleanup(self.curl) }
    }
}

/*
 *
 * TODO: Move this into handle
 *
 */

struct ResponseBuilder {
    code: u32,
    hdrs: HashMap<String,Vec<String>>,
    body: Vec<u8>
}

impl ResponseBuilder {
    fn new() -> ResponseBuilder {
        ResponseBuilder {
            code: 0,
            hdrs: HashMap::new(),
            body: Vec::new()
        }
    }

    fn add_header(&mut self, name: &str, val: &str) {
        // TODO: Reduce allocations
        use std::ascii::AsciiExt;
        let name = name.to_ascii_lowercase();

        let inserted = match self.hdrs.get_mut(&name) {
            Some(vals) => {
                vals.push(val.to_string());
                true
            }
            None => false
        };

        if !inserted {
            self.hdrs.insert(name, vec!(val.to_string()));
        }
    }

    fn build(self) -> Response {
        let ResponseBuilder { code, hdrs, body } = self;
        Response::new(code, hdrs, body)
    }
}

/*
 *
 * ===== Callbacks =====
 */

extern fn curl_read_fn(p: *mut u8, size: size_t, nmemb: size_t,
                       body: *mut Body) -> size_t {
    if body.is_null() {
        return 0;
    }

    let dst = unsafe { slice::from_raw_parts_mut(p, (size * nmemb) as usize) };
    let body = unsafe { &mut *body };

    match body.read(dst) {
        Ok(len) => len as size_t,
        Err(_) => consts::CURL_READFUNC_ABORT as size_t,
    }
}

extern fn curl_write_fn(p: *mut u8, size: size_t, nmemb: size_t,
                        resp: *mut ResponseBuilder) -> size_t {
    if !resp.is_null() {
        let builder: &mut ResponseBuilder = unsafe { mem::transmute(resp) };
        let chunk = unsafe { slice::from_raw_parts(p as *const u8,
                                                   (size * nmemb) as usize) };
        builder.body.extend(chunk.iter().map(|x| *x));
    }

    size * nmemb
}

extern fn curl_header_fn(p: *mut u8, size: size_t, nmemb: size_t,
                         resp: &mut ResponseBuilder) -> size_t {
    // TODO: Skip the first call (it seems to be the status line)

    let vec = unsafe { slice::from_raw_parts(p as *const u8,
                                             (size * nmemb) as usize) };

    match header::parse(&vec) {
        Some((name, val)) => {
            resp.add_header(name, val);
        }
        None => {}
    }

    vec.len() as size_t
}

pub extern "C" fn curl_progress_fn(cb: *mut Box<ProgressCb>, dltotal: c_double, dlnow: c_double, ultotal: c_double, ulnow: c_double) -> c_int {
    #[inline]
    fn to_usize(v: c_double) -> usize {
        if v > 0.0 { v as usize } else { 0 }
    }

    if !cb.is_null() {
        let cb: &mut ProgressCb = unsafe { &mut **cb };
        (*cb)(to_usize(dltotal), to_usize(dlnow), to_usize(ultotal), to_usize(ulnow));
    }

    0
}
<commit_msg>Fix build on nightly<commit_after>#![allow(dead_code)]

use std::sync::{Once, ONCE_INIT};
use std::mem;
use std::collections::HashMap;
use std::slice;
use libc::{self, c_int, c_long, c_double, size_t};
use super::{consts, err, info, opt};
use http::body::Body;
use http::{header, Response};

use curl_ffi as ffi;

pub type ProgressCb<'a> = FnMut(usize, usize, usize, usize) + 'a;

pub struct Easy {
    curl: *mut ffi::CURL
}

impl Easy {
    pub fn new() -> Easy {
        // Ensure that curl is globally initialized
        global_init();

        let handle = unsafe {
            let p = ffi::curl_easy_init();
            ffi::curl_easy_setopt(p, opt::NOPROGRESS, 0);
            p
        };

        Easy { curl: handle }
    }

    #[inline]
    pub fn setopt<T: opt::OptVal>(&mut self, option: opt::Opt, val: T) -> Result<(), err::ErrCode> {
        // TODO: Prevent setting callback related options
        let mut res = err::ErrCode(err::OK);

        unsafe {
            val.with_c_repr(|repr| {
                res = err::ErrCode(ffi::curl_easy_setopt(self.curl, option, repr));
            })
        }

        if res.is_success() { Ok(()) } else { Err(res) }
    }

    pub fn perform(&mut self,
                   body: Option<&mut Body>,
                   progress: Option<Box<ProgressCb>>)
                   -> Result<Response, err::ErrCode> {
        let mut builder = ResponseBuilder::new();

        unsafe {
            let resp_p: usize = mem::transmute(&builder);
            let body_p: usize = match body {
                Some(b) => mem::transmute(b),
                None => 0
            };

            let progress_p: usize = match progress.as_ref() {
                Some(cb) => mem::transmute(cb),
                None => 0
            };

            // Set callback options
            //
            // Use explicit `as` casts to work around rust-lang/rust#32201
            ffi::curl_easy_setopt(self.curl, opt::READFUNCTION,
                                  curl_read_fn as extern fn(_, _, _, _) -> _);
            ffi::curl_easy_setopt(self.curl, opt::READDATA, body_p);

            ffi::curl_easy_setopt(self.curl, opt::WRITEFUNCTION,
                                  curl_write_fn as extern fn(_, _, _, _) -> _);
            ffi::curl_easy_setopt(self.curl, opt::WRITEDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::HEADERFUNCTION,
                                  curl_header_fn as extern fn(_, _, _, _) -> _);
            ffi::curl_easy_setopt(self.curl, opt::HEADERDATA, resp_p);

            ffi::curl_easy_setopt(self.curl, opt::PROGRESSFUNCTION,
                                  curl_progress_fn as extern fn(_, _, _, _, _) -> _);
            ffi::curl_easy_setopt(self.curl, opt::PROGRESSDATA, progress_p);
        }

        let err = err::ErrCode(unsafe { ffi::curl_easy_perform(self.curl) });

        // If the request failed, abort here
        if !err.is_success() {
            return Err(err);
        }

        // Try to get the response code
        builder.code = try!(self.get_response_code());

        Ok(builder.build())
    }

    pub fn get_response_code(&self) -> Result<u32, err::ErrCode> {
        Ok(try!(self.get_info_long(info::RESPONSE_CODE)) as u32)
    }

    pub fn get_total_time(&self) -> Result<usize, err::ErrCode> {
        Ok(try!(self.get_info_long(info::TOTAL_TIME)) as usize)
    }

    fn get_info_long(&self, key: info::Key) -> Result<c_long, err::ErrCode> {
        let v: c_long = 0;
        let res = err::ErrCode(unsafe {
            ffi::curl_easy_getinfo(self.curl as *const _, key, &v)
        });

        if !res.is_success() {
            return Err(res);
        }

        Ok(v)
    }
}

#[inline]
fn global_init() {
    // Schedule curl to be cleaned up after we're done with this whole process
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| unsafe {
        assert_eq!(libc::atexit(cleanup), 0);
    });

    extern fn cleanup() {
        unsafe { ffi::curl_global_cleanup() }
    }
}

impl Drop for Easy {
    fn drop(&mut self) {
        unsafe { ffi::curl_easy_cleanup(self.curl) }
    }
}

/*
 *
 * TODO: Move this into handle
 *
 */

struct ResponseBuilder {
    code: u32,
    hdrs: HashMap<String,Vec<String>>,
    body: Vec<u8>
}

impl ResponseBuilder {
    fn new() -> ResponseBuilder {
        ResponseBuilder {
            code: 0,
            hdrs: HashMap::new(),
            body: Vec::new()
        }
    }

    fn add_header(&mut self, name: &str, val: &str) {
        // TODO: Reduce allocations
        use std::ascii::AsciiExt;
        let name = name.to_ascii_lowercase();

        let inserted = match self.hdrs.get_mut(&name) {
            Some(vals) => {
                vals.push(val.to_string());
                true
            }
            None => false
        };

        if !inserted {
            self.hdrs.insert(name, vec!(val.to_string()));
        }
    }

    fn build(self) -> Response {
        let ResponseBuilder { code, hdrs, body } = self;
        Response::new(code, hdrs, body)
    }
}

/*
 *
 * ===== Callbacks =====
 */

extern fn curl_read_fn(p: *mut u8, size: size_t, nmemb: size_t,
                       body: *mut Body) -> size_t {
    if body.is_null() {
        return 0;
    }

    let dst = unsafe { slice::from_raw_parts_mut(p, (size * nmemb) as usize) };
    let body = unsafe { &mut *body };

    match body.read(dst) {
        Ok(len) => len as size_t,
        Err(_) => consts::CURL_READFUNC_ABORT as size_t,
    }
}

extern fn curl_write_fn(p: *mut u8, size: size_t, nmemb: size_t,
                        resp: *mut ResponseBuilder) -> size_t {
    if !resp.is_null() {
        let builder: &mut ResponseBuilder = unsafe { mem::transmute(resp) };
        let chunk = unsafe { slice::from_raw_parts(p as *const u8,
                                                   (size * nmemb) as usize) };
        builder.body.extend(chunk.iter().map(|x| *x));
    }

    size * nmemb
}

extern fn curl_header_fn(p: *mut u8, size: size_t, nmemb: size_t,
                         resp: &mut ResponseBuilder) -> size_t {
    // TODO: Skip the first call (it seems to be the status line)

    let vec = unsafe { slice::from_raw_parts(p as *const u8,
                                             (size * nmemb) as usize) };

    match header::parse(&vec) {
        Some((name, val)) => {
            resp.add_header(name, val);
        }
        None => {}
    }

    vec.len() as size_t
}

pub extern "C" fn curl_progress_fn(cb: *mut Box<ProgressCb>, dltotal: c_double, dlnow: c_double, ultotal: c_double, ulnow: c_double) -> c_int {
    #[inline]
    fn to_usize(v: c_double) -> usize {
        if v > 0.0 { v as usize } else { 0 }
    }

    if !cb.is_null() {
        let cb: &mut ProgressCb = unsafe { &mut **cb };
        (*cb)(to_usize(dltotal), to_usize(dlnow), to_usize(ultotal), to_usize(ulnow));
    }

    0
}
<|endoftext|>


<commit_before>//! # generator
//!
//! Rust generator implementation
//!

use std::mem;
use std::thread;
use std::any::Any;
use std::boxed::FnBox;
use std::marker::PhantomData;

use yield_::yield_now;
use generator::Generator;
use rt::{Error, Context, ContextStack};
use reg_context::Context as RegContext;

// default stack size is 1k * sizeof(usize)
pub const DEFAULT_STACK_SIZE: usize = 1024;

/// Generator helper
pub struct Gn<A> {
    dummy: PhantomData<A>,
}

impl <A: Any> Gn<A> {
    /// create a new generator with default stack size
    pub fn new<'a, T: Any, F>(f: F) -> Box<Generator<A, Output = T> + 'a>
        where F: FnOnce() -> T + 'a
    {
        Self::new_opt(f, DEFAULT_STACK_SIZE)
    }

    /// create a new generator with specified stack size
    pub fn new_opt<'a, T: Any, F>(f: F, size: usize) -> Box<Generator<A, Output = T> + 'a>
        where F: FnOnce() -> T + 'a
    {
        let g = Box::new(GeneratorImpl::<A, T, F>::new(f, size));
        g.init()
    }
}

/// GeneratorImpl
pub struct GeneratorImpl<A: Any, T: Any, F>
    where F: FnOnce() -> T
{
    // run time context
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<F>,
}

impl<'a, A: Any, T: Any, F> GeneratorImpl<A, T, F>
    where F: FnOnce() -> T + 'a
{
    /// create a new generator with default stack size
    pub fn new(f: F, size: usize) -> Self {
        GeneratorImpl {
            para: None,
            ret: None,
            f: Some(f),
            context: Context::new(size),
        }
    }

    pub fn init(mut self: Box<Self>) -> Box<Self> {
        self.context.para = &mut self.para as &mut Any;
        self.context.ret = &mut self.ret as &mut Any;

        unsafe {
            let ptr = Box::into_raw(self);

            let start: Box<FnBox()> = Box::new(move || {
                let f = (*ptr).f.take().unwrap();
                (*ptr).ret = Some(f());
            });

            let stk = &mut (*ptr).context.stack;
            let reg = &mut (*ptr).context.regs;
            reg.init_with(gen_init,
                          ptr as usize,
                          Box::into_raw(Box::new(start)) as *mut usize,
                          stk.end());
            Box::from_raw(ptr)
        }
    }

    /// resume the generator
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        let cur = &mut env.top().regs;
        let ctx = &mut self.context as *mut Context;
        let to = unsafe { &mut (*ctx).regs };
        // save current generator context on stack
        env.push(ctx);
        // switch context
        RegContext::swap(cur, to);

        // check the panic status
        // this would propagate the panic until root context
        let err = self.context.err;
        if err.is_some() {
            panic!(err.unwrap());
        }
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }
}

impl<A: Any, T: Any, F> Drop for GeneratorImpl<A, T, F>
    where F: FnOnce() -> T
{
    fn drop(&mut self) {
        // when the thread is already panic, do nothing
        if thread::panicking() {
            return;
        }

        let mut i = 0;
        while !self.is_done() {
            if i > 2 {
                self.cancel();
                break;
            }
            self.raw_send(None);
            i += 1;
        }

        let (total_stack, used_stack) = self.stack_usage();
        if used_stack < total_stack {
            // here we should record the stack in the class
            // next time will just use
            // set_stack_size::<F>(used_stack);
        } else {
            error!("stack overflow detected!");
            panic!(Error::StackErr);
        }
    }
}

impl<A: Any, T: Any, F> Generator<A> for GeneratorImpl<A, T, F>
    where F: FnOnce() -> T
{
    type Output = T;

    fn raw_send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_started() && self.context._ref != 0 {
            return None;
        }

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        // use the replace is would drop the old value
        mem::replace(&mut self.para, para);

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    fn cancel(&mut self) {
        // consume the fun if it's not started
        if !self.is_started() {
            self.f.take();
            self.context._ref = 1;
        } else {
            // tell the func to panic
            // so that we can stop the inner func
            self.context._ref = 2;
            self.resume_gen();
        }
    }

    fn is_done(&self) -> bool {
        self.is_started() && self.context._ref != 0
    }

    fn stack_usage(&self) -> (usize, usize) {
        (self.context.stack.size(),
         self.context.stack.get_used_size())
    }
}

fn gen_init(_: usize, f: *mut usize) -> ! {
    {
        let f = f as usize;
        let clo = move || {
            let func: Box<Box<FnBox()>> = unsafe { Box::from_raw(f as *mut Box<FnBox()>) };
            func();
        };

        // we can't panic inside the generator context
        // need to propagate the panic to the main thread
        if let Err(cause) = thread::catch_panic(clo) {
            if cause.downcast_ref::<Error>().is_some() {
                match cause.downcast_ref::<Error>().unwrap() {
                    &Error::Cancel => {}
                    err => {
                        let ctx = ContextStack::current().top();
                        ctx.err = Some(*err);
                    }
                }
            } else {
                error!("Panicked inside: {:?}", cause.downcast::<&str>());
            }
        }
        // drop the clo here
    }

    yield_now();

    unreachable!("Should never comeback");
}
<commit_msg>refine gen_impl init<commit_after>//! # generator
//!
//! Rust generator implementation
//!

use std::mem;
use std::thread;
use std::any::Any;
use std::boxed::FnBox;
use std::marker::PhantomData;

use yield_::yield_now;
use generator::Generator;
use rt::{Error, Context, ContextStack};
use reg_context::Context as RegContext;

// default stack size is 1k * sizeof(usize)
pub const DEFAULT_STACK_SIZE: usize = 1024;

/// Generator helper
pub struct Gn<A> {
    dummy: PhantomData<A>,
}

impl <A: Any> Gn<A> {
    /// create a new generator with default stack size
    pub fn new<'a, T: Any, F>(f: F) -> Box<Generator<A, Output = T> + 'a>
        where F: FnOnce() -> T + 'a
    {
        Self::new_opt(f, DEFAULT_STACK_SIZE)
    }

    /// create a new generator with specified stack size
    pub fn new_opt<'a, T: Any, F>(f: F, size: usize) -> Box<Generator<A, Output = T> + 'a>
        where F: FnOnce() -> T + 'a
    {
        let mut g = Box::new(GeneratorImpl::<A, T, F>::new(f, size));
        g.init();
        g
    }
}

/// GeneratorImpl
pub struct GeneratorImpl<A: Any, T: Any, F>
    where F: FnOnce() -> T
{
    // run time context
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<F>,
}

impl<'a, A: Any, T: Any, F> GeneratorImpl<A, T, F>
    where F: FnOnce() -> T + 'a
{
    /// create a new generator with default stack size
    pub fn new(f: F, size: usize) -> Self {
        GeneratorImpl {
            para: None,
            ret: None,
            f: Some(f),
            context: Context::new(size),
        }
    }

    pub fn init(&mut self) {
        self.context.para = &mut self.para as &mut Any;
        self.context.ret = &mut self.ret as &mut Any;

        unsafe {
            let ptr = self as *mut Self;

            let start: Box<FnBox()> = Box::new(move || {
                let f = (*ptr).f.take().unwrap();
                (*ptr).ret = Some(f());
            });

            let stk = &mut (*ptr).context.stack;
            let reg = &mut (*ptr).context.regs;
            reg.init_with(gen_init,
                          ptr as usize,
                          Box::into_raw(Box::new(start)) as *mut usize,
                          stk.end());
        }
    }

    /// resume the generator
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        let cur = &mut env.top().regs;
        let ctx = &mut self.context as *mut Context;
        let to = unsafe { &mut (*ctx).regs };
        // save current generator context on stack
        env.push(ctx);
        // switch context
        RegContext::swap(cur, to);

        // check the panic status
        // this would propagate the panic until root context
        let err = self.context.err;
        if err.is_some() {
            panic!(err.unwrap());
        }
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }
}

impl<A: Any, T: Any, F> Drop for GeneratorImpl<A, T, F>
    where F: FnOnce() -> T
{
    fn drop(&mut self) {
        // when the thread is already panic, do nothing
        if thread::panicking() {
            return;
        }

        let mut i = 0;
        while !self.is_done() {
            if i > 2 {
                self.cancel();
                break;
            }
            self.raw_send(None);
            i += 1;
        }

        let (total_stack, used_stack) = self.stack_usage();
        if used_stack < total_stack {
            // here we should record the stack in the class
            // next time will just use
            // set_stack_size::<F>(used_stack);
        } else {
            error!("stack overflow detected!");
            panic!(Error::StackErr);
        }
    }
}

impl<A: Any, T: Any, F> Generator<A> for GeneratorImpl<A, T, F>
    where F: FnOnce() -> T
{
    type Output = T;

    fn raw_send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_started() && self.context._ref != 0 {
            return None;
        }

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        // use the replace is would drop the old value
        mem::replace(&mut self.para, para);

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    fn cancel(&mut self) {
        // consume the fun if it's not started
        if !self.is_started() {
            self.f.take();
            self.context._ref = 1;
        } else {
            // tell the func to panic
            // so that we can stop the inner func
            self.context._ref = 2;
            self.resume_gen();
        }
    }

    fn is_done(&self) -> bool {
        self.is_started() && self.context._ref != 0
    }

    fn stack_usage(&self) -> (usize, usize) {
        (self.context.stack.size(),
         self.context.stack.get_used_size())
    }
}

fn gen_init(_: usize, f: *mut usize) -> ! {
    {
        let f = f as usize;
        let clo = move || {
            let func: Box<Box<FnBox()>> = unsafe { Box::from_raw(f as *mut Box<FnBox()>) };
            func();
        };

        // we can't panic inside the generator context
        // need to propagate the panic to the main thread
        if let Err(cause) = thread::catch_panic(clo) {
            if cause.downcast_ref::<Error>().is_some() {
                match cause.downcast_ref::<Error>().unwrap() {
                    &Error::Cancel => {}
                    err => {
                        let ctx = ContextStack::current().top();
                        ctx.err = Some(*err);
                    }
                }
            } else {
                error!("Panicked inside: {:?}", cause.downcast::<&str>());
            }
        }
        // drop the clo here
    }

    yield_now();

    unreachable!("Should never comeback");
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use jsapi::{JSContext, JSObject};

pub type JSJitPropertyOp = *u8;

pub struct JSJitInfo {
    pub op: JSJitPropertyOp,
    pub protoID: u32,
    pub depth: u32,
    pub isInfallible: bool,
    pub isConstant: bool
}

extern {
pub fn JS_ObjectToOuterObject(cx: *mut JSContext,
                              obj: *mut JSObject) -> *mut JSObject;
}

//pub type JSJitInfo = JSJitInfo_struct;

#[nolink]
pub mod bindgen {
    use jsapi::{JSContext, JSObject, JSClass, JSRuntime};
    use libc::uintptr_t;

    extern {
        pub fn JS_NewObjectWithUniqueType(cx: *mut JSContext, clasp: *JSClass,
                                          proto: *mut JSObject, parent: *mut JSObject) -> *mut JSObject;
        pub fn JS_GetAddressableObject(rt: *mut JSRuntime, candidateObj: uintptr_t) -> *mut JSObject;
    }
}
<commit_msg>Remove bogus nolink attr<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use jsapi::{JSContext, JSObject};

pub type JSJitPropertyOp = *u8;

pub struct JSJitInfo {
    pub op: JSJitPropertyOp,
    pub protoID: u32,
    pub depth: u32,
    pub isInfallible: bool,
    pub isConstant: bool
}

extern {
pub fn JS_ObjectToOuterObject(cx: *mut JSContext,
                              obj: *mut JSObject) -> *mut JSObject;
}

//pub type JSJitInfo = JSJitInfo_struct;

pub mod bindgen {
    use jsapi::{JSContext, JSObject, JSClass, JSRuntime};
    use libc::uintptr_t;

    extern {
        pub fn JS_NewObjectWithUniqueType(cx: *mut JSContext, clasp: *JSClass,
                                          proto: *mut JSObject, parent: *mut JSObject) -> *mut JSObject;
        pub fn JS_GetAddressableObject(rt: *mut JSRuntime, candidateObj: uintptr_t) -> *mut JSObject;
    }
}
<|endoftext|>


<commit_before>//! `GraphMap<N, E>` is an undirected graph where node values are mapping keys.

use std::hash::{Hash};
use std::collections::HashMap;
use std::iter::Cloned;
use std::collections::hash_map::{
    Keys,
};
use std::collections::hash_map::Iter as HashmapIter;
use std::slice::{
    Iter,
};
use std::fmt;
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

use IntoWeightedEdge;

/// `GraphMap<N, E>` is an undirected graph, with generic node values `N` and edge weights `E`.
///
/// It uses an combined adjacency list and sparse adjacency matrix representation, using **O(|V|
/// + |E|)** space, and allows testing for edge existance in constant time.
///
/// The node type `N` must implement `Copy` and will be used as node identifier, duplicated
/// into several places in the data structure.
/// It must be suitable as a hash table key (implementing `Eq + Hash`).
/// The node type must also implement `Ord` so that the implementation can
/// order the pair (`a`, `b`) for an edge connecting any two nodes `a` and `b`.
///
/// `GraphMap` does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct GraphMap<N, E> {
    nodes: HashMap<N, Vec<N>>,
    edges: HashMap<(N, N), E>,
}

impl<N: Eq + Hash + fmt::Debug, E: fmt::Debug> fmt::Debug for GraphMap<N, E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.nodes.fmt(f)
    }
}

/// Use their natual order to map the node pair (a, b) to a canonical edge id.
#[inline]
fn edge_key<N: Copy + Ord>(a: N, b: N) -> (N, N) {
    if a <= b { (a, b) } else { (b, a) }
}

/// A trait group for `GraphMap`'s node identifier.
pub trait NodeTrait : Copy + Ord + Hash {}
impl<N> NodeTrait for N where N: Copy + Ord + Hash {}

impl<N, E> GraphMap<N, E>
    where N: NodeTrait
{
    /// Create a new `GraphMap`.
    pub fn new() -> Self {
        GraphMap {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    /// Create a new `GraphMap` with estimated capacity.
    pub fn with_capacity(nodes: usize, edges: usize) -> Self {
        GraphMap {
            nodes: HashMap::with_capacity(nodes),
            edges: HashMap::with_capacity(edges),
        }
    }

    /// Return the current node and edge capacity of the graph.
    pub fn capacity(&self) -> (usize, usize) {
        (self.nodes.capacity(), self.edges.capacity())
    }

    /// Create a new `GraphMap` from an iterable of edges.
    ///
    /// Node values are taken directly from the list.
    /// Edge weights `E` may either be specified in the list,
    /// or they are filled with default values.
    ///
    /// Nodes are inserted automatically to match the edges.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let gr = GraphMap::<_, ()>::from_edges(&[
    ///     (0, 1), (0, 2), (0, 3),
    ///     (1, 2), (1, 3),
    ///     (2, 3),
    /// ]);
    /// ```
    pub fn from_edges<I>(iterable: I) -> Self
        where I: IntoIterator,
              I::Item: IntoWeightedEdge<N, E>
    {
        Self::from_iter(iterable)
    }

    /// Return the number of nodes in the graph.
    pub fn node_count(&self) -> usize {
        self.nodes.len()
    }

    /// Return the number of edges in the graph.
    pub fn edge_count(&self) -> usize {
        self.edges.len()
    }

    /// Remove all nodes and edges
    pub fn clear(&mut self) {
        self.nodes.clear();
        self.edges.clear();
    }

    /// Add node `n` to the graph.
    pub fn add_node(&mut self, n: N) -> N {
        self.nodes.entry(n).or_insert_with(|| Vec::new());
        n
    }

    /// Return `true` if node `n` was removed.
    pub fn remove_node(&mut self, n: N) -> bool {
        let successors = match self.nodes.remove(&n) {
            None => return false,
            Some(sus) => sus,
        };
        for succ in successors.into_iter() {
            // remove all successor links
            self.remove_single_edge(&succ, &n);
            // Remove all edge values
            self.edges.remove(&edge_key(n, succ));
        }
        true
    }

    /// Return `true` if the node is contained in the graph.
    pub fn contains_node(&self, n: N) -> bool {
        self.nodes.contains_key(&n)
    }

    /// Add an edge connecting `a` and `b` to the graph, with associated
    /// data `weight`.
    ///
    /// Inserts nodes `a` and/or `b` if they aren't already part of the graph.
    ///
    /// Return `None` if the edge did not previously exist, otherwise,
    /// the associated data is updated and the old value is returned
    /// as `Some(old_weight)`.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    /// assert_eq!(g.node_count(), 2);
    /// assert_eq!(g.edge_count(), 1);
    /// ```
    pub fn add_edge(&mut self, a: N, b: N, weight: E) -> Option<E> {
        if let old @ Some(_) = self.edges.insert(edge_key(a, b), weight) {
            old
        } else {
            // insert in the adjacency list if it's a new edge
            self.nodes.entry(a)
                      .or_insert_with(|| Vec::with_capacity(1))
                      .push(b);
            if a != b {
                self.nodes.entry(b)
                          .or_insert_with(|| Vec::with_capacity(1))
                          .push(a);
            }
            None
        }
    }

    /// Remove successor relation from a to b
    ///
    /// Return `true` if it did exist.
    fn remove_single_edge(&mut self, a: &N, b: &N) -> bool {
        match self.nodes.get_mut(a) {
            None => false,
            Some(sus) => {
                match sus.iter().position(|elt| elt == b) {
                    Some(index) => { sus.swap_remove(index); true }
                    None => false,
                }
            }
        }
    }

    /// Remove edge from `a` to `b` from the graph and return the edge weight.
    ///
    /// Return `None` if the edge didn't exist.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    ///
    /// let edge_data = g.remove_edge(2, 1);
    /// assert_eq!(edge_data, Some(-1));
    /// assert_eq!(g.edge_count(), 0);
    /// ```
    pub fn remove_edge(&mut self, a: N, b: N) -> Option<E> {
        let exist1 = self.remove_single_edge(&a, &b);
        let exist2 = if a != b { self.remove_single_edge(&b, &a) } else { exist1 };
        let weight = self.edges.remove(&edge_key(a, b));
        debug_assert!(exist1 == exist2 && exist1 == weight.is_some());
        weight
    }

    /// Return `true` if the edge connecting `a` with `b` is contained in the graph.
    pub fn contains_edge(&self, a: N, b: N) -> bool {
        self.edges.contains_key(&edge_key(a, b))
    }

    /// Return an iterator over the nodes of the graph.
    ///
    /// Iterator element type is `N`.
    pub fn nodes(&self) -> Nodes<N> {
        Nodes{iter: self.nodes.keys().cloned()}
    }

    /// Return an iterator over the nodes that are connected with `from` by edges.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `N`.
    pub fn neighbors(&self, from: N) -> Neighbors<N> {
        Neighbors{iter:
            match self.nodes.get(&from) {
                Some(neigh) => neigh.iter(),
                None => [].iter(),
            }.cloned()
        }
    }

    /// Return an iterator over the nodes that are connected with `from` by edges,
    /// paired with the edge weight.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `(N, &E)`.
    pub fn edges(&self, from: N) -> Edges<N, E> {
        Edges {
            from: from,
            iter: self.neighbors(from),
            edges: &self.edges,
        }
    }

    /// Return a reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight(&self, a: N, b: N) -> Option<&E> {
        self.edges.get(&edge_key(a, b))
    }

    /// Return a mutable reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight_mut(&mut self, a: N, b: N) -> Option<&mut E> {
        self.edges.get_mut(&edge_key(a, b))
    }

    /// Return an iterator over all edges of the graph with their weight in arbitrary order.
    ///
    /// Iterator element type is `(N, N, &E)`
    pub fn all_edges(&self) -> AllEdges<N, E> {
        AllEdges {
            inner: self.edges.iter()
        }
    }
}

/// Create a new `GraphMap` from an iterable of edges.
impl<N, E, Item> FromIterator<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn from_iter<I>(iterable: I) -> Self
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        let mut g = Self::with_capacity(0, low);
        g.extend(iter);
        g
    }
}

/// Extend the graph from an iterable of edges.
///
/// Nodes are inserted automatically to match the edges.
impl<N, E, Item> Extend<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn extend<I>(&mut self, iterable: I)
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        self.edges.reserve(low);

        for elt in iter {
            let (source, target, weight) = elt.into_weighted_edge();
            self.add_edge(source, target, weight);
        }
    }
}

/// Utitily macro -- reinterpret passed in macro arguments as items
macro_rules! items {
    ($($item:item)*) => ($($item)*);
}

macro_rules! iterator_wrap {
    ($name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
     item: $item: ty,
     iter: $iter: ty,
     ) => (
        items! {
            pub struct $name <$($typarm),*> where $($bounds)* {
                iter: $iter,
            }
            impl<$($typarm),*> Iterator for $name <$($typarm),*>
                where $($bounds)*
            {
                type Item = $item;
                #[inline]
                fn next(&mut self) -> Option<Self::Item> {
                    self.iter.next()
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.iter.size_hint()
                }
            }
            impl<$($typarm),*> DoubleEndedIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: DoubleEndedIterator<Item=$item>,
            {
                #[inline]
                fn next_back(&mut self) -> Option<Self::Item> {
                    self.iter.next_back()
                }
            }

            impl<$($typarm),*> ExactSizeIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: ExactSizeIterator<Item=$item>,
            {
            }
        }
    );
}

iterator_wrap! {
    Nodes <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Keys<'a, N, Vec<N>>>,
}

iterator_wrap! {
    Neighbors <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Iter<'a, N>>,
}

pub struct Edges<'a, N, E: 'a> where N: 'a + NodeTrait {
    from: N,
    edges: &'a HashMap<(N, N), E>,
    iter: Neighbors<'a, N>,
}

impl<'a, N, E> Iterator for Edges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, &'a E);
    fn next(&mut self) -> Option<(N, &'a E)>
    {
        match self.iter.next() {
            None => None,
            Some(b) => {
                let a = self.from;
                match self.edges.get(&edge_key(a, b)) {
                    None => unreachable!(),
                    Some(edge) => {
                        Some((b, edge))
                    }
                }
            }
        }
    }
}

pub struct AllEdges<'a, N, E: 'a> where N: 'a + NodeTrait {
    inner: HashmapIter<'a, (N, N), E>
}

impl<'a, N, E> Iterator for AllEdges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, N, &'a E);
    fn next(&mut self) -> Option<Self::Item>
    {
        match self.inner.next() {
            None => None,
            Some((&(a, b), v)) => Some((a, b, v))
        }
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> Index<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    type Output = E;
    fn index(&self, index: (N, N)) -> &E
    {
        self.edge_weight(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> IndexMut<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    fn index_mut(&mut self, index: (N, N)) -> &mut E
    {
        self.edge_weight_mut(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}
<commit_msg>graphmap: Iterator cleanup of DEI, ESI.<commit_after>//! `GraphMap<N, E>` is an undirected graph where node values are mapping keys.

use std::hash::{Hash};
use std::collections::HashMap;
use std::iter::Cloned;
use std::collections::hash_map::{
    Keys,
};
use std::collections::hash_map::Iter as HashmapIter;
use std::slice::{
    Iter,
};
use std::fmt;
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

use IntoWeightedEdge;

/// `GraphMap<N, E>` is an undirected graph, with generic node values `N` and edge weights `E`.
///
/// It uses an combined adjacency list and sparse adjacency matrix representation, using **O(|V|
/// + |E|)** space, and allows testing for edge existance in constant time.
///
/// The node type `N` must implement `Copy` and will be used as node identifier, duplicated
/// into several places in the data structure.
/// It must be suitable as a hash table key (implementing `Eq + Hash`).
/// The node type must also implement `Ord` so that the implementation can
/// order the pair (`a`, `b`) for an edge connecting any two nodes `a` and `b`.
///
/// `GraphMap` does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct GraphMap<N, E> {
    nodes: HashMap<N, Vec<N>>,
    edges: HashMap<(N, N), E>,
}

impl<N: Eq + Hash + fmt::Debug, E: fmt::Debug> fmt::Debug for GraphMap<N, E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.nodes.fmt(f)
    }
}

/// Use their natual order to map the node pair (a, b) to a canonical edge id.
#[inline]
fn edge_key<N: Copy + Ord>(a: N, b: N) -> (N, N) {
    if a <= b { (a, b) } else { (b, a) }
}

/// A trait group for `GraphMap`'s node identifier.
pub trait NodeTrait : Copy + Ord + Hash {}
impl<N> NodeTrait for N where N: Copy + Ord + Hash {}

impl<N, E> GraphMap<N, E>
    where N: NodeTrait
{
    /// Create a new `GraphMap`.
    pub fn new() -> Self {
        GraphMap {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    /// Create a new `GraphMap` with estimated capacity.
    pub fn with_capacity(nodes: usize, edges: usize) -> Self {
        GraphMap {
            nodes: HashMap::with_capacity(nodes),
            edges: HashMap::with_capacity(edges),
        }
    }

    /// Return the current node and edge capacity of the graph.
    pub fn capacity(&self) -> (usize, usize) {
        (self.nodes.capacity(), self.edges.capacity())
    }

    /// Create a new `GraphMap` from an iterable of edges.
    ///
    /// Node values are taken directly from the list.
    /// Edge weights `E` may either be specified in the list,
    /// or they are filled with default values.
    ///
    /// Nodes are inserted automatically to match the edges.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let gr = GraphMap::<_, ()>::from_edges(&[
    ///     (0, 1), (0, 2), (0, 3),
    ///     (1, 2), (1, 3),
    ///     (2, 3),
    /// ]);
    /// ```
    pub fn from_edges<I>(iterable: I) -> Self
        where I: IntoIterator,
              I::Item: IntoWeightedEdge<N, E>
    {
        Self::from_iter(iterable)
    }

    /// Return the number of nodes in the graph.
    pub fn node_count(&self) -> usize {
        self.nodes.len()
    }

    /// Return the number of edges in the graph.
    pub fn edge_count(&self) -> usize {
        self.edges.len()
    }

    /// Remove all nodes and edges
    pub fn clear(&mut self) {
        self.nodes.clear();
        self.edges.clear();
    }

    /// Add node `n` to the graph.
    pub fn add_node(&mut self, n: N) -> N {
        self.nodes.entry(n).or_insert_with(|| Vec::new());
        n
    }

    /// Return `true` if node `n` was removed.
    pub fn remove_node(&mut self, n: N) -> bool {
        let successors = match self.nodes.remove(&n) {
            None => return false,
            Some(sus) => sus,
        };
        for succ in successors.into_iter() {
            // remove all successor links
            self.remove_single_edge(&succ, &n);
            // Remove all edge values
            self.edges.remove(&edge_key(n, succ));
        }
        true
    }

    /// Return `true` if the node is contained in the graph.
    pub fn contains_node(&self, n: N) -> bool {
        self.nodes.contains_key(&n)
    }

    /// Add an edge connecting `a` and `b` to the graph, with associated
    /// data `weight`.
    ///
    /// Inserts nodes `a` and/or `b` if they aren't already part of the graph.
    ///
    /// Return `None` if the edge did not previously exist, otherwise,
    /// the associated data is updated and the old value is returned
    /// as `Some(old_weight)`.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    /// assert_eq!(g.node_count(), 2);
    /// assert_eq!(g.edge_count(), 1);
    /// ```
    pub fn add_edge(&mut self, a: N, b: N, weight: E) -> Option<E> {
        if let old @ Some(_) = self.edges.insert(edge_key(a, b), weight) {
            old
        } else {
            // insert in the adjacency list if it's a new edge
            self.nodes.entry(a)
                      .or_insert_with(|| Vec::with_capacity(1))
                      .push(b);
            if a != b {
                self.nodes.entry(b)
                          .or_insert_with(|| Vec::with_capacity(1))
                          .push(a);
            }
            None
        }
    }

    /// Remove successor relation from a to b
    ///
    /// Return `true` if it did exist.
    fn remove_single_edge(&mut self, a: &N, b: &N) -> bool {
        match self.nodes.get_mut(a) {
            None => false,
            Some(sus) => {
                match sus.iter().position(|elt| elt == b) {
                    Some(index) => { sus.swap_remove(index); true }
                    None => false,
                }
            }
        }
    }

    /// Remove edge from `a` to `b` from the graph and return the edge weight.
    ///
    /// Return `None` if the edge didn't exist.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    ///
    /// let edge_data = g.remove_edge(2, 1);
    /// assert_eq!(edge_data, Some(-1));
    /// assert_eq!(g.edge_count(), 0);
    /// ```
    pub fn remove_edge(&mut self, a: N, b: N) -> Option<E> {
        let exist1 = self.remove_single_edge(&a, &b);
        let exist2 = if a != b { self.remove_single_edge(&b, &a) } else { exist1 };
        let weight = self.edges.remove(&edge_key(a, b));
        debug_assert!(exist1 == exist2 && exist1 == weight.is_some());
        weight
    }

    /// Return `true` if the edge connecting `a` with `b` is contained in the graph.
    pub fn contains_edge(&self, a: N, b: N) -> bool {
        self.edges.contains_key(&edge_key(a, b))
    }

    /// Return an iterator over the nodes of the graph.
    ///
    /// Iterator element type is `N`.
    pub fn nodes(&self) -> Nodes<N> {
        Nodes{iter: self.nodes.keys().cloned()}
    }

    /// Return an iterator over the nodes that are connected with `from` by edges.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `N`.
    pub fn neighbors(&self, from: N) -> Neighbors<N> {
        Neighbors{iter:
            match self.nodes.get(&from) {
                Some(neigh) => neigh.iter(),
                None => [].iter(),
            }.cloned()
        }
    }

    /// Return an iterator over the nodes that are connected with `from` by edges,
    /// paired with the edge weight.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `(N, &E)`.
    pub fn edges(&self, from: N) -> Edges<N, E> {
        Edges {
            from: from,
            iter: self.neighbors(from),
            edges: &self.edges,
        }
    }

    /// Return a reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight(&self, a: N, b: N) -> Option<&E> {
        self.edges.get(&edge_key(a, b))
    }

    /// Return a mutable reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight_mut(&mut self, a: N, b: N) -> Option<&mut E> {
        self.edges.get_mut(&edge_key(a, b))
    }

    /// Return an iterator over all edges of the graph with their weight in arbitrary order.
    ///
    /// Iterator element type is `(N, N, &E)`
    pub fn all_edges(&self) -> AllEdges<N, E> {
        AllEdges {
            inner: self.edges.iter()
        }
    }
}

/// Create a new `GraphMap` from an iterable of edges.
impl<N, E, Item> FromIterator<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn from_iter<I>(iterable: I) -> Self
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        let mut g = Self::with_capacity(0, low);
        g.extend(iter);
        g
    }
}

/// Extend the graph from an iterable of edges.
///
/// Nodes are inserted automatically to match the edges.
impl<N, E, Item> Extend<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn extend<I>(&mut self, iterable: I)
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        self.edges.reserve(low);

        for elt in iter {
            let (source, target, weight) = elt.into_weighted_edge();
            self.add_edge(source, target, weight);
        }
    }
}

/// Utitily macro -- reinterpret passed in macro arguments as items
macro_rules! items {
    ($($item:item)*) => ($($item)*);
}

macro_rules! iterator_wrap {
    ($name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
     item: $item: ty,
     iter: $iter: ty,
     ) => (
        items! {
            pub struct $name <$($typarm),*> where $($bounds)* {
                iter: $iter,
            }
            impl<$($typarm),*> Iterator for $name <$($typarm),*>
                where $($bounds)*
            {
                type Item = $item;
                #[inline]
                fn next(&mut self) -> Option<Self::Item> {
                    self.iter.next()
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.iter.size_hint()
                }
            }
        }
    );
}

iterator_wrap! {
    Nodes <'a, N> where { N: 'a + NodeTrait }
    item: N,
    iter: Cloned<Keys<'a, N, Vec<N>>>,
}

impl<'a, N: 'a + NodeTrait> ExactSizeIterator for Nodes<'a, N> { }

iterator_wrap! {
    Neighbors <'a, N> where { N: 'a + NodeTrait }
    item: N,
    iter: Cloned<Iter<'a, N>>,
}

impl<'a, N: 'a + NodeTrait> DoubleEndedIterator for Neighbors<'a, N> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iter.next_back()
    }
}

impl<'a, N: 'a + NodeTrait> ExactSizeIterator for Neighbors<'a, N> { }

pub struct Edges<'a, N, E: 'a> where N: 'a + NodeTrait {
    from: N,
    edges: &'a HashMap<(N, N), E>,
    iter: Neighbors<'a, N>,
}

impl<'a, N, E> Iterator for Edges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, &'a E);
    fn next(&mut self) -> Option<(N, &'a E)>
    {
        match self.iter.next() {
            None => None,
            Some(b) => {
                let a = self.from;
                match self.edges.get(&edge_key(a, b)) {
                    None => unreachable!(),
                    Some(edge) => {
                        Some((b, edge))
                    }
                }
            }
        }
    }
}

pub struct AllEdges<'a, N, E: 'a> where N: 'a + NodeTrait {
    inner: HashmapIter<'a, (N, N), E>
}

impl<'a, N, E> Iterator for AllEdges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, N, &'a E);
    fn next(&mut self) -> Option<Self::Item>
    {
        match self.inner.next() {
            None => None,
            Some((&(a, b), v)) => Some((a, b, v))
        }
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> Index<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    type Output = E;
    fn index(&self, index: (N, N)) -> &E
    {
        self.edge_weight(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> IndexMut<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    fn index_mut(&mut self, index: (N, N)) -> &mut E
    {
        self.edge_weight_mut(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}
<|endoftext|>


<commit_before>mod node;
mod node_children;
mod node_text;
mod text_info;

#[cfg(not(test))]
use std::{mem::size_of, sync::Arc};

pub(crate) use self::node::Node;
pub(crate) use self::node_children::NodeChildren;
pub(crate) use self::node_text::NodeText;
pub(crate) use self::text_info::TextInfo;

#[cfg(not(test))]
const PTR_SIZE: usize = size_of::<&u8>();
#[cfg(not(test))]
const CHILD_INFO_SIZE: usize = size_of::<Arc<Node>>() + size_of::<TextInfo>();

// Aim for nodes to be 1024 bytes minus Arc counters.  Keeping the nodes
// multiples of large powers of two makes it easier for the memory allocator
// to avoid fragmentation.
#[cfg(not(test))]
const TARGET_NODE_SIZE: usize = 1024 - (PTR_SIZE * 2);

// Node min/max values.
// For testing, they're set small to trigger deeper trees.  For
// non-testing, they're determined by TARGET_NODE_SIZE, above.
#[cfg(test)]
pub(crate) const MAX_CHILDREN: usize = 5;
#[cfg(not(test))]
pub(crate) const MAX_CHILDREN: usize = (TARGET_NODE_SIZE - 1) / CHILD_INFO_SIZE;
pub(crate) const MIN_CHILDREN: usize = MAX_CHILDREN - (MAX_CHILDREN / 2);

#[cfg(test)]
pub(crate) const MAX_BYTES: usize = 9; // Note: can't be 8, because 3-byte characters.
#[cfg(not(test))]
pub(crate) const MAX_BYTES: usize = TARGET_NODE_SIZE - 1 - (PTR_SIZE * 2);
pub(crate) const MIN_BYTES: usize = MAX_BYTES - (MAX_BYTES / 2);

// Type used for storing tree metadata, such as byte and char length.
pub(crate) type Count = u64;
<commit_msg>Tweaking tree parameters to better handle corner cases.<commit_after>mod node;
mod node_children;
mod node_text;
mod text_info;

#[cfg(not(test))]
use std::{mem::size_of, sync::Arc};

pub(crate) use self::node::Node;
pub(crate) use self::node_children::NodeChildren;
pub(crate) use self::node_text::NodeText;
pub(crate) use self::text_info::TextInfo;

#[cfg(not(test))]
const PTR_SIZE: usize = size_of::<&u8>();
#[cfg(not(test))]
const CHILD_INFO_SIZE: usize = size_of::<Arc<Node>>() + size_of::<TextInfo>();

// Aim for nodes to be 1024 bytes minus Arc counters.  Keeping the nodes
// multiples of large powers of two makes it easier for the memory allocator
// to avoid fragmentation.
#[cfg(not(test))]
const TARGET_NODE_SIZE: usize = 1024 - (PTR_SIZE * 2);

// Node min/max values.
// For testing, they're set small to trigger deeper trees.  For
// non-testing, they're determined by TARGET_NODE_SIZE, above.
// MAX_BYTES must be >= 4 to allow for 4-byte utf8 characters.
#[cfg(test)]
pub(crate) const MAX_CHILDREN: usize = 5;
#[cfg(not(test))]
pub(crate) const MAX_CHILDREN: usize = (TARGET_NODE_SIZE - 1) / CHILD_INFO_SIZE;
pub(crate) const MIN_CHILDREN: usize = MAX_CHILDREN / 2;

#[cfg(test)]
pub(crate) const MAX_BYTES: usize = 9; // Note: can't be 8, because 3-byte characters.
#[cfg(not(test))]
pub(crate) const MAX_BYTES: usize = TARGET_NODE_SIZE - 1 - (PTR_SIZE * 2);
// MIN_BYTES is little smaller than half MAX_BYTES so that repeated
// splitting/merging doesn't happen on alternating small insertions and
// removals.
pub(crate) const MIN_BYTES: usize = (MAX_BYTES / 2) - (MAX_BYTES / 32);

// Type used for storing tree metadata, such as byte and char length.
pub(crate) type Count = u64;
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::ops::DerefMut;
use rand::{self, ThreadRng};
use protobuf::Message;

pub use log::LogLevelFilter;
use log::{self, Log, LogMetadata, LogRecord, SetLoggerError};

pub mod codec;
pub mod macros;
pub mod logger;

pub fn init_log(level: LogLevelFilter) -> Result<(), SetLoggerError> {
    log::set_logger(|filter| {
        filter.set(level);
        Box::new(StdOutLogger { level: level })
    })
}

struct StdOutLogger {
    level: LogLevelFilter,
}

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

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}] {}", record.level(), record.args());
        }
    }
}

pub fn limit_size<T: Message + Clone>(entries: &[T], max: u64) -> Vec<T> {
    if entries.len() == 0 {
        return entries.to_vec();
    }

    let mut size = Message::compute_size(&entries[0]) as u64;
    let mut limit = 1usize;
    while limit < entries.len() {
        size += Message::compute_size(&entries[limit]) as u64;
        if size > max {
            break;
        }
        limit += 1;
    }
    entries[..limit].to_vec()
}

pub struct DefaultRng {
    rng: ThreadRng,
}

impl DefaultRng {
    fn new() -> DefaultRng {
        DefaultRng { rng: rand::thread_rng() }
    }
}

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

impl Deref for DefaultRng {
    type Target = ThreadRng;

    fn deref(&self) -> &ThreadRng {
        &self.rng
    }
}

impl DerefMut for DefaultRng {
    fn deref_mut(&mut self) -> &mut ThreadRng {
        &mut self.rng
    }
}
<commit_msg>make RwLock more friendly<commit_after>use std::ops::Deref;
use std::ops::DerefMut;
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use rand::{self, ThreadRng};
use protobuf::Message;

pub use log::LogLevelFilter;
use log::{self, Log, LogMetadata, LogRecord, SetLoggerError};

pub mod codec;
pub mod macros;
pub mod logger;

pub fn init_log(level: LogLevelFilter) -> Result<(), SetLoggerError> {
    log::set_logger(|filter| {
        filter.set(level);
        Box::new(StdOutLogger { level: level })
    })
}

struct StdOutLogger {
    level: LogLevelFilter,
}

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

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}] {}", record.level(), record.args());
        }
    }
}

pub fn limit_size<T: Message + Clone>(entries: &[T], max: u64) -> Vec<T> {
    if entries.len() == 0 {
        return entries.to_vec();
    }

    let mut size = Message::compute_size(&entries[0]) as u64;
    let mut limit = 1usize;
    while limit < entries.len() {
        size += Message::compute_size(&entries[limit]) as u64;
        if size > max {
            break;
        }
        limit += 1;
    }
    entries[..limit].to_vec()
}

pub struct DefaultRng {
    rng: ThreadRng,
}

impl DefaultRng {
    fn new() -> DefaultRng {
        DefaultRng { rng: rand::thread_rng() }
    }
}

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

impl Deref for DefaultRng {
    type Target = ThreadRng;

    fn deref(&self) -> &ThreadRng {
        &self.rng
    }
}

impl DerefMut for DefaultRng {
    fn deref_mut(&mut self) -> &mut ThreadRng {
        &mut self.rng
    }
}

pub trait HandyRwLock<T> {
    fn wl(&self) -> RwLockWriteGuard<T>;
    fn rl(&self) -> RwLockReadGuard<T>;
}

impl<T> HandyRwLock<T> for RwLock<T> {
    fn wl(&self) -> RwLockWriteGuard<T> {
        self.write().unwrap()
    }

    fn rl(&self) -> RwLockReadGuard<T> {
        self.read().unwrap()
    }
}
<|endoftext|>


<commit_before>//! Keeps `WHERE` related stuff.

use common::ToSQL;

#[derive(Clone, PartialEq, Eq)]
pub enum Operator {
    And,
    Or
}

impl Operator {
    pub fn to_sql(&self) -> &str {
        match *self {
            Operator::And => "AND",
            Operator::Or => "OR"
        }
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum WhereType<'a> {
    Simple(&'a str),
    Extended(Where<'a>),
}

/// Represents `WHERE` clause which is widely used in different queries.
#[derive(Clone, PartialEq, Eq)]
pub struct Where<'a> {
    /// Operator which will be used to join expressions
    pub operator: Operator,
    expressions: Vec<WhereType<'a>>,
}

impl<'a> Where<'a> {
    /// Method to start with.
    pub fn new(operator: Operator) -> Self {
        Where {
            operator: operator,
            expressions: vec![]
        }
    }

    /// Just an alias for `new` with pre-defined `AND` operator.
    pub fn with_and() -> Self {
        Self::new(Operator::And)
    }

    /// Just an alias for `new` with pre-defined `OR` operator.
    pub fn with_or() -> Self {
        Self::new(Operator::Or)
    }

    /// Specifies clause. Can receive either `&str` or `Where`.
    pub fn expr<T: IntoWhereType<'a>>(mut self, expression: T) -> Self {
        self.expressions.push(expression.into_where_type());
        self
    }
}

pub trait IntoWhereType<'a> {
    fn into_where_type(self) -> WhereType<'a>;
}

impl<'a> IntoWhereType<'a> for &'a str {
    fn into_where_type(self) -> WhereType<'a> {
        WhereType::Simple(self)
    }
}

impl<'a> IntoWhereType<'a> for Where<'a> {
    fn into_where_type(self) -> WhereType<'a> {
        WhereType::Extended(self)
    }
}

impl<'a> ToSQL for WhereType<'a> {
    fn to_sql(&self) -> String {
        match *self {
            WhereType::Simple(clause) => clause.to_string(),
            WhereType::Extended(ref clause) => clause.to_sql()
        }
    }
}

impl<'a> ToSQL for &'a str {
    fn to_sql(&self) -> String {
        self.to_string()
    }
}

impl<'a> ToSQL for Where<'a> {
    fn to_sql(&self) -> String {
        let operator = format!(" {} ", self.operator.to_sql());
        let mut rv = String::new();
        rv.push('(');
        rv.push_str(&self.expressions.iter()
                    .map(|x| x.to_sql())
                    .collect::<Vec<_>>()
                    .join(&operator));

        rv.push(')');
        rv
    }
}

#[cfg(test)]
mod tests {
    use super::{Operator, Where};
    use common::ToSQL;

    #[test]
    fn test_operator() {
        let and = Operator::And;
        let or = Operator::Or;

        assert_eq!(and.to_sql(), "AND");
        assert_eq!(or.to_sql(), "OR");
    }

    #[test]
    fn test_alone_where() {
        let foo = Where::new(Operator::And).expr("foo == bar").expr("fizz == bazz");
        assert_eq!(foo.to_sql(), "(foo == bar AND fizz == bazz)".to_string())
    }

    #[test]
    fn test_nested_where_clauses() {
        let clause = Where::with_or()
            .expr(Where::with_and().expr("foo == bar").expr("fizz == bazz"))
            .expr(Where::with_and().expr("a == b").expr("c == d"));

        let test_sql_string = {
            "((foo == bar AND fizz == bazz) OR \
            (a == b AND c == d))".to_string()
        };
        assert_eq!(clause.to_sql(), test_sql_string);
    }

    #[test]
    fn test_really_nested_where_clauses() {
        let foo = Where::with_and().expr("foo == bar").expr("fizz == bazz");
        let bar = Where::with_and().expr("a == b").expr("c == d");
        let bazz1 = Where::with_or().expr(foo.clone()).expr(bar.clone());
        let bazz2 = Where::with_or().expr(bar.clone()).expr(foo.clone());
        let fizz = Where::with_and().expr(bazz1).expr(bazz2);

        let test_sql_string = {
            "(((foo == bar AND fizz == bazz) OR \
            (a == b AND c == d)) AND \
            ((a == b AND c == d) OR \
            (foo == bar AND fizz == bazz)))".to_string()
        };
        assert_eq!(fizz.to_sql(), test_sql_string);
    }
}
<commit_msg>Resolved #41<commit_after>//! Keeps `WHERE` related stuff.

use common::ToSQL;

#[derive(Clone, PartialEq, Eq)]
pub enum Operator {
    And,
    Or
}

impl Operator {
    pub fn to_sql(&self) -> &str {
        match *self {
            Operator::And => "AND",
            Operator::Or => "OR"
        }
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum WhereType<'a> {
    Simple(&'a str),
    Extended(Where<'a>),
}

/// Represents `WHERE` clause which is widely used in different queries.
#[derive(Clone, PartialEq, Eq)]
pub struct Where<'a> {
    /// Operator which will be used to join expressions
    pub operator: Operator,
    expressions: Vec<WhereType<'a>>,
}

impl<'a> Where<'a> {
    /// Method to start with.
    pub fn new(operator: Operator) -> Self {
        Where {
            operator: operator,
            expressions: vec![]
        }
    }

    /// Just an alias for `new` with pre-defined `AND` operator.
    pub fn with_and() -> Self {
        Self::new(Operator::And)
    }

    /// Just an alias for `new` with pre-defined `OR` operator.
    pub fn with_or() -> Self {
        Self::new(Operator::Or)
    }

    /// Specifies clause. Can receive either `&str` or `Where`.
    pub fn expr<T: IntoWhereType<'a>>(mut self, expression: T) -> Self {
        self.expressions.push(expression.into_where_type());
        self
    }
}

pub trait IntoWhereType<'a> {
    fn into_where_type(self) -> WhereType<'a>;
}

impl<'a> IntoWhereType<'a> for &'a str {
    fn into_where_type(self) -> WhereType<'a> {
        WhereType::Simple(self)
    }
}

impl<'a> IntoWhereType<'a> for Where<'a> {
    fn into_where_type(self) -> WhereType<'a> {
        WhereType::Extended(self)
    }
}

impl<'a> ToSQL for WhereType<'a> {
    fn to_sql(&self) -> String {
        match *self {
            WhereType::Simple(clause) => clause.to_string(),
            WhereType::Extended(ref clause) => clause.to_sql()
        }
    }
}

impl<'a> ToSQL for &'a str {
    fn to_sql(&self) -> String {
        self.to_string()
    }
}

impl<'a> ToSQL for Where<'a> {
    fn to_sql(&self) -> String {
        let operator = format!(" {} ", self.operator.to_sql());
        let mut rv = String::new();
        rv.push('(');
        rv.push_str(&self.expressions.iter()
                    .map(|x| x.to_sql())
                    .collect::<Vec<_>>()
                    .join(&operator));

        rv.push(')');
        rv
    }
}

#[cfg(test)]
mod tests {
    use super::{Operator, Where};
    use common::ToSQL;

    #[test]
    fn test_operator() {
        let and = Operator::And;
        let or = Operator::Or;

        assert_eq!(and.to_sql(), "AND");
        assert_eq!(or.to_sql(), "OR");
    }

    #[test]
    fn test_alone_where() {
        let foo = Where::new(Operator::And).expr("foo = bar").expr("fizz = bazz");
        assert_eq!(foo.to_sql(), "(foo = bar AND fizz = bazz)".to_string())
    }

    #[test]
    fn test_nested_where_clauses() {
        let clause = Where::with_or()
            .expr(Where::with_and().expr("foo = bar").expr("fizz = bazz"))
            .expr(Where::with_and().expr("a = b").expr("c = d"));

        let test_sql_string = {
            "((foo = bar AND fizz = bazz) OR \
            (a = b AND c = d))".to_string()
        };
        assert_eq!(clause.to_sql(), test_sql_string);
    }

    #[test]
    fn test_really_nested_where_clauses() {
        let foo = Where::with_and().expr("foo = bar").expr("fizz = bazz");
        let bar = Where::with_and().expr("a = b").expr("c = d");
        let bazz1 = Where::with_or().expr(foo.clone()).expr(bar.clone());
        let bazz2 = Where::with_or().expr(bar.clone()).expr(foo.clone());
        let fizz = Where::with_and().expr(bazz1).expr(bazz2);

        let test_sql_string = {
            "(((foo = bar AND fizz = bazz) OR \
            (a = b AND c = d)) AND \
            ((a = b AND c = d) OR \
            (foo = bar AND fizz = bazz)))".to_string()
        };
        assert_eq!(fizz.to_sql(), test_sql_string);
    }
}
<|endoftext|>