<commit_before>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};
use noise::{Brownian2, perlin2};

const SPAWN_RATE: f64 = 0.005;
const CONSUMPTION: f64 = 0.04;
const SURVIVAL_THRESHOLD: f64 = 0.0;
const DEATH_RELEASE_COEFFICIENT: f64 = 0.5;
const INHALE_CAP: usize = 1000000;
const MOVEMENT_COST: usize = 20;

const FLUID_CYCLES: usize = 6;

const KILL_FLUID_COLOR_NORMAL: f64 = 0.01;
const SIGNAL_FLUID_COLOR_NORMAL: f64 = 0.2;
const FOOD_FLUID_COLOR_NORMAL: f64 = 180.0;

const EXPLODE_AMOUNT: f64 = 0.1;

#[derive(Debug, Clone)]
struct Mate {
    mate: (usize, usize),
    source: (usize, usize),
}

#[derive(Debug)]
struct Delta {
    movement_attempts: Vec<(usize, usize)>,
    mate_attempts: Vec<Mate>,
}

pub struct Hex {
    pub solution: Solution,
    pub cell: Option<Cell>,
    pub decision: Option<Decision>,
    delta: Delta,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        let killf = ((self.solution.fluids[2] - KILL_FLUID_NORMAL) /
                     KILL_FLUID_COLOR_NORMAL) as f32;
        let mut ocolors = [killf.abs(),
                           (self.solution.fluids[0] / FOOD_FLUID_COLOR_NORMAL) as f32,
                           0.25 * self.solution.fluids[3] as f32,
                           1.0];
        let signal_colors = [[0.0, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]];
        for i in 0..4 {
            let signalf = (((self.solution.fluids[4 + i] - SIGNAL_FLUID_NORMAL) /
                            SIGNAL_FLUID_COLOR_NORMAL) as f32)
                .abs();
            for j in 0..3 {
                ocolors[j] += signal_colors[i][j] * signalf;
            }
        }
        ocolors
    }
}

pub struct Grid {
    pub spawning: bool,
    pub width: usize,
    pub height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            spawning: true,
            width: width,
            height: height,
            tiles: randomizing_vec(width, height, rng),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        self.tiles = randomizing_vec(self.width, self.height, rng);
    }

    pub fn hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    fn hex_and_neighbors(&mut self, x: usize, y: usize) -> (&mut Hex, [&Hex; 6]) {
        (unsafe { mem::transmute(self.hex_mut(x, y)) },
         if y % 2 == 0 {
            [// UpRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height - 1) % self.height),
             // UpLeft
             self.hex(x, (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex(x, (y + self.height + 1) % self.height),
             // DownRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        } else {
            [// UpRight
             self.hex(x, (y + self.height - 1) % self.height),
             // UpLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height + 1) % self.height),
             // DownRight
             self.hex(x, (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        })
    }

    pub fn cycle(&mut self, rng: &mut Isaac64Rng) {
        if self.spawning {
            self.cycle_spawn(rng);
        }
        self.cycle_cells();
        self.cycle_decisions(rng);
        for _ in 0..FLUID_CYCLES {
            self.cycle_fluids();
        }
        self.cycle_death();
    }

    fn cycle_spawn(&mut self, rng: &mut Isaac64Rng) {
        if rng.next_f64() < SPAWN_RATE {
            let tile = rng.gen_range(0, self.width * self.height);
            if self.tiles[tile].cell.is_none() {
                self.tiles[tile].cell = Some(Cell::new(rng));
            }
        }
    }

    fn cycle_cells(&mut self) {
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                this.decision = if let Some(ref mut this_cell) = this.cell {
                    let neighbor_presents = [neighbors[0].cell.is_some(),
                                             neighbors[1].cell.is_some(),
                                             neighbors[2].cell.is_some(),
                                             neighbors[3].cell.is_some(),
                                             neighbors[4].cell.is_some(),
                                             neighbors[5].cell.is_some()];

                    Some(this_cell.decide([&this.solution.fluids,
                                           &neighbors[0].solution.fluids,
                                           &neighbors[1].solution.fluids,
                                           &neighbors[2].solution.fluids,
                                           &neighbors[3].solution.fluids,
                                           &neighbors[4].solution.fluids,
                                           &neighbors[5].solution.fluids],
                                          &neighbor_presents))
                } else {
                    None
                }
            }
        }
    }

    fn cycle_decisions(&mut self, rng: &mut Isaac64Rng) {
        // Compute the deltas resulting from the decision.
        for x in 0..self.width {
            for y in 0..self.height {
                let (width, height) = (self.width, self.height);
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                // Clear the movements from the previous cycle.
                this.delta.movement_attempts.clear();
                this.delta.mate_attempts.clear();
                this.solution.coefficients = if let Some(ref decision) = this.decision {
                    decision.coefficients
                } else {
                    // Set the diffusion coefficients to the normal values.
                    NORMAL_DIFFUSION
                };

                // Only add movements here if no cell is present.
                if this.cell.is_none() {
                    // Add any neighbor movements to the movement_attempts vector.
                    for (n, &facing) in neighbors.iter().zip(&[Direction::DownLeft,
                                                               Direction::DownRight,
                                                               Direction::Right,
                                                               Direction::UpRight,
                                                               Direction::UpLeft,
                                                               Direction::Left]) {
                        match n.decision {
                            Some(Decision { choice: Choice::Move(direction), .. }) => {
                                // It attempted to move into this hex cell.
                                if facing == direction {
                                    this.delta
                                        .movement_attempts
                                        .push(in_direction(x, y, width, height, facing.flip()));

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.movement_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Divide { mate, spawn }, .. }) => {
                                // It attempted to spawn into this hex cell.
                                if facing == spawn {
                                    let source = in_direction(x, y, width, height, facing.flip());;
                                    this.delta
                                        .mate_attempts
                                        .push(Mate {
                                            mate: in_direction(source.0,
                                                               source.1,
                                                               width,
                                                               height,
                                                               mate),
                                            source: source,
                                        });

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.mate_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Explode(way), .. }) => {
                                this.solution.diffuse[2] += if way {
                                    EXPLODE_AMOUNT
                                } else {
                                    -EXPLODE_AMOUNT
                                };
                            }
                            Some(Decision { choice: Choice::Suicide, .. }) => {
                                if let Some(ref mut c) = this.cell {
                                    c.inhale = 0;
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        // Perform the deltas.
        for x in 0..self.width {
            for y in 0..self.height {
                // Handle movement.
                if self.hex(x, y).delta.movement_attempts.len() == 1 {
                    let from_coord = self.hex(x, y).delta.movement_attempts[0];
                    self.hex_mut(x, y).cell = self.hex_mut(from_coord.0, from_coord.1).cell.take();
                    // Apply movement cost.
                    let inhale = self.hex(x, y).cell.as_ref().unwrap().inhale;
                    if inhale >= MOVEMENT_COST {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale -= MOVEMENT_COST;
                    } else {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale = 0;
                    }
                    // Handle mating.
                } else if self.hex(x, y).delta.mate_attempts.len() == 1 {
                    let mate = self.hex(x, y).delta.mate_attempts[0].clone();
                    self.hex_mut(x, y).cell = if mate.mate == (x, y) {
                        // Apply movement cost to source.
                        let inhale =
                            self.hex(mate.source.0, mate.source.1).cell.as_ref().unwrap().inhale;
                        if inhale >= MOVEMENT_COST {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale -= MOVEMENT_COST;
                        } else {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale = 0;
                        }
                        Some(self.hex_mut(mate.source.0, mate.source.1)
                            .cell
                            .as_mut()
                            .unwrap()
                            .divide(rng))
                    } else {
                        if self.hex(mate.mate.0, mate.mate.1).cell.is_some() {
                            // Apply movement cost to source.
                            let inhale = self.hex(mate.source.0, mate.source.1)
                                .cell
                                .as_ref()
                                .unwrap()
                                .inhale;
                            if inhale >= MOVEMENT_COST {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale -= MOVEMENT_COST;
                            } else {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale = 0;
                            }
                            // This is safe so long as the cells arent the same.
                            Some(unsafe {
                                    mem::transmute::<_,
                                                     &mut Hex>(self.hex_mut(mate.source.0, mate.source.1))
                                }
                                .cell
                                .as_mut()
                                .unwrap()
                                .mate(&self.hex(mate.mate.0, mate.mate.1)
                                          .cell
                                          .as_ref()
                                          .unwrap(),
                                      rng))
                        } else {
                            None
                        }
                    };
                }

                // Clear the decisions.
                self.hex_mut(x, y).decision = None;
            }
        }
    }

    fn cycle_fluids(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);

                for n in &neighbors {
                    this.solution.diffuse_from(&n.solution);
                }
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }

    fn cycle_death(&mut self) {
        // Finish the cycle.
        for hex in &mut self.tiles {
            if hex.cell.is_some() {
                if hex.solution.fluids[2] > KILL_FLUID_UPPER_THRESHOLD ||
                   hex.solution.fluids[2] < KILL_FLUID_LOWER_THRESHOLD ||
                   hex.cell.as_ref().unwrap().inhale == 0 {
                    hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                              hex.cell.as_ref().unwrap().inhale as f64;
                    hex.cell = None;
                } else if hex.solution.fluids[0] <= CONSUMPTION {
                    if hex.cell.as_ref().unwrap().inhale != 0 {
                        hex.cell.as_mut().unwrap().inhale -= 1;
                    } else {
                        hex.cell = None;
                    }
                } else {
                    hex.solution.fluids[0] -= CONSUMPTION;
                    if hex.solution.fluids[0] < SURVIVAL_THRESHOLD {
                        if hex.cell.as_ref().unwrap().inhale != 0 {
                            hex.cell.as_mut().unwrap().inhale -= 1;
                        } else {
                            hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                                      hex.cell.as_ref().unwrap().inhale as f64;
                            hex.cell = None;
                        }
                    } else {
                        if hex.cell.as_ref().unwrap().inhale < INHALE_CAP {
                            hex.cell.as_mut().unwrap().inhale += 1;
                        }
                    }
                }
            }
        }
    }
}

fn randomizing_vec(width: usize, height: usize, rng: &mut Isaac64Rng) -> Vec<Hex> {
    let seeds = [rng.gen(), rng.gen()];
    let noise = Brownian2::new(perlin2, 4).wavelength(64.0);
    (0..height)
        .cartesian_product((0..width))
        .map(|(x, y)| {
            Hex {
                solution: Solution::new([0.0,
                                         1.0,
                                         KILL_FLUID_NORMAL,
                                         noise.apply(&seeds[0], &[x as f64, y as f64]),
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL],
                                        NORMAL_DIFFUSION),
                cell: None,
                decision: None,
                delta: Delta {
                    movement_attempts: Vec::with_capacity(6),
                    mate_attempts: Vec::with_capacity(6),
                },
            }
        })
        .collect_vec()
}

fn in_direction(x: usize,
                y: usize,
                width: usize,
                height: usize,
                direction: Direction)
                -> (usize, usize) {
    let diff = direction.delta(y % 2 == 0);
    (((width + x) as isize + diff.0) as usize % width,
     ((height + y) as isize + diff.1) as usize % height)
}
<commit_msg>must be raised even more<commit_after>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};
use noise::{Brownian2, perlin2};

const SPAWN_RATE: f64 = 0.005;
const CONSUMPTION: f64 = 0.04;
const SURVIVAL_THRESHOLD: f64 = 0.0;
const DEATH_RELEASE_COEFFICIENT: f64 = 0.5;
const INHALE_CAP: usize = 1000000;
const MOVEMENT_COST: usize = 30;

const FLUID_CYCLES: usize = 6;

const KILL_FLUID_COLOR_NORMAL: f64 = 0.01;
const SIGNAL_FLUID_COLOR_NORMAL: f64 = 0.2;
const FOOD_FLUID_COLOR_NORMAL: f64 = 180.0;

const EXPLODE_AMOUNT: f64 = 0.1;

#[derive(Debug, Clone)]
struct Mate {
    mate: (usize, usize),
    source: (usize, usize),
}

#[derive(Debug)]
struct Delta {
    movement_attempts: Vec<(usize, usize)>,
    mate_attempts: Vec<Mate>,
}

pub struct Hex {
    pub solution: Solution,
    pub cell: Option<Cell>,
    pub decision: Option<Decision>,
    delta: Delta,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        let killf = ((self.solution.fluids[2] - KILL_FLUID_NORMAL) /
                     KILL_FLUID_COLOR_NORMAL) as f32;
        let mut ocolors = [killf.abs(),
                           (self.solution.fluids[0] / FOOD_FLUID_COLOR_NORMAL) as f32,
                           0.25 * self.solution.fluids[3] as f32,
                           1.0];
        let signal_colors = [[0.0, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]];
        for i in 0..4 {
            let signalf = (((self.solution.fluids[4 + i] - SIGNAL_FLUID_NORMAL) /
                            SIGNAL_FLUID_COLOR_NORMAL) as f32)
                .abs();
            for j in 0..3 {
                ocolors[j] += signal_colors[i][j] * signalf;
            }
        }
        ocolors
    }
}

pub struct Grid {
    pub spawning: bool,
    pub width: usize,
    pub height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            spawning: true,
            width: width,
            height: height,
            tiles: randomizing_vec(width, height, rng),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        self.tiles = randomizing_vec(self.width, self.height, rng);
    }

    pub fn hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    fn hex_and_neighbors(&mut self, x: usize, y: usize) -> (&mut Hex, [&Hex; 6]) {
        (unsafe { mem::transmute(self.hex_mut(x, y)) },
         if y % 2 == 0 {
            [// UpRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height - 1) % self.height),
             // UpLeft
             self.hex(x, (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex(x, (y + self.height + 1) % self.height),
             // DownRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        } else {
            [// UpRight
             self.hex(x, (y + self.height - 1) % self.height),
             // UpLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height + 1) % self.height),
             // DownRight
             self.hex(x, (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        })
    }

    pub fn cycle(&mut self, rng: &mut Isaac64Rng) {
        if self.spawning {
            self.cycle_spawn(rng);
        }
        self.cycle_cells();
        self.cycle_decisions(rng);
        for _ in 0..FLUID_CYCLES {
            self.cycle_fluids();
        }
        self.cycle_death();
    }

    fn cycle_spawn(&mut self, rng: &mut Isaac64Rng) {
        if rng.next_f64() < SPAWN_RATE {
            let tile = rng.gen_range(0, self.width * self.height);
            if self.tiles[tile].cell.is_none() {
                self.tiles[tile].cell = Some(Cell::new(rng));
            }
        }
    }

    fn cycle_cells(&mut self) {
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                this.decision = if let Some(ref mut this_cell) = this.cell {
                    let neighbor_presents = [neighbors[0].cell.is_some(),
                                             neighbors[1].cell.is_some(),
                                             neighbors[2].cell.is_some(),
                                             neighbors[3].cell.is_some(),
                                             neighbors[4].cell.is_some(),
                                             neighbors[5].cell.is_some()];

                    Some(this_cell.decide([&this.solution.fluids,
                                           &neighbors[0].solution.fluids,
                                           &neighbors[1].solution.fluids,
                                           &neighbors[2].solution.fluids,
                                           &neighbors[3].solution.fluids,
                                           &neighbors[4].solution.fluids,
                                           &neighbors[5].solution.fluids],
                                          &neighbor_presents))
                } else {
                    None
                }
            }
        }
    }

    fn cycle_decisions(&mut self, rng: &mut Isaac64Rng) {
        // Compute the deltas resulting from the decision.
        for x in 0..self.width {
            for y in 0..self.height {
                let (width, height) = (self.width, self.height);
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                // Clear the movements from the previous cycle.
                this.delta.movement_attempts.clear();
                this.delta.mate_attempts.clear();
                this.solution.coefficients = if let Some(ref decision) = this.decision {
                    decision.coefficients
                } else {
                    // Set the diffusion coefficients to the normal values.
                    NORMAL_DIFFUSION
                };

                // Only add movements here if no cell is present.
                if this.cell.is_none() {
                    // Add any neighbor movements to the movement_attempts vector.
                    for (n, &facing) in neighbors.iter().zip(&[Direction::DownLeft,
                                                               Direction::DownRight,
                                                               Direction::Right,
                                                               Direction::UpRight,
                                                               Direction::UpLeft,
                                                               Direction::Left]) {
                        match n.decision {
                            Some(Decision { choice: Choice::Move(direction), .. }) => {
                                // It attempted to move into this hex cell.
                                if facing == direction {
                                    this.delta
                                        .movement_attempts
                                        .push(in_direction(x, y, width, height, facing.flip()));

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.movement_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Divide { mate, spawn }, .. }) => {
                                // It attempted to spawn into this hex cell.
                                if facing == spawn {
                                    let source = in_direction(x, y, width, height, facing.flip());;
                                    this.delta
                                        .mate_attempts
                                        .push(Mate {
                                            mate: in_direction(source.0,
                                                               source.1,
                                                               width,
                                                               height,
                                                               mate),
                                            source: source,
                                        });

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.mate_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Explode(way), .. }) => {
                                this.solution.diffuse[2] += if way {
                                    EXPLODE_AMOUNT
                                } else {
                                    -EXPLODE_AMOUNT
                                };
                            }
                            Some(Decision { choice: Choice::Suicide, .. }) => {
                                if let Some(ref mut c) = this.cell {
                                    c.inhale = 0;
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        // Perform the deltas.
        for x in 0..self.width {
            for y in 0..self.height {
                // Handle movement.
                if self.hex(x, y).delta.movement_attempts.len() == 1 {
                    let from_coord = self.hex(x, y).delta.movement_attempts[0];
                    self.hex_mut(x, y).cell = self.hex_mut(from_coord.0, from_coord.1).cell.take();
                    // Apply movement cost.
                    let inhale = self.hex(x, y).cell.as_ref().unwrap().inhale;
                    if inhale >= MOVEMENT_COST {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale -= MOVEMENT_COST;
                    } else {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale = 0;
                    }
                    // Handle mating.
                } else if self.hex(x, y).delta.mate_attempts.len() == 1 {
                    let mate = self.hex(x, y).delta.mate_attempts[0].clone();
                    self.hex_mut(x, y).cell = if mate.mate == (x, y) {
                        // Apply movement cost to source.
                        let inhale =
                            self.hex(mate.source.0, mate.source.1).cell.as_ref().unwrap().inhale;
                        if inhale >= MOVEMENT_COST {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale -= MOVEMENT_COST;
                        } else {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale = 0;
                        }
                        Some(self.hex_mut(mate.source.0, mate.source.1)
                            .cell
                            .as_mut()
                            .unwrap()
                            .divide(rng))
                    } else {
                        if self.hex(mate.mate.0, mate.mate.1).cell.is_some() {
                            // Apply movement cost to source.
                            let inhale = self.hex(mate.source.0, mate.source.1)
                                .cell
                                .as_ref()
                                .unwrap()
                                .inhale;
                            if inhale >= MOVEMENT_COST {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale -= MOVEMENT_COST;
                            } else {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale = 0;
                            }
                            // This is safe so long as the cells arent the same.
                            Some(unsafe {
                                    mem::transmute::<_,
                                                     &mut Hex>(self.hex_mut(mate.source.0, mate.source.1))
                                }
                                .cell
                                .as_mut()
                                .unwrap()
                                .mate(&self.hex(mate.mate.0, mate.mate.1)
                                          .cell
                                          .as_ref()
                                          .unwrap(),
                                      rng))
                        } else {
                            None
                        }
                    };
                }

                // Clear the decisions.
                self.hex_mut(x, y).decision = None;
            }
        }
    }

    fn cycle_fluids(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);

                for n in &neighbors {
                    this.solution.diffuse_from(&n.solution);
                }
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }

    fn cycle_death(&mut self) {
        // Finish the cycle.
        for hex in &mut self.tiles {
            if hex.cell.is_some() {
                if hex.solution.fluids[2] > KILL_FLUID_UPPER_THRESHOLD ||
                   hex.solution.fluids[2] < KILL_FLUID_LOWER_THRESHOLD ||
                   hex.cell.as_ref().unwrap().inhale == 0 {
                    hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                              hex.cell.as_ref().unwrap().inhale as f64;
                    hex.cell = None;
                } else if hex.solution.fluids[0] <= CONSUMPTION {
                    if hex.cell.as_ref().unwrap().inhale != 0 {
                        hex.cell.as_mut().unwrap().inhale -= 1;
                    } else {
                        hex.cell = None;
                    }
                } else {
                    hex.solution.fluids[0] -= CONSUMPTION;
                    if hex.solution.fluids[0] < SURVIVAL_THRESHOLD {
                        if hex.cell.as_ref().unwrap().inhale != 0 {
                            hex.cell.as_mut().unwrap().inhale -= 1;
                        } else {
                            hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                                      hex.cell.as_ref().unwrap().inhale as f64;
                            hex.cell = None;
                        }
                    } else {
                        if hex.cell.as_ref().unwrap().inhale < INHALE_CAP {
                            hex.cell.as_mut().unwrap().inhale += 1;
                        }
                    }
                }
            }
        }
    }
}

fn randomizing_vec(width: usize, height: usize, rng: &mut Isaac64Rng) -> Vec<Hex> {
    let seeds = [rng.gen(), rng.gen()];
    let noise = Brownian2::new(perlin2, 4).wavelength(64.0);
    (0..height)
        .cartesian_product((0..width))
        .map(|(x, y)| {
            Hex {
                solution: Solution::new([0.0,
                                         1.0,
                                         KILL_FLUID_NORMAL,
                                         noise.apply(&seeds[0], &[x as f64, y as f64]),
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL],
                                        NORMAL_DIFFUSION),
                cell: None,
                decision: None,
                delta: Delta {
                    movement_attempts: Vec::with_capacity(6),
                    mate_attempts: Vec::with_capacity(6),
                },
            }
        })
        .collect_vec()
}

fn in_direction(x: usize,
                y: usize,
                width: usize,
                height: usize,
                direction: Direction)
                -> (usize, usize) {
    let diff = direction.delta(y % 2 == 0);
    (((width + x) as isize + diff.0) as usize % width,
     ((height + y) as isize + diff.1) as usize % height)
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use nom::IResult;
use std::io::{stderr, Write, ErrorKind};
use std::process;
use std::fmt;
use wires::{OffsetRadix, Options, StringExtractor};

#[derive(Debug)]
struct ZWord {
    first: u8,
    second: u8,
    third: u8,
    word_end_bit: u8
}

impl ZWord {
    pub fn to_string_with_last_byte(&self, previous_byte: u8) -> (String, u8) {
        let ZWord { first: a, second: b, third: c, .. } = *self;
        let chars = vec![
            char_from_5_bits(a, previous_byte),
            char_from_5_bits(b, a),
            char_from_5_bits(c, b)
        ];
        let s : String = chars.into_iter().collect();
        (s, c)
    }
}

pub struct ZorkStringExtractor {

}

impl ZorkStringExtractor {
    fn read_until_break(&self, bytes: &[u8], collection: &mut Vec<ZWord>) -> usize {
        let mut bytes_consumed = 0usize;
        let mut slice = bytes;
        loop {
            let result = take_z_word(slice);
            if let IResult::Done(rest, word) = result {
                bytes_consumed += 2;
                let should_break = word.word_end_bit == 1 || rest.len() <= 2;
                collection.push(word);
                slice = rest;
                if should_break { break; }
            }
        }
        bytes_consumed
    }
    fn dump_zword_vec(&self, words: &[ZWord]) -> String{
        let mut previous_byte = 0u8;
        let mut strings: Vec<String> = Vec::new();
        for word in words.iter() {
            let (string, last_byte) = word.to_string_with_last_byte(previous_byte);
            previous_byte = last_byte;
            strings.push(string);
        }

        strings.concat()
    }
}

impl StringExtractor for ZorkStringExtractor {
    fn bytes_to_strings<W: Write>(&self, bytes: &[u8], writer: &mut W, options: &Options) {
        let length = bytes.len();
        let mut offset = 0usize;
        let mut collection : Vec<ZWord> = Vec::new();

        while offset < (length - 2) {
            let bytes_consumed = self.read_until_break(&bytes[offset..], &mut collection);
            let o_string = self.offset_string(offset, options.print_offset);
            let string = self.dump_zword_vec(&collection);
            let write_result = writeln!(writer, "{}{}", o_string, string);
            if let Err(e) = write_result {
                match e.kind() {
                    ErrorKind::BrokenPipe => break,
                        _ => {
                            writeln!(stderr(), "{}", e).unwrap();
                            process::exit(1);
                        }
                }
            }
            offset += bytes_consumed;
            collection.truncate(0);
        }
    }

    fn offset_string(&self, offset: usize, radix: OffsetRadix) -> String {
        let mut output = "".to_string();
        match radix {
            OffsetRadix::Hex => fmt::write(&mut output, format_args!("0x{:X}: ", offset)).unwrap(),
            OffsetRadix::Octal => fmt::write(&mut output, format_args!("0o{:o}: ", offset)).unwrap(),
            OffsetRadix::Decimal => fmt::write(&mut output, format_args!("{}: ", offset)).unwrap(),
            OffsetRadix::None => ()
        }

        output
    }
}

named!( take_5_bits<u8>, bits!( take_bits!( u8, 5 ) ) );

named!( take_z_word<&[u8],ZWord>,
    bits!(
        do_parse!(
            word_end_bit: take_bits!( u8, 1 ) >>
            first: take_bits!( u8, 5 ) >>
            second: take_bits!( u8, 5 ) >>
            third: take_bits!( u8, 5 ) >>
            (
                ZWord {
                    first: first,
                    second: second,
                    third: third,
                    word_end_bit: word_end_bit
                }
            )
        )
    )
);

fn char_from_5_bits(fiver: u8, previous_byte: u8) -> char {

    let alphabet_table: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ];
    let uppercase_chars: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ];

    let punctuation_chars: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', '?', '\n', '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', '.', ',', '!', '?', '_', '#', '\'', '"', '/', '\\', '-', ':', '(', ')' ];

    match previous_byte {
        4u8 => uppercase_chars[fiver as usize],
        5u8 => punctuation_chars[fiver as usize],
        _ => alphabet_table[fiver as usize]
    }
}

fn read_until_break(bytes: &[u8], collection: &mut Vec<ZWord>) {
    let mut slice = bytes;
    loop {
        let result = take_z_word(slice);
        if let IResult::Done(rest, word) = result {
            let should_break = word.word_end_bit == 1 || rest.len() <= 2;
            collection.push(word);
            slice = rest;
            if should_break { break; }
        }
    }
}

#[test]
fn it_takes_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(take_5_bits( sl ), IResult::Done(&sl[1..], 21) );
}

#[test]
fn it_can_get_letter() {
    let starts_with_six = vec! [0b00110111, 0b11110000, 0b11110001];
    let sl = &starts_with_six[..];
    let expected = 'a';
    let actual = char_from_5_bits( take_5_bits(sl).to_result().unwrap() );
    assert_eq!(expected, actual);
}

#[test]
fn it_can_parse_the() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "the".to_string();
    let actual = z_string_fragment(sl);
    assert_eq!(expected, actual);
}

#[test]
fn read_until_break_breaks() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0100u8, 0b1100_1011u8, 0b0101_0101u8, 0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "thethe".to_string();
    let mut collection : Vec<ZWord> = Vec::new();
    read_until_break(sl, &mut collection);
    println!("{:?}", collection);
    let strings : Vec<String> = collection
        .into_iter()
        .map(|zword| zword.to_string())
        .collect();

    let actual = strings.concat();

    assert_eq!(expected, actual);
}<commit_msg>clean up whitespace<commit_after>#![allow(dead_code)]

use nom::IResult;
use std::io::{stderr, Write, ErrorKind};
use std::process;
use std::fmt;
use wires::{OffsetRadix, Options, StringExtractor};

#[derive(Debug)]
struct ZWord {
    first: u8,
    second: u8,
    third: u8,
    word_end_bit: u8
}

impl ZWord {
    pub fn to_string_with_last_byte(&self, previous_byte: u8) -> (String, u8) {
        let ZWord { first: a, second: b, third: c, .. } = *self;
        let chars = vec![
            char_from_5_bits(a, previous_byte),
            char_from_5_bits(b, a),
            char_from_5_bits(c, b)
        ];
        let s : String = chars.into_iter().collect();
        (s, c)
    }
}

pub struct ZorkStringExtractor {

}

impl ZorkStringExtractor {
    fn read_until_break(&self, bytes: &[u8], collection: &mut Vec<ZWord>) -> usize {
        let mut bytes_consumed = 0usize;
        let mut slice = bytes;
        loop {
            let result = take_z_word(slice);
            if let IResult::Done(rest, word) = result {
                bytes_consumed += 2;
                let should_break = word.word_end_bit == 1 || rest.len() <= 2;
                collection.push(word);
                slice = rest;
                if should_break { break; }
            }
        }
        bytes_consumed
    }

    fn dump_zword_vec(&self, words: &[ZWord]) -> String{
        let mut previous_byte = 0u8;
        let mut strings: Vec<String> = Vec::new();
        for word in words.iter() {
            let (string, last_byte) = word.to_string_with_last_byte(previous_byte);
            previous_byte = last_byte;
            strings.push(string);
        }

        strings.concat()
    }
}

impl StringExtractor for ZorkStringExtractor {
    fn bytes_to_strings<W: Write>(&self, bytes: &[u8], writer: &mut W, options: &Options) {
        let length = bytes.len();
        let mut offset = 0usize;
        let mut collection : Vec<ZWord> = Vec::new();

        while offset < (length - 2) {
            let bytes_consumed = self.read_until_break(&bytes[offset..], &mut collection);
            let o_string = self.offset_string(offset, options.print_offset);
            let string = self.dump_zword_vec(&collection);
            let write_result = writeln!(writer, "{}{}", o_string, string);
            if let Err(e) = write_result {
                match e.kind() {
                    ErrorKind::BrokenPipe => break,
                    _ => {
                        writeln!(stderr(), "{}", e).unwrap();
                        process::exit(1);
                    }
                }
            }
            offset += bytes_consumed;
            collection.truncate(0);
        }
    }

    fn offset_string(&self, offset: usize, radix: OffsetRadix) -> String {
        let mut output = "".to_string();
        match radix {
            OffsetRadix::Hex => fmt::write(&mut output, format_args!("0x{:X}: ", offset)).unwrap(),
            OffsetRadix::Octal => fmt::write(&mut output, format_args!("0o{:o}: ", offset)).unwrap(),
            OffsetRadix::Decimal => fmt::write(&mut output, format_args!("{}: ", offset)).unwrap(),
            OffsetRadix::None => ()
        }

        output
    }
}

named!( take_5_bits<u8>, bits!( take_bits!( u8, 5 ) ) );

named!( take_z_word<&[u8],ZWord>,
    bits!(
        do_parse!(
            word_end_bit: take_bits!( u8, 1 ) >>
            first: take_bits!( u8, 5 ) >>
            second: take_bits!( u8, 5 ) >>
            third: take_bits!( u8, 5 ) >>
            (
                ZWord {
                    first: first,
                    second: second,
                    third: third,
                    word_end_bit: word_end_bit
                }
            )
        )
    )
);

fn char_from_5_bits(fiver: u8, previous_byte: u8) -> char {

    let alphabet_table: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ];
    let uppercase_chars: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ];

    let punctuation_chars: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', '?', '\n', '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', '.', ',', '!', '?', '_', '#', '\'', '"', '/', '\\', '-', ':', '(', ')' ];

    match previous_byte {
        4u8 => uppercase_chars[fiver as usize],
        5u8 => punctuation_chars[fiver as usize],
        _ => alphabet_table[fiver as usize]
    }
}

fn read_until_break(bytes: &[u8], collection: &mut Vec<ZWord>) {
    let mut slice = bytes;
    loop {
        let result = take_z_word(slice);
        if let IResult::Done(rest, word) = result {
            let should_break = word.word_end_bit == 1 || rest.len() <= 2;
            collection.push(word);
            slice = rest;
            if should_break { break; }
        }
    }
}

#[test]
fn it_takes_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(take_5_bits( sl ), IResult::Done(&sl[1..], 21) );
}

#[test]
fn it_can_get_letter() {
    let starts_with_six = vec! [0b00110111, 0b11110000, 0b11110001];
    let sl = &starts_with_six[..];
    let expected = 'a';
    let actual = char_from_5_bits( take_5_bits(sl).to_result().unwrap() );
    assert_eq!(expected, actual);
}

#[test]
fn it_can_parse_the() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "the".to_string();
    let actual = z_string_fragment(sl);
    assert_eq!(expected, actual);
}

#[test]
fn read_until_break_breaks() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0100u8, 0b1100_1011u8, 0b0101_0101u8, 0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "thethe".to_string();
    let mut collection : Vec<ZWord> = Vec::new();
    read_until_break(sl, &mut collection);
    println!("{:?}", collection);
    let strings : Vec<String> = collection
        .into_iter()
        .map(|zword| zword.to_string())
        .collect();

    let actual = strings.concat();

    assert_eq!(expected, actual);
}<|endoftext|>


<commit_before>use bit_vec::BitVec;

pub fn shift(state: &mut BitVec) {
    let range = 1 .. state.len();

    for i in range.rev() {
        let pred = state[i - 1];
        state.set(i, pred);
    };

    state.set(0, false);
}

#[cfg(test)]
mod test {
    use bit_vec::BitVec;
    use super::shift;

    #[test]
    fn it_works() {
        let ref mut bv = BitVec::from_elem(4, true);

        shift(bv);
        assert!(bv.eq_vec(&[false, true, true, true]));

        shift(bv);
        assert!(bv.eq_vec(&[false, false, true, true]));

        shift(bv);
        assert!(bv.eq_vec(&[false, false, false, true]));

        shift(bv);
        assert!(bv.eq_vec(&[false, false, false, false]));

        shift(bv);
        assert!(bv.eq_vec(&[false, false, false, false]));
    }
}
<commit_msg>Fix test name<commit_after>use bit_vec::BitVec;

pub fn shift(state: &mut BitVec) {
    let range = 1 .. state.len();

    for i in range.rev() {
        let pred = state[i - 1];
        state.set(i, pred);
    };

    state.set(0, false);
}

#[cfg(test)]
mod test {
    use bit_vec::BitVec;
    use super::shift;

    #[test]
    fn shift_works() {
        let ref mut bv = BitVec::from_elem(4, true);

        shift(bv);
        assert!(bv.eq_vec(&[false, true, true, true]));

        shift(bv);
        assert!(bv.eq_vec(&[false, false, true, true]));

        shift(bv);
        assert!(bv.eq_vec(&[false, false, false, true]));

        shift(bv);
        assert!(bv.eq_vec(&[false, false, false, false]));

        shift(bv);
        assert!(bv.eq_vec(&[false, false, false, false]));
    }
}
<|endoftext|>


<commit_before>use hyper::Client;
use hyper::client::Response;
use serde_json::StreamDeserializer;
use std::io::{BufRead, BufReader, Read};
use std::sync::mpsc::{Sender, channel};
use std::thread;
use super::Error;
use super::rand;
use super::serde_json;
use super::term;
use super::url;

include!(concat!(env!("OUT_DIR"), "/logs.rs"));

const PROXY_HOST: &'static str = "http://127.0.0.1:8001";

#[derive(Debug)]
struct Record {
    namespace: String,
    pod: String,
    container: String,
    color: term::color::Color,
    text: String,
}

#[derive(Default, Debug)]
pub struct Logs {
    follow: bool,
    label: Option<String>,
    namespace: Option<String>,
}

impl Logs {
    pub fn new(follow: bool, label: Option<String>, namespace: Option<String>) -> Logs {
        Logs {
            follow: follow,
            label: label,
            namespace: namespace,
        }
    }

    pub fn fetch(&self) -> Result<(), Error> {
        let colors = vec![term::color::CYAN,
                          term::color::MAGENTA,
                          term::color::GREEN,
                          term::color::YELLOW,
                          term::color::BRIGHT_BLUE];
        let mut rng = rand::thread_rng();
        let client = Client::new();
        let mut pods_endpoint = match self.namespace {
            Some(ref ns) => {
                try!(try!(url::Url::parse(PROXY_HOST))
                    .join(&format!("/api/v1/namespaces/{}/pods", ns)))
            }
            _ => try!(try!(url::Url::parse(PROXY_HOST)).join("/api/v1/pods")),

        };
        if let Some(ref label) = self.label {
            pods_endpoint.query_pairs_mut().append_pair("labelSelector", label);
        }
        if self.follow {
            pods_endpoint.query_pairs_mut().append_pair("watch", true.to_string().as_str());
        }
        let response = try!(client.get(pods_endpoint).send());
        let (tx, rx) = channel();
        // recv records from the channel
        let mut t = term::stdout().unwrap();
        thread::spawn(move || {
            loop {
                if let Ok(Record { namespace, pod, container, color, text }) = rx.recv() {
                    t.reset().unwrap();
                    t.fg(color).unwrap();
                    write!(t, "{}/{}/{}: ", namespace, pod, container).unwrap();
                    t.reset().unwrap();
                    writeln!(t, " {}", text).unwrap();
                }
            }
        });

        fn podlogs(client: &Client,
                   follow: bool,
                   pod: Pod,
                   px: Sender<Record>,
                   color: term::color::Color)
                   -> Vec<thread::JoinHandle<()>> {
            let mut tails = vec![];
            for container in pod.spec.containers {
                let pxc = px.clone();
                let this_namespace = pod.metadata.namespace.clone();
                let this_pod_name = pod.metadata.name.clone();
                let mut logs_endpoint = url::Url::parse(PROXY_HOST)
                    .unwrap()
                    .join(&format!("/api/v1/namespaces/{}/pods/{}/log",
                                   this_namespace,
                                   this_pod_name))
                    .unwrap();
                logs_endpoint.query_pairs_mut()
                    .extend_pairs(vec![("container", container.name.as_str()),
                                       ("follow", follow.to_string().as_str())]);
                let reader = BufReader::new(client.get(logs_endpoint).send().unwrap());

                tails.push(thread::spawn(move || {
                    for l in reader.lines() {
                        if let Ok(text) = l {
                            let _ = pxc.send(Record {
                                namespace: this_namespace.clone(),
                                pod: this_pod_name.clone(),
                                container: container.name.clone(),
                                color: color,
                                text: text,
                            });
                        }
                    }
                }))
            }
            tails
        }

        if self.follow {
            let stream: StreamDeserializer<PodEvent, _> = StreamDeserializer::new(response.bytes());
            for e in stream {
                match e {
                    Ok(event) => {
                        let _ = podlogs(&client,
                                        self.follow,
                                        event.object,
                                        tx.clone(),
                                        rand::sample(&mut rng, colors.clone(), 1)[0]);
                    }
                    Err(_) => {
                        break;
                    }
                }
            }
        } else {
            let pods = try!(serde_json::from_reader::<Response, PodList>(response));
            for pod in pods.items {
                let _ = podlogs(&client,
                                self.follow,
                                pod,
                                tx.clone(),
                                rand::sample(&mut rng, colors.clone(), 1)[0]);
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>custom iterator<commit_after>use hyper::Client;
use hyper::client::Response;
use serde_json::StreamDeserializer;
use std::io;
use std::io::{BufRead, BufReader, Read};
use std::sync::mpsc::{Sender, channel};
use std::thread;
use super::Error;
use super::rand;
use super::serde_json;
use super::term;
use super::url;

include!(concat!(env!("OUT_DIR"), "/logs.rs"));

const PROXY_HOST: &'static str = "http://127.0.0.1:8001";

#[derive(Debug)]
struct Record {
    namespace: String,
    pod: String,
    container: String,
    color: term::color::Color,
    text: String,
}

#[derive(Default, Debug)]
pub struct Logs {
    follow: bool,
    label: Option<String>,
    namespace: Option<String>,
}

struct Pods {
    inner: Box<Iterator<Item = Pod>>,
}

impl Pods {
    pub fn new<Bytes>(follow: bool, bytes: Bytes) -> Result<Pods, Error>
        where Bytes: 'static + Iterator<Item = io::Result<u8>>
    {
        if follow {
            let s: StreamDeserializer<PodEvent, _> = StreamDeserializer::new(bytes);
            Ok(Pods { inner: Box::new(s.filter_map(|e| e.ok()).map(|e| e.object)) })
        } else {
            Ok(Pods {
                inner: Box::new(try!(serde_json::from_iter::<_, PodList>(bytes)).items.into_iter()),
            })
        }
    }
}
impl Iterator for Pods {
    type Item = Pod;
    fn next(&mut self) -> Option<Pod> {
        self.inner.next()
    }
}

impl Logs {
    pub fn new(follow: bool, label: Option<String>, namespace: Option<String>) -> Logs {
        Logs {
            follow: follow,
            label: label,
            namespace: namespace,
        }
    }

    pub fn fetch(&self) -> Result<(), Error> {
        let colors = vec![term::color::CYAN,
                          term::color::MAGENTA,
                          term::color::GREEN,
                          term::color::YELLOW,
                          term::color::BRIGHT_BLUE];
        let mut rng = rand::thread_rng();
        let (tx, rx) = channel();
        // recv records from the channel
        let mut t = term::stdout().unwrap();
        thread::spawn(move || {
            loop {
                if let Ok(Record { namespace, pod, container, color, text }) = rx.recv() {
                    t.reset().unwrap();
                    t.fg(color).unwrap();
                    write!(t, "{}/{}/{}: ", namespace, pod, container).unwrap();
                    t.reset().unwrap();
                    writeln!(t, " {}", text).unwrap();
                }
            }
        });

        let client = Client::new();
        let mut pods_endpoint = match self.namespace {
            Some(ref ns) => {
                try!(try!(url::Url::parse(PROXY_HOST))
                    .join(&format!("/api/v1/namespaces/{}/pods", ns)))
            }
            _ => try!(try!(url::Url::parse(PROXY_HOST)).join("/api/v1/pods")),

        };
        if let Some(ref label) = self.label {
            pods_endpoint.query_pairs_mut().append_pair("labelSelector", label);
        }
        if self.follow {
            pods_endpoint.query_pairs_mut().append_pair("watch", true.to_string().as_str());
        }
        let response = try!(client.get(pods_endpoint).send());

        for pod in try!(Pods::new(self.follow, response.bytes())) {
            let color = rand::sample(&mut rng, colors.clone(), 1)[0];
            for container in pod.spec.containers {
                let pxc = tx.clone();
                let this_namespace = pod.metadata.namespace.clone();
                let this_pod_name = pod.metadata.name.clone();
                let mut logs_endpoint = url::Url::parse(PROXY_HOST)
                    .unwrap()
                    .join(&format!("/api/v1/namespaces/{}/pods/{}/log",
                                   this_namespace,
                                   this_pod_name))
                    .unwrap();
                logs_endpoint.query_pairs_mut()
                    .extend_pairs(vec![("container", container.name.as_str()),
                                       ("follow", self.follow.to_string().as_str())]);
                let reader = BufReader::new(client.get(logs_endpoint).send().unwrap());

                thread::spawn(move || {
                    for l in reader.lines() {
                        if let Ok(text) = l {
                            let _ = pxc.send(Record {
                                namespace: this_namespace.clone(),
                                pod: this_pod_name.clone(),
                                container: container.name.clone(),
                                color: color,
                                text: text,
                            });
                        }
                    }
                });
            }
        }

        Ok(())
    }
}

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


<commit_before>#[macro_use]
extern crate glium;
extern crate cgmath;

use std::io::Read;
use std::fs::File;
use std::path::{Path, PathBuf};

use glium::{DisplayBuild, Surface};
use glium::glutin::{Event, ElementState, VirtualKeyCode};

use cgmath::{Vector3, Point3};

mod scene;
mod camera;
use camera::Camera;

/// Get the root directory of the project
fn get_project_root() -> PathBuf {
    let exe_dir = std::env::current_exe().unwrap();
    let mut parent_dir = exe_dir.parent().unwrap();
    // This fails if the executable is not in the project tree
    while !parent_dir.ends_with("rusty") {
        parent_dir = parent_dir.parent().unwrap();
    }
    parent_dir.to_path_buf()
}

/// Read a shader found at path
fn read_shader_from_file(shader_path: &Path) -> String {
    let mut file = File::open(shader_path).unwrap();
    let mut shader_src = String::new();
    file.read_to_string(&mut shader_src).unwrap();
    shader_src
}

fn main() {
    let display = glium::glutin::WindowBuilder::new().with_depth_buffer(24).build_glium().unwrap();

    let root_path = get_project_root();
    // TODO: Enable use of arbitrary scene
    let scenes = vec!("scenes/cornell/cornell.obj",
                      "scenes/cornell/cornell_chesterfield.obj",
                      "scenes/cornell-box/CornellBox-Original.obj",
                      "scenes/cornell-box/CornellBox-Glossy.obj",
                      "scenes/cornell-box/CornellBox-Water.obj",
                      "scenes/sibenik/sibenik.obj",
                      "scenes/nanosuit/nanosuit.obj");
    let mut scene = scene::load_scene(&root_path.join(scenes[0]), &display);

    let src_path = root_path.join("src");
    let vertex_shader_src = read_shader_from_file(&src_path.join("vertex.glsl"));
    let fragment_shader_src = read_shader_from_file(&src_path.join("fragment.glsl"));
    let program = glium::Program::from_source(&display, &vertex_shader_src, &fragment_shader_src, None)
        .expect("Failed to create program!");

    let params = glium::DrawParameters {
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };

    let mut camera = Camera::new(Point3::new(0.0, 0.0, -2.0), Vector3::new(0.0, 0.0, 1.0));

    loop {
        let mut target = display.draw();

        let (width, height) = target.get_dimensions();
        // TODO: Move this to camera
        let camera_to_clip = cgmath::perspective(cgmath::Rad(std::f32::consts::PI / 3.0),
                                              width as f32 / height as f32, 0.01, 1000.0f32);
        let world_to_camera = camera.get_world_to_camera();

        target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
        // Draw meshes one at a time
        for mesh in &scene.meshes {
            mesh.draw(&mut target, &program, &params, camera_to_clip * world_to_camera);
        }
        target.finish().unwrap();

        for event in display.poll_events() {
            camera.handle_event(&event);
            match event {
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Key1))
                    => scene = scene::load_scene(&root_path.join(scenes[0]), &display),
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Key2))
                    => scene = scene::load_scene(&root_path.join(scenes[1]), &display),
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Key3))
                    => scene = scene::load_scene(&root_path.join(scenes[2]), &display),
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Key4))
                    => scene = scene::load_scene(&root_path.join(scenes[3]), &display),
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Key5))
                    => scene = scene::load_scene(&root_path.join(scenes[4]), &display),
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Key6))
                    => scene = scene::load_scene(&root_path.join(scenes[5]), &display),
                Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Key7))
                    => scene = scene::load_scene(&root_path.join(scenes[6]), &display),
                Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Compress scene switch events<commit_after>#[macro_use]
extern crate glium;
extern crate cgmath;

use std::io::Read;
use std::fs::File;
use std::path::{Path, PathBuf};

use glium::{DisplayBuild, Surface};
use glium::glutin::{Event, ElementState, VirtualKeyCode};

use cgmath::{Vector3, Point3};

mod scene;
mod camera;
use camera::Camera;

/// Get the root directory of the project
fn get_project_root() -> PathBuf {
    let exe_dir = std::env::current_exe().unwrap();
    let mut parent_dir = exe_dir.parent().unwrap();
    // This fails if the executable is not in the project tree
    while !parent_dir.ends_with("rusty") {
        parent_dir = parent_dir.parent().unwrap();
    }
    parent_dir.to_path_buf()
}

/// Read a shader found at path
fn read_shader_from_file(shader_path: &Path) -> String {
    let mut file = File::open(shader_path).unwrap();
    let mut shader_src = String::new();
    file.read_to_string(&mut shader_src).unwrap();
    shader_src
}

fn main() {
    let display = glium::glutin::WindowBuilder::new().with_depth_buffer(24).build_glium().unwrap();

    let root_path = get_project_root();
    // TODO: Enable use of arbitrary scene
    let scenes = vec!("scenes/cornell/cornell.obj",
                      "scenes/cornell/cornell_chesterfield.obj",
                      "scenes/cornell-box/CornellBox-Original.obj",
                      "scenes/cornell-box/CornellBox-Glossy.obj",
                      "scenes/cornell-box/CornellBox-Water.obj",
                      "scenes/sibenik/sibenik.obj",
                      "scenes/nanosuit/nanosuit.obj");
    let mut scene = scene::load_scene(&root_path.join(scenes[0]), &display);

    let src_path = root_path.join("src");
    let vertex_shader_src = read_shader_from_file(&src_path.join("vertex.glsl"));
    let fragment_shader_src = read_shader_from_file(&src_path.join("fragment.glsl"));
    let program = glium::Program::from_source(&display, &vertex_shader_src, &fragment_shader_src, None)
        .expect("Failed to create program!");

    let params = glium::DrawParameters {
        depth: glium::Depth {
            test: glium::draw_parameters::DepthTest::IfLess,
            write: true,
            .. Default::default()
        },
        .. Default::default()
    };

    let mut camera = Camera::new(Point3::new(0.0, 0.0, -2.0), Vector3::new(0.0, 0.0, 1.0));

    loop {
        let mut target = display.draw();

        let (width, height) = target.get_dimensions();
        // TODO: Move this to camera
        let camera_to_clip = cgmath::perspective(cgmath::Rad(std::f32::consts::PI / 3.0),
                                              width as f32 / height as f32, 0.01, 1000.0f32);
        let world_to_camera = camera.get_world_to_camera();

        target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
        // Draw meshes one at a time
        for mesh in &scene.meshes {
            mesh.draw(&mut target, &program, &params, camera_to_clip * world_to_camera);
        }
        target.finish().unwrap();

        for event in display.poll_events() {
            camera.handle_event(&event);
            match event {
                // Not sure how portable this is
                Event::KeyboardInput(ElementState::Pressed, code @ 2 ... 11, _) => {
                    let i = code as usize - 2;
                    if i < scenes.len() {
                        scene = scene::load_scene(&root_path.join(scenes[i]), &display);
                    }
                }
                Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>#[crate_id = "rboy"];

extern crate native;
extern crate green;
extern crate getopts;
extern crate sync;
extern crate time;
extern crate sdl;

use cpu::CPU;
use sync::DuplexStream;
use sync::RWArc;

mod register;
mod mbc;
mod mmu;
mod cpu;
mod serial;
mod timer;
mod keypad;
mod gpu;
mod sound;
mod gbmode;

static SCALE: int = 2;

#[start]
fn start(argc: int, argv: **u8) -> int { green::start(argc, argv, main) }

fn main() {
	let args: ~[~str] = std::os::args();
	let program = args[0].clone() + " <filename>";

	let opts = ~[ getopts::optflag("s", "serial", "Output serial to stdout"), getopts::optflag("c", "classic", "Force Classic mode") ];
	let matches = match getopts::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f.to_err_msg()); return }
	};

	let filename: ~str = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		println!("{}", getopts::usage(program, opts));
		return;
	};

	sdl::init([sdl::InitVideo]);
	sdl::wm::set_caption("RBoy - A gameboy in Rust", "rboy");
	let screen = match sdl::video::set_video_mode(160*SCALE, 144*SCALE, 32, [sdl::video::HWSurface], [sdl::video::DoubleBuf]) {
		Ok(screen) => screen,
		Err(err) => fail!("failed to open screen: {}", err),
	};

	let (sdlstream, cpustream) = sync::duplex();
	let rawscreen = ~[0x00u8,.. 160*144*3];
	let arc = RWArc::new(rawscreen);
	let arc2 = arc.clone();
	native::task::spawn(proc() cpuloop(&cpustream, arc2, filename, &matches));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(8);

	'main : loop {
		periodic.recv();
		match sdlstream.try_recv() {
			std::comm::Disconnected => { break 'main },
			std::comm::Data(_) => recalculate_screen(screen, &arc),
			std::comm::Empty => {},
		}
		'event : loop {
			match sdl::event::poll_event() {
				sdl::event::QuitEvent => break 'main,
				sdl::event::NoEvent => break 'event,
				sdl::event::KeyEvent(sdl::event::EscapeKey, _, _, _)
					=> break 'main,
				sdl::event::KeyEvent(sdl::event::LShiftKey, true, _, _)
					=> sdlstream.send(SpeedUp),
				sdl::event::KeyEvent(sdl::event::LShiftKey, false, _, _)
					=> sdlstream.send(SlowDown),
				sdl::event::KeyEvent(sdlkey, true, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdlstream.send(KeyDown(key)),
						None => {},
					}
				},
				sdl::event::KeyEvent(sdlkey, false, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdlstream.send(KeyUp(key)),
						None => {},
					}
				},
				_ => {}
			}
		}
	}
}

fn sdl_to_keypad(key: sdl::event::Key) -> Option<keypad::KeypadKey> {
	match key {
		sdl::event::ZKey => Some(keypad::A),
		sdl::event::XKey => Some(keypad::B),
		sdl::event::UpKey => Some(keypad::Up),
		sdl::event::DownKey => Some(keypad::Down),
		sdl::event::LeftKey => Some(keypad::Left),
		sdl::event::RightKey => Some(keypad::Right),
		sdl::event::SpaceKey => Some(keypad::Select),
		sdl::event::ReturnKey => Some(keypad::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl::video::Surface, arc: &RWArc<~[u8]>) {
	arc.read(|data|
		for y in range(0, 144) {
			for x in range(0, 160) {
				screen.fill_rect(
					Some(sdl::Rect { x: (x*SCALE) as i16, y: (y*SCALE) as i16, w: SCALE as u16, h: SCALE as u16 }),
					sdl::video::RGB(data[y*160*3 + x*3 + 0],
					                data[y*160*3 + x*3 + 1],
					                data[y*160*3 + x*3 + 2])
				);
			}
		}
	);
	screen.flip();
}

enum GBEvent {
	KeyUp(keypad::KeypadKey),
	KeyDown(keypad::KeypadKey),
	SpeedUp,
	SlowDown,
}

fn cpuloop(channel: &DuplexStream<uint, GBEvent>, arc: RWArc<~[u8]>, filename: ~str, matches: &getopts::Matches) {
	let mut c = match matches.opt_present("classic") {
		true => CPU::new(filename),
		false => CPU::new_cgb(filename),
	};
	c.mmu.serial.tostdout = matches.opt_present("serial");

	let mut timer = std::io::timer::Timer::new().unwrap();
	let mut periodic = timer.periodic(8);

	let waitticks = (4194.304 * 4.0) as uint;

	let mut ticks = 0;
	loop {
		while ticks < waitticks {
			ticks += c.cycle();
			if c.mmu.gpu.updated {
				c.mmu.gpu.updated = false;
				arc.write(|data|
					for i in range(0, data.len()) { data[i] = c.mmu.gpu.data[i]; }
				);
				channel.try_send(0);
			}
		}
		ticks -= waitticks;
		periodic.recv();

		match channel.try_recv() {
			std::comm::Data(event) => match event {
				KeyUp(key) => c.mmu.keypad.keyup(key),
				KeyDown(key) => c.mmu.keypad.keydown(key),
				SpeedUp => periodic = timer.periodic(1),
				SlowDown => periodic = timer.periodic(8),
			},
			std::comm::Empty => {},
			std::comm::Disconnected => { break },
		};
	}
}
<commit_msg>Logging moved to its own crate<commit_after>#[crate_id = "rboy"];

#[feature(phase)];
#[phase(syntax, link)] extern crate log;

extern crate native;
extern crate green;
extern crate getopts;
extern crate sync;
extern crate time;
extern crate sdl;

use cpu::CPU;
use sync::DuplexStream;
use sync::RWArc;

mod register;
mod mbc;
mod mmu;
mod cpu;
mod serial;
mod timer;
mod keypad;
mod gpu;
mod sound;
mod gbmode;

static SCALE: int = 2;

#[start]
fn start(argc: int, argv: **u8) -> int { green::start(argc, argv, main) }

fn main() {
	let args: ~[~str] = std::os::args();
	let program = args[0].clone() + " <filename>";

	let opts = ~[ getopts::optflag("s", "serial", "Output serial to stdout"), getopts::optflag("c", "classic", "Force Classic mode") ];
	let matches = match getopts::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f.to_err_msg()); return }
	};

	let filename: ~str = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		println!("{}", getopts::usage(program, opts));
		return;
	};

	sdl::init([sdl::InitVideo]);
	sdl::wm::set_caption("RBoy - A gameboy in Rust", "rboy");
	let screen = match sdl::video::set_video_mode(160*SCALE, 144*SCALE, 32, [sdl::video::HWSurface], [sdl::video::DoubleBuf]) {
		Ok(screen) => screen,
		Err(err) => fail!("failed to open screen: {}", err),
	};

	let (sdlstream, cpustream) = sync::duplex();
	let rawscreen = ~[0x00u8,.. 160*144*3];
	let arc = RWArc::new(rawscreen);
	let arc2 = arc.clone();
	native::task::spawn(proc() cpuloop(&cpustream, arc2, filename, &matches));

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(8);

	'main : loop {
		periodic.recv();
		match sdlstream.try_recv() {
			std::comm::Disconnected => { break 'main },
			std::comm::Data(_) => recalculate_screen(screen, &arc),
			std::comm::Empty => {},
		}
		'event : loop {
			match sdl::event::poll_event() {
				sdl::event::QuitEvent => break 'main,
				sdl::event::NoEvent => break 'event,
				sdl::event::KeyEvent(sdl::event::EscapeKey, _, _, _)
					=> break 'main,
				sdl::event::KeyEvent(sdl::event::LShiftKey, true, _, _)
					=> sdlstream.send(SpeedUp),
				sdl::event::KeyEvent(sdl::event::LShiftKey, false, _, _)
					=> sdlstream.send(SlowDown),
				sdl::event::KeyEvent(sdlkey, true, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdlstream.send(KeyDown(key)),
						None => {},
					}
				},
				sdl::event::KeyEvent(sdlkey, false, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdlstream.send(KeyUp(key)),
						None => {},
					}
				},
				_ => {}
			}
		}
	}
}

fn sdl_to_keypad(key: sdl::event::Key) -> Option<keypad::KeypadKey> {
	match key {
		sdl::event::ZKey => Some(keypad::A),
		sdl::event::XKey => Some(keypad::B),
		sdl::event::UpKey => Some(keypad::Up),
		sdl::event::DownKey => Some(keypad::Down),
		sdl::event::LeftKey => Some(keypad::Left),
		sdl::event::RightKey => Some(keypad::Right),
		sdl::event::SpaceKey => Some(keypad::Select),
		sdl::event::ReturnKey => Some(keypad::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl::video::Surface, arc: &RWArc<~[u8]>) {
	arc.read(|data|
		for y in range(0, 144) {
			for x in range(0, 160) {
				screen.fill_rect(
					Some(sdl::Rect { x: (x*SCALE) as i16, y: (y*SCALE) as i16, w: SCALE as u16, h: SCALE as u16 }),
					sdl::video::RGB(data[y*160*3 + x*3 + 0],
					                data[y*160*3 + x*3 + 1],
					                data[y*160*3 + x*3 + 2])
				);
			}
		}
	);
	screen.flip();
}

enum GBEvent {
	KeyUp(keypad::KeypadKey),
	KeyDown(keypad::KeypadKey),
	SpeedUp,
	SlowDown,
}

fn cpuloop(channel: &DuplexStream<uint, GBEvent>, arc: RWArc<~[u8]>, filename: ~str, matches: &getopts::Matches) {
	let mut c = match matches.opt_present("classic") {
		true => CPU::new(filename),
		false => CPU::new_cgb(filename),
	};
	c.mmu.serial.tostdout = matches.opt_present("serial");

	let mut timer = std::io::timer::Timer::new().unwrap();
	let mut periodic = timer.periodic(8);

	let waitticks = (4194.304 * 4.0) as uint;

	let mut ticks = 0;
	loop {
		while ticks < waitticks {
			ticks += c.cycle();
			if c.mmu.gpu.updated {
				c.mmu.gpu.updated = false;
				arc.write(|data|
					for i in range(0, data.len()) { data[i] = c.mmu.gpu.data[i]; }
				);
				channel.try_send(0);
			}
		}
		ticks -= waitticks;
		periodic.recv();

		match channel.try_recv() {
			std::comm::Data(event) => match event {
				KeyUp(key) => c.mmu.keypad.keyup(key),
				KeyDown(key) => c.mmu.keypad.keydown(key),
				SpeedUp => periodic = timer.periodic(1),
				SlowDown => periodic = timer.periodic(8),
			},
			std::comm::Empty => {},
			std::comm::Disconnected => { break },
		};
	}
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io;
use std::io::Write;

#[derive(Debug)]
enum Expr {
    Numeral(i64),
    Plus(Box<Expr>, Box<Expr>),
    Minus(Box<Expr>, Box<Expr>),
    Times(Box<Expr>, Box<Expr>),
    Divide(Box<Expr>, Box<Expr>),
    Negate(Box<Expr>),
}

#[derive(Debug)]
enum Tok {
    Numeral(i64),
    Plus,
    Minus,
    Times,
    Divide,
    Lparen,
    Rparen
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expr::Numeral(i) => write!(f, "{}", i),
            &Expr::Plus(ref i, ref j) => write!(f, "{} + {}", i, j),
            &Expr::Minus(ref i, ref j) => write!(f, "{} - {}", i, j),
            &Expr::Times(ref i, ref j) => write!(f, "{} * {}", i, j),
            &Expr::Divide(ref i, ref j) => write!(f, "{} / {}", i, j),
            &Expr::Negate(ref i) => write!(f, "-{}", i),
        }
    }
}

fn eval(expr: Expr) -> i64 {
    match expr {
        Expr::Numeral(i) => i,
        Expr::Plus(i, j) => eval(*i) + eval(*j),
        Expr::Minus(i, j) => eval(*i) - eval(*j),
        Expr::Times(i, j) => eval(*i) * eval(*j),
        Expr::Divide(i, j) => eval(*i) / eval(*j),
        Expr::Negate(i) => eval(*i) * -1,
    }
}

fn char_is_digit(c: &char) -> bool {
    *c == '0' || *c == '1' || *c == '2' || *c == '3' || *c == '4' || *c == '5' || *c == '6' || *c == '7' || *c == '8' || *c == '9'
}

fn lex(line: &str) -> Vec<Tok> {
    let mut toks = vec![];
    let mut iter = line.chars().peekable();

    while let Some(c) = iter.next() {
        if c == ' ' {
            // do nothing
        } else if c == '+' {
            toks.push(Tok::Plus);
        } else if c == '-' {
            toks.push(Tok::Minus);
        } else if c == '*' {
            toks.push(Tok::Times);
        } else if c == '/' {
            toks.push(Tok::Divide);
        } else if c == '(' {
            toks.push(Tok::Lparen);
        } else if c == ')' {
            toks.push(Tok::Rparen);
        } else if char_is_digit(&c) {
            let mut ingesting_numeral = true;
            let mut numeral: Vec<char> = vec![];
            numeral.push(c);

            while ingesting_numeral {
                if let Some(c_digit) = iter.peek() {
                    if char_is_digit(c_digit) {
                        numeral.push(*c_digit);
                    } else {
                        ingesting_numeral = false;
                    }
                } else {
                    ingesting_numeral = false;
                }

                if ingesting_numeral {
                    iter.next();
                }
            }

            let n: String = numeral.iter().cloned().collect();
            if let Ok(i) = n.parse::<i64>() {
                toks.push(Tok::Numeral(i));
            }
        }
    }

    toks
}

fn main() {
    println!("Welcome to calc!");
    loop {
        print!("     > ");
        if let Err(x) = io::stdout().flush() {
            println!("could not flush: {}", x);
        }
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("Could not read line.");
        let lexed = lex(&input);
        println!("{:?}", lexed);
    }
}
<commit_msg>It works! Finish parsing, add to repl after lexing<commit_after>use std::fmt;
use std::io;
use std::io::Write;

#[derive(Debug)]
enum Expr {
    Numeral(i64),
    Plus(Box<Expr>, Box<Expr>),
    Minus(Box<Expr>, Box<Expr>),
    Times(Box<Expr>, Box<Expr>),
    Divide(Box<Expr>, Box<Expr>),
    Negate(Box<Expr>),
}

#[derive(Debug)]
enum Tok {
    Numeral(i64),
    Plus,
    Minus,
    Times,
    Divide,
    Lparen,
    Rparen,
    Eof,
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expr::Numeral(i) => write!(f, "{}", i),
            &Expr::Plus(ref i, ref j) => write!(f, "{} + {}", i, j),
            &Expr::Minus(ref i, ref j) => write!(f, "{} - {}", i, j),
            &Expr::Times(ref i, ref j) => write!(f, "{} * {}", i, j),
            &Expr::Divide(ref i, ref j) => write!(f, "{} / {}", i, j),
            &Expr::Negate(ref i) => write!(f, "-{}", i),
        }
    }
}

fn eval(expr: Expr) -> i64 {
    match expr {
        Expr::Numeral(i) => i,
        Expr::Plus(i, j) => eval(*i) + eval(*j),
        Expr::Minus(i, j) => eval(*i) - eval(*j),
        Expr::Times(i, j) => eval(*i) * eval(*j),
        Expr::Divide(i, j) => eval(*i) / eval(*j),
        Expr::Negate(i) => eval(*i) * -1,
    }
}

fn char_is_digit(c: &char) -> bool {
    *c == '0' || *c == '1' || *c == '2' || *c == '3' || *c == '4' || *c == '5' || *c == '6' || *c == '7' || *c == '8' || *c == '9'
}

fn lex(line: &str) -> Vec<Tok> {
    let mut toks = vec![];
    let mut iter = line.chars().peekable();

    while let Some(c) = iter.next() {
        if c == ' ' {
            // do nothing
        } else if c == '+' {
            toks.push(Tok::Plus);
        } else if c == '-' {
            toks.push(Tok::Minus);
        } else if c == '*' {
            toks.push(Tok::Times);
        } else if c == '/' {
            toks.push(Tok::Divide);
        } else if c == '(' {
            toks.push(Tok::Lparen);
        } else if c == ')' {
            toks.push(Tok::Rparen);
        } else if char_is_digit(&c) {
            let mut ingesting_numeral = true;
            let mut numeral: Vec<char> = vec![];
            numeral.push(c);

            while ingesting_numeral {
                if let Some(c_digit) = iter.peek() {
                    if char_is_digit(c_digit) {
                        numeral.push(*c_digit);
                    } else {
                        ingesting_numeral = false;
                    }
                } else {
                    ingesting_numeral = false;
                }

                if ingesting_numeral {
                    iter.next();
                }
            }

            let n: String = numeral.iter().cloned().collect();
            if let Ok(i) = n.parse::<i64>() {
                toks.push(Tok::Numeral(i));
            }
        }
    }

    toks.push(Tok::Eof);
    toks
}

/*
    recursive descent with operator precedence climbing
*/
fn parse(toks: &Vec<Tok>) -> Result<Expr, &'static str> {
    if toks.len() == 0 {
        return Err("Can't parse; no tokens.");
    }

    let mut current_token: usize = 0;

    parse_expr(toks, &mut current_token)
}

fn parse_expr(toks: &Vec<Tok>, current_token: &mut usize) -> Result<Expr, &'static str> {
    let lhs = try!(parse_primary(toks, current_token));
    parse_binary_ops_rhs(toks, current_token, 0, lhs)
}

fn parse_primary(toks: &Vec<Tok>, current_token: &mut usize) -> Result<Expr, &'static str> {
    let tok = try!(get_token(toks, current_token));
    match *tok {
        Tok::Minus => parse_negate(toks, current_token),
        Tok::Numeral(_) => parse_numeral(toks, current_token),
        Tok::Lparen => parse_paren(toks, current_token),
        _ => Err("Only negation, parens, or numerals are primary expressions.")
    }
}

fn parse_binary_ops_rhs(toks: &Vec<Tok>, current_token: &mut usize, expr_precedence: i8, mut left_expr: Expr) -> Result<Expr, &'static str> {
    loop {
        let tok = try!(get_token(toks, current_token));
        let tok_precedence = op_precedence(tok);

        if tok_precedence < expr_precedence {
            return Ok(left_expr)
        } else {
            // since non binary operators have negative precedence, tok is a binary op here.
            eat_token(current_token); // eat binop
            let mut right_expr = try!(parse_primary(toks, current_token));

            // If BinOp binds less tightly with RHS than the operator after RHS, let
            // the pending operator take RHS as its LHS.

            let next_op = try!(get_token(toks, current_token));
            let next_prec = op_precedence(next_op);
            if tok_precedence < next_prec {
                right_expr = try!(parse_binary_ops_rhs(toks, current_token, expr_precedence + 1, right_expr))
            }

            left_expr = binary_op_expr(tok, left_expr, right_expr)
        }
    }
}

fn binary_op_expr(binary_op: &Tok, lhs: Expr, rhs: Expr) -> Expr {
    match *binary_op {
        Tok::Plus => Expr::Plus(Box::new(lhs), Box::new(rhs)),
        Tok::Minus => Expr::Minus(Box::new(lhs), Box::new(rhs)),
        Tok::Times => Expr::Times(Box::new(lhs), Box::new(rhs)),
        Tok::Divide => Expr::Divide(Box::new(lhs), Box::new(rhs)),
        _ => unreachable!()
    }
}

// Expects toks[current_token] to be a Tok::Numeral, panics otherwise
fn parse_numeral(toks: &Vec<Tok>, current_token: &mut usize) -> Result<Expr, &'static str> {
    let tok = try!(get_token(toks, current_token));

    match *tok {
        Tok::Numeral(i) => {
            eat_token(current_token); // eat numeral
            Ok(Expr::Numeral(i))
        },
        _ => unreachable!()
    }
}

fn parse_paren(toks: &Vec<Tok>, current_token: &mut usize) -> Result<Expr, &'static str> {
    eat_token(current_token); // eat left paren

    let expr = try!(parse_expr(toks, current_token));

    let tok = try!(get_token(toks, current_token));
    match *tok {
        Tok::Rparen => {
            eat_token(current_token); // eat right paren
            Ok(expr)
        },
        _ => Err("Unmatched left parenthesis."),
    }
}

fn parse_negate(toks: &Vec<Tok>, current_token: &mut usize) -> Result<Expr, &'static str> {
    eat_token(current_token); // eat minus

    let tok = try!(get_token(toks, current_token));
    match *tok {
        Tok::Numeral(i) => {
            eat_token(current_token); // eat numeral
            Ok(Expr::Negate(Box::new(Expr::Numeral(i))))
        },
        _ => Err("Can't negate anything but a numeral.")
    }
}

fn op_precedence(tok: &Tok) -> i8 {
    match *tok {
        Tok::Numeral(_) => -1,
        Tok::Plus => 10,
        Tok::Minus => 10,
        Tok::Times => 20,
        Tok::Divide => 20,
        Tok::Lparen => -1,
        Tok::Rparen => -1,
        Tok::Eof => -1,
    }
}

fn eat_token(current_token: &mut usize) {
    *current_token += 1;
}

fn get_token<'a, 'b>(toks: &'a Vec<Tok>, current_token: &'b mut usize) -> Result<&'a Tok, &'static str> {
    if let Some(tok) = toks.get(*current_token) {
        Ok(tok)
    } else {
        Err("Attempted to get token but there are no more.")
    }
}

fn main() {
    println!("Welcome to calc!");
    loop {
        print!("     > ");
        if let Err(x) = io::stdout().flush() {
            println!("could not flush: {}", x);
        }
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("Could not read line.");
        let lexed = lex(&input);
        match parse(&lexed) {
            Ok(parsed) => {
                println!("{:?}", parsed);
                println!("{}", eval(parsed));
            },
            Err(msg) => {
                println!("{}", msg);
            }
        }
    }
}
<|endoftext|>


<commit_before>
extern crate chrono;
extern crate docopt;

use std::process::Command;

use std::io::prelude::*;
use std::net::TcpStream;

use docopt::Docopt;

extern crate libc;
use libc::*;
use std::ffi::CString;
use std::default::Default;

// #define MFSTYPENAMELEN  16  length of fs type name including null
// #define MAXPATHLEN      1024
// #define MNAMELEN        MAXPATHLEN
   // struct statfs { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
   //       uint32_t    f_bsize;        /* fundamental file system block size */
   //       int32_t     f_iosize;       /* optimal transfer block size */
   //       uint64_t    f_blocks;       /* total data blocks in file system */
   //       uint64_t    f_bfree;        /* free blocks in fs */
   //       uint64_t    f_bavail;       /* free blocks avail to non-superuser */
   //       uint64_t    f_files;        /* total file nodes in file system */
   //       uint64_t    f_ffree;        /* free file nodes in fs */
   //       fsid_t      f_fsid;         /* file system id */
   //       uid_t       f_owner;        /* user that mounted the filesystem */
   //       uint32_t    f_type;         /* type of filesystem */
   //       uint32_t    f_flags;        /* copy of mount exported flags */
   //       uint32_t    f_fssubtype;    /* fs sub-type (flavor) */
   //       char        f_fstypename[MFSTYPENAMELEN];   /* fs type name */
   //       char        f_mntonname[MAXPATHLEN];        /* directory on which mounted */
   //       char        f_mntfromname[MAXPATHLEN];      /* mounted filesystem */
   //       uint32_t    f_reserved[8];  /* For future use */
   //   };

type Uid = uint32_t;

#[repr(C)]
struct StatFs {
	f_bsize: uint32_t,
	f_iosize: int32_t,
	f_blocks: uint64_t,
	f_bfree:  uint64_t,
	f_bavail: uint64_t,
	f_files:  uint64_t,
	f_ffree:  uint64_t,
	f_fsid:	  [uint32_t; 2],
	f_owner:  Uid,
	f_type:	  uint32_t,
	f_flags:  uint32_t,
	f_fstypename: 	[c_char; 16],
	f_mntonname: 	[c_char; 1024],
	f_mntfromname: 	[c_char; 1024],
	f_reserved: 	[uint32_t; 8],
}

impl Default for StatFs {
	fn default() -> StatFs {
		StatFs{
			f_bsize: 0,
			f_iosize: 0,
			f_blocks: 0,
			f_bfree: 0,
			f_bavail: 0,
			f_files: 0,
			f_ffree: 0,
			f_fsid: [0; 2],
			f_owner: 0,
			f_type: 0,
			f_flags: 0,
			f_fstypename: [0; 16],
			f_mntonname:  [0; 1024],
			f_mntfromname:[0; 1024],
			f_reserved: [0; 8]
		}
	}
}

extern {
	fn statfs(path: *const c_char, stafs: *mut StatFs) -> size_t;
	// statfs(const char *path, struct statfs *buf);
}

// Write the Docopt usage string. dfrites ?
static USAGE: &'static str = "
Usage: durite -g GHOSTNAME -l HOSTNAME [-p PORT]
       durite (--help | -h)

Options:
    -h, --help     Show this screen.
    -l HOSTNAME    Hostname to advertise in graphite.
    -g GHOSTNAME   Graphite Hostname.
    -p PORT        Graphite port [default: 2003]
";

#[cfg(not(any(target_os="macos")))]
fn disk_free() -> std::process::Output {
	Command::new("df")
		.arg("--portability").output().unwrap_or_else(|e| { panic!("failed to execute process: {}", e) })
}

#[cfg(any(target_os="macos"))]
fn disk_free() -> std::process::Output {
	Command::new("df")
		.arg("-k").output().unwrap_or_else(|e| { panic!("failed to execute process: {}", e) })
}

fn send_content(stream: &mut std::net::TcpStream, hostname: &str, probe_and_value: String, timestamp: i64) {
	let content = format!("durite.{}.{} {}\n", hostname, probe_and_value, timestamp);
	let _ = stream.write(&content.as_bytes());
}

fn main() {

	// Parse argv and exit the program with an error message if it fails.
	let args = Docopt::new(USAGE)
		.and_then(|d| d.argv(std::env::args().into_iter()).parse())
		.unwrap_or_else(|e| e.exit());

    let connect_string = format!("{}:{}", args.get_str("-g"), args.get_str("-p"));
    println!("Connect string is {}", connect_string);
    let my_hostname = args.get_str("-l");

	while true {
	    let dt = chrono::UTC::now();
	    let timestamp = dt.timestamp();
	    let o = disk_free();
		let stdout = String::from_utf8(o.stdout).
			ok().
			unwrap();

		let lines = stdout.split("\n");

	    match TcpStream::connect(&*connect_string) {
	    	Ok(s) => {
	    		let mut stream = s;
				for line in lines {
					if line.starts_with("/") {
						let values: Vec<&str> = line.split(" ").filter(|e| {
							e.len() != 0
						}).collect();

						let disk = values[0];
						// du reports kbytes
						let all = values[2] * 1024;
						let available = values[3] *1024;
						// let w = values[8].to_string();
						// let mut st: StatFs = Default::default();
						// let mp = CString::new(w.into_bytes()).unwrap();
						// unsafe {
						// 	let o = statfs(mp.as_ptr(), &mut st);
						// 	println!("o{} {:?}", o, st.f_bfree);
						// }
						send_content(&mut stream, my_hostname, format!("{}.available {}", disk, available), timestamp);
						send_content(&mut stream, my_hostname, format!("{}.all {}", disk, all), timestamp);
				 	}
				 }
	    	},
	    	Err(e) => println!("Unable to connect to {}: {:?}\nIgnoring this data point.", connect_string, e)
		}
	 	std::thread::sleep_ms(10000);
	}
}
<commit_msg>correct unit<commit_after>
extern crate chrono;
extern crate docopt;

use std::process::Command;

use std::io::prelude::*;
use std::net::TcpStream;

use docopt::Docopt;

use std::str::FromStr;

extern crate libc;
use libc::*;
use std::ffi::CString;
use std::default::Default;

// #define MFSTYPENAMELEN  16  length of fs type name including null
// #define MAXPATHLEN      1024
// #define MNAMELEN        MAXPATHLEN
   // struct statfs { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
   //       uint32_t    f_bsize;        /* fundamental file system block size */
   //       int32_t     f_iosize;       /* optimal transfer block size */
   //       uint64_t    f_blocks;       /* total data blocks in file system */
   //       uint64_t    f_bfree;        /* free blocks in fs */
   //       uint64_t    f_bavail;       /* free blocks avail to non-superuser */
   //       uint64_t    f_files;        /* total file nodes in file system */
   //       uint64_t    f_ffree;        /* free file nodes in fs */
   //       fsid_t      f_fsid;         /* file system id */
   //       uid_t       f_owner;        /* user that mounted the filesystem */
   //       uint32_t    f_type;         /* type of filesystem */
   //       uint32_t    f_flags;        /* copy of mount exported flags */
   //       uint32_t    f_fssubtype;    /* fs sub-type (flavor) */
   //       char        f_fstypename[MFSTYPENAMELEN];   /* fs type name */
   //       char        f_mntonname[MAXPATHLEN];        /* directory on which mounted */
   //       char        f_mntfromname[MAXPATHLEN];      /* mounted filesystem */
   //       uint32_t    f_reserved[8];  /* For future use */
   //   };

type Uid = uint32_t;

#[repr(C)]
struct StatFs {
	f_bsize: uint32_t,
	f_iosize: int32_t,
	f_blocks: uint64_t,
	f_bfree:  uint64_t,
	f_bavail: uint64_t,
	f_files:  uint64_t,
	f_ffree:  uint64_t,
	f_fsid:	  [uint32_t; 2],
	f_owner:  Uid,
	f_type:	  uint32_t,
	f_flags:  uint32_t,
	f_fstypename: 	[c_char; 16],
	f_mntonname: 	[c_char; 1024],
	f_mntfromname: 	[c_char; 1024],
	f_reserved: 	[uint32_t; 8],
}

impl Default for StatFs {
	fn default() -> StatFs {
		StatFs{
			f_bsize: 0,
			f_iosize: 0,
			f_blocks: 0,
			f_bfree: 0,
			f_bavail: 0,
			f_files: 0,
			f_ffree: 0,
			f_fsid: [0; 2],
			f_owner: 0,
			f_type: 0,
			f_flags: 0,
			f_fstypename: [0; 16],
			f_mntonname:  [0; 1024],
			f_mntfromname:[0; 1024],
			f_reserved: [0; 8]
		}
	}
}

extern {
	fn statfs(path: *const c_char, stafs: *mut StatFs) -> size_t;
	// statfs(const char *path, struct statfs *buf);
}

// Write the Docopt usage string. dfrites ?
static USAGE: &'static str = "
Usage: durite -g GHOSTNAME -l HOSTNAME [-p PORT]
       durite (--help | -h)

Options:
    -h, --help     Show this screen.
    -l HOSTNAME    Hostname to advertise in graphite.
    -g GHOSTNAME   Graphite Hostname.
    -p PORT        Graphite port [default: 2003]
";

#[cfg(not(any(target_os="macos")))]
fn disk_free() -> std::process::Output {
	Command::new("df")
		.arg("--portability").output().unwrap_or_else(|e| { panic!("failed to execute process: {}", e) })
}

#[cfg(any(target_os="macos"))]
fn disk_free() -> std::process::Output {
	Command::new("df")
		.arg("-k").output().unwrap_or_else(|e| { panic!("failed to execute process: {}", e) })
}

fn send_content(stream: &mut std::net::TcpStream, hostname: &str, probe_and_value: String, timestamp: i64) {
	let content = format!("durite.{}.{} {}\n", hostname, probe_and_value, timestamp);
	let _ = stream.write(&content.as_bytes());
}

fn main() {

	// Parse argv and exit the program with an error message if it fails.
	let args = Docopt::new(USAGE)
		.and_then(|d| d.argv(std::env::args().into_iter()).parse())
		.unwrap_or_else(|e| e.exit());

    let connect_string = format!("{}:{}", args.get_str("-g"), args.get_str("-p"));
    println!("Connect string is {}", connect_string);
    let my_hostname = args.get_str("-l");

	while true {
	    let dt = chrono::UTC::now();
	    let timestamp = dt.timestamp();
	    let o = disk_free();
		let stdout = String::from_utf8(o.stdout).
			ok().
			unwrap();

		let lines = stdout.split("\n");

	    match TcpStream::connect(&*connect_string) {
	    	Ok(s) => {
	    		let mut stream = s;
				for line in lines {
					if line.starts_with("/") {
						let values: Vec<&str> = line.split(" ").filter(|e| {
							e.len() != 0
						}).collect();

						let disk = values[0];
						// du reports kbytes
                        let all: u64 = u64::from_str(values[2]).unwrap() * 1024;
						let available: u64 = u64::from_str(values[3]).unwrap() *1024;
						// let w = values[8].to_string();
						// let mut st: StatFs = Default::default();
						// let mp = CString::new(w.into_bytes()).unwrap();
						// unsafe {
						// 	let o = statfs(mp.as_ptr(), &mut st);
						// 	println!("o{} {:?}", o, st.f_bfree);
						// }
						send_content(&mut stream, my_hostname, format!("{}.available {}", disk, available), timestamp);
						send_content(&mut stream, my_hostname, format!("{}.all {}", disk, all), timestamp);
				 	}
				 }
	    	},
	    	Err(e) => println!("Unable to connect to {}: {:?}\nIgnoring this data point.", connect_string, e)
		}
	 	std::thread::sleep_ms(10000);
	}
}
<|endoftext|>