<commit_before>#![feature(old_path)]

extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate drag_controller;
extern crate sdl2_window;

use std::old_path::*;

use std::cell::RefCell;

use graphics::ImageSize;
use drag_controller::{
    DragController,
    Drag
};
use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window as Window;

fn main() {
    println!("Click in the red square and drag.");
    println!("Toggle grid with G.");
    println!("Reset grid with R.");

    let opengl = OpenGL::_3_2;
    let window = Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Deform".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let image = Path::new("./bin/assets/rust-logo.png");
    let image = Texture::from_path(&image).unwrap();

    let (width, height) = image.get_size();
    let width = width as f64;
    let height = height as f64;
    let mut grid = graphics::deform::DeformGrid::new(
        [0.0, 0.0, width, height],
        20, 20
    );

    let mut drag = DragController::new();
    let mut draw_grid = true;

    let mut gl = GlGraphics::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::*;

        drag.event(&e, |action| {
            match action {
                Drag::Start(x, y) => {
                    match grid.hit([x, y]) {
                        None => {
                            // Did not hit deformed grid.
                            grid.add_control_point([x, y]);
                        }
                        Some(pos) => {
                            // Add point to deformed grid.
                            grid.add_control_point(pos);
                            let n = grid.ps.len();
                            grid.set_current(n - 1, [x, y]);
                        }
                    }
                    grid.update();
                    true
                }
                Drag::Move(x, y) => {
                    let n = grid.ps.len();
                    grid.set_current(n - 1, [x, y]);
                    grid.update();
                    true
                }
                Drag::End(_, _) => false,
                // Continue dragging when receiving focus.
                Drag::Interrupt => true,
            }
        });
        if let Some(button) = e.press_args() {
            use piston::input::Button::Keyboard;
            use piston::input::keyboard::Key;

            if button == Keyboard(Key::G) {
                draw_grid = !draw_grid;
                println!("Draw grid {}", draw_grid);
            } else if button == Keyboard(Key::R) {
                grid.reset_control_points();
                grid.reset_vertices_and_texture_coords();
                grid.update();
                println!("Reset grid");
            }
        }
        if let Some(args) = e.render_args() {
            gl.draw(
                [0, 0, args.width as i32, args.height as i32],
                |c, g| {

            graphics::clear(graphics::color::WHITE, g);

            // Draw deformed image.
            grid.draw_image(&image, &c.draw_state, c.transform, g);

            if draw_grid {
                // Draw grid.
                grid.draw_vertical_lines(
                    &graphics::Line::new([0.0, 1.0, 0.0, 1.0], 0.5),
                    &c.draw_state,
                    c.transform,
                    g
                );
                grid.draw_horizontal_lines(
                    &graphics::Line::new([0.0, 0.0, 1.0, 1.0], 0.5),
                    &c.draw_state,
                    c.transform,
                    g
                );
            }

            // Draw rect of the original grid.
            graphics::Rectangle::border([1.0, 0.0, 0.0, 1.0], 1.5)
                .draw([0.0, 0.0, width, height], &c.draw_state, c.transform, g);

            // Draw control points.
            let original = graphics::Ellipse::new([1.0, 0.0, 0.0, 0.5]);
            let current = graphics::Ellipse::new([0.0, 0.0, 0.0, 0.5]);
            for i in (0..grid.ps.len()) {
                use graphics::ellipse::circle;

                // Original positions.
                let x = grid.ps[i][0];
                let y = grid.ps[i][1];
                original.draw(circle(x, y, 3.0), &c.draw_state, c.transform, g);

                // Current positions.
                let x = grid.qs[i][0];
                let y = grid.qs[i][1];
                current.draw(circle(x, y, 3.0), &c.draw_state, c.transform, g);
            };

            });
        } // end render
    }
}

<commit_msg>Upgrade deform example to new path<commit_after>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate drag_controller;
extern crate sdl2_window;

use std::path::Path;
use std::cell::RefCell;

use graphics::ImageSize;
use drag_controller::{
    DragController,
    Drag
};
use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window as Window;

fn main() {
    println!("Click in the red square and drag.");
    println!("Toggle grid with G.");
    println!("Reset grid with R.");

    let opengl = OpenGL::_3_2;
    let window = Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "piston-example-deform".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let image = Path::new("./bin/assets/rust-logo.png");
    let image = Texture::from_path(&image).unwrap();

    let (width, height) = image.get_size();
    let width = width as f64;
    let height = height as f64;
    let mut grid = graphics::deform::DeformGrid::new(
        [0.0, 0.0, width, height],
        20, 20
    );

    let mut drag = DragController::new();
    let mut draw_grid = true;

    let mut gl = GlGraphics::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::*;

        drag.event(&e, |action| {
            match action {
                Drag::Start(x, y) => {
                    match grid.hit([x, y]) {
                        None => {
                            // Did not hit deformed grid.
                            grid.add_control_point([x, y]);
                        }
                        Some(pos) => {
                            // Add point to deformed grid.
                            grid.add_control_point(pos);
                            let n = grid.ps.len();
                            grid.set_current(n - 1, [x, y]);
                        }
                    }
                    grid.update();
                    true
                }
                Drag::Move(x, y) => {
                    let n = grid.ps.len();
                    grid.set_current(n - 1, [x, y]);
                    grid.update();
                    true
                }
                Drag::End(_, _) => false,
                // Continue dragging when receiving focus.
                Drag::Interrupt => true,
            }
        });
        if let Some(button) = e.press_args() {
            use piston::input::Button::Keyboard;
            use piston::input::keyboard::Key;

            if button == Keyboard(Key::G) {
                draw_grid = !draw_grid;
                println!("Draw grid {}", draw_grid);
            } else if button == Keyboard(Key::R) {
                grid.reset_control_points();
                grid.reset_vertices_and_texture_coords();
                grid.update();
                println!("Reset grid");
            }
        }
        if let Some(args) = e.render_args() {
            gl.draw(
                [0, 0, args.width as i32, args.height as i32],
                |c, g| {

            graphics::clear(graphics::color::WHITE, g);

            // Draw deformed image.
            grid.draw_image(&image, &c.draw_state, c.transform, g);

            if draw_grid {
                // Draw grid.
                grid.draw_vertical_lines(
                    &graphics::Line::new([0.0, 1.0, 0.0, 1.0], 0.5),
                    &c.draw_state,
                    c.transform,
                    g
                );
                grid.draw_horizontal_lines(
                    &graphics::Line::new([0.0, 0.0, 1.0, 1.0], 0.5),
                    &c.draw_state,
                    c.transform,
                    g
                );
            }

            // Draw rect of the original grid.
            graphics::Rectangle::border([1.0, 0.0, 0.0, 1.0], 1.5)
                .draw([0.0, 0.0, width, height], &c.draw_state, c.transform, g);

            // Draw control points.
            let original = graphics::Ellipse::new([1.0, 0.0, 0.0, 0.5]);
            let current = graphics::Ellipse::new([0.0, 0.0, 0.0, 0.5]);
            for i in (0..grid.ps.len()) {
                use graphics::ellipse::circle;

                // Original positions.
                let x = grid.ps[i][0];
                let y = grid.ps[i][1];
                original.draw(circle(x, y, 3.0), &c.draw_state, c.transform, g);

                // Current positions.
                let x = grid.qs[i][0];
                let y = grid.qs[i][1];
                current.draw(circle(x, y, 3.0), &c.draw_state, c.transform, g);
            };

            });
        } // end render
    }
}

<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(unused_attributes)]

extern crate regex;
extern crate time;
extern crate rustc_serialize;

mod util;

use util::command;
use util::fs;
use std::env;
use std::path::Path;

fn main() {
  let worlds = vec![
    "VR",
    "utes",
    "Sara",
    "SaraLite",
    "Sara_dbe1",
    "Chernarus",
    "Chernarus_Summer",
    "Porto",
    "Intro",
    "IsolaDiCapraia",
    "Mountains_ACR",
    "Takistan",
    "Zargabad",
    "Woodland_ACR",
    "Bootcamp_ACR",
    "Desert_E",
    "ProvingGrounds_PMC",
    "Shapur_BAF",
    "fata",
    "Stratis",
    "anim_helvantis_v2",
    "Altis",
    "pja310"
  ];

  let cwd: String = format!("{}\\", get_cwd());

  prepare_comfyDowntime(cwd.as_ref());

  // Mission Generation for all Maps
  for map in worlds {
    println!("Generating missions for Map: {}", map);
    compile_comfyDowntime(cwd.as_ref(), map);
    compile_comfyCompetition(cwd.as_ref(), map);
  }
}

/*
  This function prepares the ComfyDowntime mission to be packed.
  It copies the main ComfyDowntime folder into 3 seperate ones. 1 for each major faction in the Armaverse.
  BLUFOR, OPFOR and INDFOR.

  Along with this, it edits the mission.sqm and description.ext files and Replaces the units, sides and mission name to fit the currently used faction.
*/
fn prepare_comfyDowntime(path: &str) {
  let mission_downtime = "FP_ComfyDowntime";
  let dirpath: String = format!("{}{}.VR", path, mission_downtime);
  let mission_str: &str = "COMFY_USE_B = false; COMFY_USE_O = false; COMFY_USE_I = false;";

  // Create Folders for ComfyDowntime Faction Variations
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Blufor", path, mission_downtime).as_ref(), "/E"]);
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Opfor", path, mission_downtime).as_ref(), "/E"]);
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Indfor", path, mission_downtime).as_ref(), "/E"]);

  /***********************
  # Mission.sqm Editing
  ************************/
  let mission_path: String = format!("{}.VR\\mission.sqm", mission_downtime);
  let mission_path_slice: &str = mission_path.as_ref();
  let mission_path_struct = Path::new(mission_path_slice);
  let mission_file: String = fs::read(&mission_path_struct);

  let mut mission_blufor: String = mission_file.replace(mission_str, "COMFY_USE_B = true; COMFY_USE_O = false; COMFY_USE_I = false;");
  let mut mission_opfor: String = mission_file.replace(mission_str, "COMFY_USE_B = false; COMFY_USE_O = true; COMFY_USE_I = false;");
  let mut mission_indfor: String = mission_file.replace(mission_str, "COMFY_USE_B = false; COMFY_USE_O = false; COMFY_USE_I = true;");

  // Now replace the Units in the mission to fit the Faction. We don't require to replace blufor units, since blufor classes are already default
  mission_opfor = mission_opfor.replace("b_soldier_unarmed_f", "o_soldier_unarmed_f");
  mission_indfor = mission_indfor.replace("b_soldier_unarmed_f", "i_soldier_unarmed_f");

  // Adjust the Actual Side of the unit.
  mission_opfor = mission_opfor.replace("side=\"WEST\";", "side=\"EAST\";");
  mission_indfor = mission_indfor.replace("side=\"WEST\";", "side=\"GUER\";");

  mission_blufor = mission_blufor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (BLUFOR)");
  mission_opfor = mission_opfor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (OPFOR)");
  mission_indfor = mission_indfor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (INDFOR)");

  fs::write(format!("{}_Blufor.\\mission.sqm", mission_downtime).as_ref(), mission_blufor.as_ref());
  fs::write(format!("{}_Opfor.\\mission.sqm", mission_downtime).as_ref(), mission_opfor.as_ref());
  fs::write(format!("{}_Indfor.\\mission.sqm", mission_downtime).as_ref(), mission_indfor.as_ref());

  /***********************
  # Description.ext Editing
  ************************/
  let description_path: String = format!("{}.VR\\description.ext", mission_downtime);
  let description_path_slice: &str = description_path.as_ref();
  let description_path_struct = Path::new(description_path_slice);
  let description_file: String = fs::read(&description_path_struct);

  let description_blufor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (BLUFOR)");
  let description_opfor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (OPFOR)");
  let description_indfor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (INDFOR)");

  fs::write(format!("{}_Blufor.\\description.ext", mission_downtime).as_ref(), description_blufor.as_ref());
  fs::write(format!("{}_Opfor.\\description.ext", mission_downtime).as_ref(), description_opfor.as_ref());
  fs::write(format!("{}_Indfor.\\description.ext", mission_downtime).as_ref(), description_indfor.as_ref());
}

/*
  This function Executes the PBOConsole Command and builds the Actual PBO Files for the
  ComfyDowntime Mission.

  It creates 3 PBO Files. One for Each Major Faction in Arma. BLUFOR; OPFOR and INFDOR/GUER
*/
fn compile_comfyDowntime(path: &str, map: &str) {
  let dirpath_blufor: String = format!("{}FP_ComfyDowntime_Blufor", path);
  let newpath_blufor: String = format!("{}FP_ComfyDowntime_Blufor.{}.pbo", path, map);

  let dirpath_opfor: String = format!("{}FP_ComfyDowntime_Opfor", path);
  let newpath_opfor: String = format!("{}FP_ComfyDowntime_Opfor.{}.pbo", path, map);

  let dirpath_indfor: String = format!("{}FP_ComfyDowntime_Indfor", path);
  let newpath_indfor: String = format!("{}FP_ComfyDowntime_Indfor.{}.pbo", path, map);

  command::run("PBOConsole", &["-pack", dirpath_blufor.as_ref(), newpath_blufor.as_ref()]);
  command::run("PBOConsole", &["-pack", dirpath_opfor.as_ref(), newpath_opfor.as_ref()]);
  command::run("PBOConsole", &["-pack", dirpath_indfor.as_ref(), newpath_indfor.as_ref()]);
}

/*
  This function Executes the PBOConsole Command and builds the Actual BPO Files for the ComfyCompetition Mission.
*/
fn compile_comfyCompetition(path: &str, map: &str) {
  let dirpath: String = format!("{}FP_ComfyCompetition.VR", path);
  let newpath: String = format!("{}FP_ComfyCompetition.{}.pbo", path, map);
  command::run("PBOConsole", &["-pack", dirpath.as_ref(), newpath.as_ref()]);
}

/*
  This function returns the Current working directory as a String.
  If combined with another path, an \\ or / might have to be added to
  the End of this String.

  for this, use the following format:
  format!("{}\\", get_cwd())
*/
fn get_cwd() -> String {
  let pathbuf = env::current_dir().unwrap();
  let path: &str = pathbuf.to_str().unwrap();
  path.to_string()
}<commit_msg>Removed intro map<commit_after>#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(unused_attributes)]

extern crate regex;
extern crate time;
extern crate rustc_serialize;

mod util;

use util::command;
use util::fs;
use std::env;
use std::path::Path;

fn main() {
  let worlds = vec![
    "VR",
    "utes",
    "Sara",
    "SaraLite",
    "Sara_dbe1",
    "Chernarus",
    "Chernarus_Summer",
    "Porto",
    "IsolaDiCapraia",
    "Mountains_ACR",
    "Takistan",
    "Zargabad",
    "Woodland_ACR",
    "Bootcamp_ACR",
    "Desert_E",
    "ProvingGrounds_PMC",
    "Shapur_BAF",
    "fata",
    "Stratis",
    "anim_helvantis_v2",
    "Altis",
    "pja310"
  ];

  let cwd: String = format!("{}\\", get_cwd());

  prepare_comfyDowntime(cwd.as_ref());

  // Mission Generation for all Maps
  for map in worlds {
    println!("Generating missions for Map: {}", map);
    compile_comfyDowntime(cwd.as_ref(), map);
    compile_comfyCompetition(cwd.as_ref(), map);
  }
}

/*
  This function prepares the ComfyDowntime mission to be packed.
  It copies the main ComfyDowntime folder into 3 seperate ones. 1 for each major faction in the Armaverse.
  BLUFOR, OPFOR and INDFOR.

  Along with this, it edits the mission.sqm and description.ext files and Replaces the units, sides and mission name to fit the currently used faction.
*/
fn prepare_comfyDowntime(path: &str) {
  let mission_downtime = "FP_ComfyDowntime";
  let dirpath: String = format!("{}{}.VR", path, mission_downtime);
  let mission_str: &str = "COMFY_USE_B = false; COMFY_USE_O = false; COMFY_USE_I = false;";

  // Create Folders for ComfyDowntime Faction Variations
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Blufor", path, mission_downtime).as_ref(), "/E"]);
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Opfor", path, mission_downtime).as_ref(), "/E"]);
  command::run("robocopy", &[dirpath.as_ref(), format!("{}{}_Indfor", path, mission_downtime).as_ref(), "/E"]);

  /***********************
  # Mission.sqm Editing
  ************************/
  let mission_path: String = format!("{}.VR\\mission.sqm", mission_downtime);
  let mission_path_slice: &str = mission_path.as_ref();
  let mission_path_struct = Path::new(mission_path_slice);
  let mission_file: String = fs::read(&mission_path_struct);

  let mut mission_blufor: String = mission_file.replace(mission_str, "COMFY_USE_B = true; COMFY_USE_O = false; COMFY_USE_I = false;");
  let mut mission_opfor: String = mission_file.replace(mission_str, "COMFY_USE_B = false; COMFY_USE_O = true; COMFY_USE_I = false;");
  let mut mission_indfor: String = mission_file.replace(mission_str, "COMFY_USE_B = false; COMFY_USE_O = false; COMFY_USE_I = true;");

  // Now replace the Units in the mission to fit the Faction. We don't require to replace blufor units, since blufor classes are already default
  mission_opfor = mission_opfor.replace("b_soldier_unarmed_f", "o_soldier_unarmed_f");
  mission_indfor = mission_indfor.replace("b_soldier_unarmed_f", "i_soldier_unarmed_f");

  // Adjust the Actual Side of the unit.
  mission_opfor = mission_opfor.replace("side=\"WEST\";", "side=\"EAST\";");
  mission_indfor = mission_indfor.replace("side=\"WEST\";", "side=\"GUER\";");

  mission_blufor = mission_blufor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (BLUFOR)");
  mission_opfor = mission_opfor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (OPFOR)");
  mission_indfor = mission_indfor.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (INDFOR)");

  fs::write(format!("{}_Blufor.\\mission.sqm", mission_downtime).as_ref(), mission_blufor.as_ref());
  fs::write(format!("{}_Opfor.\\mission.sqm", mission_downtime).as_ref(), mission_opfor.as_ref());
  fs::write(format!("{}_Indfor.\\mission.sqm", mission_downtime).as_ref(), mission_indfor.as_ref());

  /***********************
  # Description.ext Editing
  ************************/
  let description_path: String = format!("{}.VR\\description.ext", mission_downtime);
  let description_path_slice: &str = description_path.as_ref();
  let description_path_struct = Path::new(description_path_slice);
  let description_file: String = fs::read(&description_path_struct);

  let description_blufor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (BLUFOR)");
  let description_opfor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (OPFOR)");
  let description_indfor: String = description_file.replace("<!mission_name!>", "FP Comfy Downtime 3.0 (INDFOR)");

  fs::write(format!("{}_Blufor.\\description.ext", mission_downtime).as_ref(), description_blufor.as_ref());
  fs::write(format!("{}_Opfor.\\description.ext", mission_downtime).as_ref(), description_opfor.as_ref());
  fs::write(format!("{}_Indfor.\\description.ext", mission_downtime).as_ref(), description_indfor.as_ref());
}

/*
  This function Executes the PBOConsole Command and builds the Actual PBO Files for the
  ComfyDowntime Mission.

  It creates 3 PBO Files. One for Each Major Faction in Arma. BLUFOR; OPFOR and INFDOR/GUER
*/
fn compile_comfyDowntime(path: &str, map: &str) {
  let dirpath_blufor: String = format!("{}FP_ComfyDowntime_Blufor", path);
  let newpath_blufor: String = format!("{}FP_ComfyDowntime_Blufor.{}.pbo", path, map);

  let dirpath_opfor: String = format!("{}FP_ComfyDowntime_Opfor", path);
  let newpath_opfor: String = format!("{}FP_ComfyDowntime_Opfor.{}.pbo", path, map);

  let dirpath_indfor: String = format!("{}FP_ComfyDowntime_Indfor", path);
  let newpath_indfor: String = format!("{}FP_ComfyDowntime_Indfor.{}.pbo", path, map);

  command::run("PBOConsole", &["-pack", dirpath_blufor.as_ref(), newpath_blufor.as_ref()]);
  command::run("PBOConsole", &["-pack", dirpath_opfor.as_ref(), newpath_opfor.as_ref()]);
  command::run("PBOConsole", &["-pack", dirpath_indfor.as_ref(), newpath_indfor.as_ref()]);
}

/*
  This function Executes the PBOConsole Command and builds the Actual BPO Files for the ComfyCompetition Mission.
*/
fn compile_comfyCompetition(path: &str, map: &str) {
  let dirpath: String = format!("{}FP_ComfyCompetition.VR", path);
  let newpath: String = format!("{}FP_ComfyCompetition.{}.pbo", path, map);
  command::run("PBOConsole", &["-pack", dirpath.as_ref(), newpath.as_ref()]);
}

/*
  This function returns the Current working directory as a String.
  If combined with another path, an \\ or / might have to be added to
  the End of this String.

  for this, use the following format:
  format!("{}\\", get_cwd())
*/
fn get_cwd() -> String {
  let pathbuf = env::current_dir().unwrap();
  let path: &str = pathbuf.to_str().unwrap();
  path.to_string()
}<|endoftext|>


<commit_before>use super::response::Response;
use super::request::Request;
use super::alloy::Alloy;

/// The Status returned by `Ingot's` `enter` and `exit` methods. This indicates
/// to the `Furnace` whether this is a terminal `Ingot` or whether to continue
/// passing the `Request` and `Response` down the `Furnace's` stack.
///
/// Most `Furnaces` will ignore the returned `Status` from the `exit` method of
/// `Ingots`.
pub enum Status {
    /// `Continue` indicates that this is an intermediate `Ingot` in the stack
    /// and the `Furnace` should continue passing requests down the `Furnace's`
    /// stack.
    ///
    /// Most `Ingots` will return `Continue` from both `enter` and `exit`.
    Continue,

    /// `Unwind` indicates that this is a terminal `Ingot` or something went
    /// wrong. It can be used to immediately stop passing requests down the
    /// `Furnace's` stack and start calling `exit` of all previous `Ingots`.
    ///
    /// For instance, an authorization `Ingot` might return `Unwind` if the
    /// request fails an authentication check, and `Continue` otherwise.
    Unwind
}

/// All middleware should implement `Ingot`, which allows it to be `smelted`
/// to a `Furnace` so that it will be called for each incoming request.
///
/// There are two sorts of data associated with `Ingots`, data internal
/// to the `Ingot` and data that the `Ingot` would like to expose to `Ingots`
/// further down the stack or terminal controllers.
///
/// Internal data should be stored on the `struct` that implements `Ingot`
/// itself. All `Ingots` are cloned for each client request, so the object
/// initially smelted on to the `Iron` instance will be provided as `&self` to
/// enter for every request. Data stored on `Ingot` instances does _not_ persist
/// between requests and is _not_ shared between different, concurrent, requests.
/// The same is true for data stored on `Alloys`.
///
/// External data should be stored in the `Alloy` passed to both `enter` and
/// `exit`. `Alloy` is a thin wrapper around `AnyMap` and is effectively a
/// a key value store from a type to an instance of that type. This means
/// that each `Ingot` can have a unique type that it stores in the `Alloy`.
/// This can either be an instance of that `Ingot` or some other type. Since
/// the same `Alloy` is passed to all further `Ingots` in the `Furnace`, this
/// scheme allows you to expose data or functionality to future `Ingots`.
pub trait Ingot<Rq: Request, Rs: Response>: Send + Clone {
    /// `enter` is called for each `Ingot` in a `Furnace` as a client request
    /// comes down the stack. `Ingots` should expose data through `Alloy` and
    /// store any data that will persist through the request here.
    ///
    /// returning `Unwind` from this handler will cause the `Furnace` to stop
    /// going down the `Furnace's` stack and start bubbling back up and calling
    /// `exit`.
    fn enter(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }

    /// `exit` is called for each `Ingot` in `Furnace` that has had it's `enter`
    /// method called for this request. `Ingot's``exit` method will be called
    /// as the stack is unwound in FILO order. `Ingots` have their `exit`
    /// methods called in opposite order from which `enter` was called, which
    /// is FIFO.
    ///
    /// While this method must return a `Status`, most `Furnaces` will ignore
    /// this method's return value.
    fn exit(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }

    fn clone_box(&self) -> Box<Ingot<Rq, Rs>> { box self.clone() as Box<Ingot<Rq, Rs>> }
}

impl<Rq: Request, Rs: Response> Clone for Box<Ingot<Rq, Rs>> {
    fn clone(&self) -> Box<Ingot<Rq, Rs>> { self.clone_box() }
}
<commit_msg>(doc) Added rustdoc for ingot module.<commit_after>//! Exposes the `Ingot` trait which must be implemented by
//! all middleware.

use super::response::Response;
use super::request::Request;
use super::alloy::Alloy;

/// The Status returned by `Ingot's` `enter` and `exit` methods. This indicates
/// to the `Furnace` whether this is a terminal `Ingot` or whether to continue
/// passing the `Request` and `Response` down the `Furnace's` stack.
///
/// Most `Furnaces` will ignore the returned `Status` from the `exit` method of
/// `Ingots`.
pub enum Status {
    /// `Continue` indicates that this is an intermediate `Ingot` in the stack
    /// and the `Furnace` should continue passing requests down the `Furnace's`
    /// stack.
    ///
    /// Most `Ingots` will return `Continue` from both `enter` and `exit`.
    Continue,

    /// `Unwind` indicates that this is a terminal `Ingot` or something went
    /// wrong. It can be used to immediately stop passing requests down the
    /// `Furnace's` stack and start calling `exit` of all previous `Ingots`.
    ///
    /// For instance, an authorization `Ingot` might return `Unwind` if the
    /// request fails an authentication check, and `Continue` otherwise.
    Unwind
}

/// All middleware should implement `Ingot`, which allows it to be `smelted`
/// to a `Furnace` so that it will be called for each incoming request.
///
/// There are two sorts of data associated with `Ingots`, data internal
/// to the `Ingot` and data that the `Ingot` would like to expose to `Ingots`
/// further down the stack or terminal controllers.
///
/// Internal data should be stored on the `struct` that implements `Ingot`
/// itself. All `Ingots` are cloned for each client request, so the object
/// initially smelted on to the `Iron` instance will be provided as `&self` to
/// enter for every request. Data stored on `Ingot` instances does _not_ persist
/// between requests and is _not_ shared between different, concurrent, requests.
/// The same is true for data stored on `Alloys`.
///
/// External data should be stored in the `Alloy` passed to both `enter` and
/// `exit`. `Alloy` is a thin wrapper around `AnyMap` and is effectively a
/// a key value store from a type to an instance of that type. This means
/// that each `Ingot` can have a unique type that it stores in the `Alloy`.
/// This can either be an instance of that `Ingot` or some other type. Since
/// the same `Alloy` is passed to all further `Ingots` in the `Furnace`, this
/// scheme allows you to expose data or functionality to future `Ingots`.
pub trait Ingot<Rq: Request, Rs: Response>: Send + Clone {
    /// `enter` is called for each `Ingot` in a `Furnace` as a client request
    /// comes down the stack. `Ingots` should expose data through `Alloy` and
    /// store any data that will persist through the request here.
    ///
    /// returning `Unwind` from this handler will cause the `Furnace` to stop
    /// going down the `Furnace's` stack and start bubbling back up and calling
    /// `exit`.
    fn enter(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }

    /// `exit` is called for each `Ingot` in `Furnace` that has had it's `enter`
    /// method called for this request. `Ingot's``exit` method will be called
    /// as the stack is unwound in FILO order. `Ingots` have their `exit`
    /// methods called in opposite order from which `enter` was called, which
    /// is FIFO.
    ///
    /// While this method must return a `Status`, most `Furnaces` will ignore
    /// this method's return value.
    fn exit(&mut self, _request: &mut Rq, _response: &mut Rs, _alloy: &mut Alloy) -> Status {
        Continue
    }

    fn clone_box(&self) -> Box<Ingot<Rq, Rs>> { box self.clone() as Box<Ingot<Rq, Rs>> }
}

impl<Rq: Request, Rs: Response> Clone for Box<Ingot<Rq, Rs>> {
    fn clone(&self) -> Box<Ingot<Rq, Rs>> { self.clone_box() }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use config::ContextConfig;
use context::Context;

pub struct ContextMap {
    map: HashMap<String, Vec<usize>>,
    contexts: Vec<Context>,
}

impl ContextMap {
    pub fn new() -> ContextMap {
        ContextMap {
            map: HashMap::new(),
            contexts: Vec::new(),
        }
    }

    pub fn from_configs(configs: Vec<ContextConfig>) -> ContextMap {
        let mut context_map = ContextMap::new();
        for i in configs {
            context_map.insert(i.into());
        }
        context_map
    }

    pub fn insert(&mut self, context: Context) {
        self.contexts.push(context);
        let last_context = self.contexts
                               .last()
                               .expect("Failed to remove the last Context from a non empty vector");
        let index_of_last_context = self.contexts.len() - 1;
        let patterns = last_context.patterns();
        ContextMap::update_indices(&mut self.map, index_of_last_context, patterns);
    }

    fn update_indices(map: &mut HashMap<String, Vec<usize>>,
                      new_index: usize,
                      patterns: &[String]) {
        if patterns.is_empty() {
            ContextMap::add_index_to_every_index_vectors(map, new_index);
        } else {
            ContextMap::add_index_to_looked_up_index_vectors(map, new_index, patterns);
        }
    }

    fn add_index_to_every_index_vectors(map: &mut HashMap<String, Vec<usize>>, new_index: usize) {
        for (_, v) in map.iter_mut() {
            v.push(new_index);
        }
    }

    fn add_index_to_looked_up_index_vectors(map: &mut HashMap<String, Vec<usize>>,
                                            new_index: usize,
                                            patterns: &[String]) {
        for i in patterns {
            map.entry(i.clone()).or_insert_with(Vec::new).push(new_index);
        }
    }

    pub fn contexts_mut(&mut self) -> &mut Vec<Context> {
        &mut self.contexts
    }

    pub fn contexts_iter_mut(&mut self, key: &str) -> Iterator {
        let ids = self.map.get(key);
        Iterator {
            ids: ids,
            pos: 0,
            contexts: &mut self.contexts,
        }
    }
}

pub trait StreamingIterator {
    type Item;
    fn next<'a>(&'a mut self) -> Option<&'a mut Self::Item>;
}

pub struct Iterator<'a> {
    ids: Option<&'a Vec<usize>>,
    pos: usize,
    contexts: &'a mut Vec<Context>,
}

impl<'a> StreamingIterator for Iterator<'a> {
    type Item = Context;
    fn next(&mut self) -> Option<&mut Context> {
        if let Some(ids) = self.ids {
            if let Some(id) = ids.get(self.pos) {
                self.pos += 1;
                self.contexts.get_mut(*id)
            } else {
                None
            }
        } else {
            None
        }
    }
}

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

    use conditions::ConditionsBuilder;
    use context::{Context, LinearContext, BaseContextBuilder};
    use uuid::Uuid;
    use std::time::Duration;

    fn assert_conext_map_contains_uuid(context_map: &mut ContextMap, uuid: &Uuid, key: &String) {
        let mut iter = context_map.contexts_iter_mut(key);
        let context = iter.next().expect("Failed to get back an inserted context");
        if let &mut Context::Linear(ref context) = context {
            assert_eq!(uuid, context.uuid());
        } else {
            unreachable!();
        }
    }

    #[test]
    fn test_given_context_map_when_a_context_is_inserted_then_its_patters_are_inserted_to_the_map_with_its_id
        () {
        let mut context_map = ContextMap::new();
        let uuid = Uuid::new_v4();
        let context1 = {
            let conditions = {
                let patterns = vec!["A".to_string(), "B".to_string()];
                ConditionsBuilder::new(Duration::from_millis(100)).patterns(patterns).build()
            };
            let base = BaseContextBuilder::new(uuid.clone(), conditions).build();
            LinearContext::new(base)
        };
        context_map.insert(Context::Linear(context1));
        assert_eq!(context_map.contexts_mut().len(), 1);
        assert_conext_map_contains_uuid(&mut context_map, &uuid, &"A".to_string());
        assert_conext_map_contains_uuid(&mut context_map, &uuid, &"B".to_string());
    }
}
<commit_msg>StreamingIterator: remove lifetimes as the default elision is the same<commit_after>use std::collections::HashMap;

use config::ContextConfig;
use context::Context;

pub struct ContextMap {
    map: HashMap<String, Vec<usize>>,
    contexts: Vec<Context>,
}

impl ContextMap {
    pub fn new() -> ContextMap {
        ContextMap {
            map: HashMap::new(),
            contexts: Vec::new(),
        }
    }

    pub fn from_configs(configs: Vec<ContextConfig>) -> ContextMap {
        let mut context_map = ContextMap::new();
        for i in configs {
            context_map.insert(i.into());
        }
        context_map
    }

    pub fn insert(&mut self, context: Context) {
        self.contexts.push(context);
        let last_context = self.contexts
                               .last()
                               .expect("Failed to remove the last Context from a non empty vector");
        let index_of_last_context = self.contexts.len() - 1;
        let patterns = last_context.patterns();
        ContextMap::update_indices(&mut self.map, index_of_last_context, patterns);
    }

    fn update_indices(map: &mut HashMap<String, Vec<usize>>,
                      new_index: usize,
                      patterns: &[String]) {
        if patterns.is_empty() {
            ContextMap::add_index_to_every_index_vectors(map, new_index);
        } else {
            ContextMap::add_index_to_looked_up_index_vectors(map, new_index, patterns);
        }
    }

    fn add_index_to_every_index_vectors(map: &mut HashMap<String, Vec<usize>>, new_index: usize) {
        for (_, v) in map.iter_mut() {
            v.push(new_index);
        }
    }

    fn add_index_to_looked_up_index_vectors(map: &mut HashMap<String, Vec<usize>>,
                                            new_index: usize,
                                            patterns: &[String]) {
        for i in patterns {
            map.entry(i.clone()).or_insert_with(Vec::new).push(new_index);
        }
    }

    pub fn contexts_mut(&mut self) -> &mut Vec<Context> {
        &mut self.contexts
    }

    pub fn contexts_iter_mut(&mut self, key: &str) -> Iterator {
        let ids = self.map.get(key);
        Iterator {
            ids: ids,
            pos: 0,
            contexts: &mut self.contexts,
        }
    }
}

pub trait StreamingIterator {
    type Item;
    fn next(&mut self) -> Option<&mut Self::Item>;
}

pub struct Iterator<'a> {
    ids: Option<&'a Vec<usize>>,
    pos: usize,
    contexts: &'a mut Vec<Context>,
}

impl<'a> StreamingIterator for Iterator<'a> {
    type Item = Context;
    fn next(&mut self) -> Option<&mut Context> {
        if let Some(ids) = self.ids {
            if let Some(id) = ids.get(self.pos) {
                self.pos += 1;
                self.contexts.get_mut(*id)
            } else {
                None
            }
        } else {
            None
        }
    }
}

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

    use conditions::ConditionsBuilder;
    use context::{Context, LinearContext, BaseContextBuilder};
    use uuid::Uuid;
    use std::time::Duration;

    fn assert_conext_map_contains_uuid(context_map: &mut ContextMap, uuid: &Uuid, key: &String) {
        let mut iter = context_map.contexts_iter_mut(key);
        let context = iter.next().expect("Failed to get back an inserted context");
        if let &mut Context::Linear(ref context) = context {
            assert_eq!(uuid, context.uuid());
        } else {
            unreachable!();
        }
    }

    #[test]
    fn test_given_context_map_when_a_context_is_inserted_then_its_patters_are_inserted_to_the_map_with_its_id
        () {
        let mut context_map = ContextMap::new();
        let uuid = Uuid::new_v4();
        let context1 = {
            let conditions = {
                let patterns = vec!["A".to_string(), "B".to_string()];
                ConditionsBuilder::new(Duration::from_millis(100)).patterns(patterns).build()
            };
            let base = BaseContextBuilder::new(uuid.clone(), conditions).build();
            LinearContext::new(base)
        };
        context_map.insert(Context::Linear(context1));
        assert_eq!(context_map.contexts_mut().len(), 1);
        assert_conext_map_contains_uuid(&mut context_map, &uuid, &"A".to_string());
        assert_conext_map_contains_uuid(&mut context_map, &uuid, &"B".to_string());
    }
}
<|endoftext|>


<commit_before>// TODO(tailhook) until we fill all stabs
#![allow(dead_code)]

#[macro_use] extern crate log;
#[macro_use] extern crate matches;
#[macro_use] extern crate quick_error;
#[macro_use] extern crate lazy_static;
extern crate env_logger;
extern crate futures;
extern crate futures_cpupool;
extern crate quire;
extern crate time;
extern crate argparse;
extern crate tokio_core;
extern crate tokio_service;
extern crate minihttp;
extern crate netbuf;
extern crate mime;
extern crate sha1;
extern crate mime_guess;
extern crate tk_sendfile;
extern crate tk_bufstream;
extern crate rustc_serialize;
extern crate tokio_curl;
extern crate curl;
extern crate byteorder;
extern crate httparse;
extern crate httpbin;
extern crate slab;
extern crate string_intern;

mod intern;
mod config;
mod handler;
mod handlers;
mod routing;
mod serializer;
mod default_error_page;
mod response;
mod websocket;
mod chat;
mod dev;
mod startup;

// Utils
mod short_circuit;
mod either;

use std::process::exit;
use std::env;

use argparse::{ArgumentParser, Parse, StoreTrue, Print, List, StoreFalse};
use tokio_core::reactor::Core;

pub use response::Pickler;

pub fn main() {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "warn");
    }
    env_logger::init().unwrap();

    let mut verbose = true;
    let mut show_config = false;
    let mut port = 8000;
    let mut routes = Vec::<dev::Route>::new();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Runs a web server, configured from the command-line, or in other
            words runs swindon in a devd emulation mode (not all devd options
            are supported yet).
        ");
        ap.refer(&mut routes)
            .add_argument("route", List, "
                Add a route. Routes can be:
                (a) `subdomain/path=DEST` -- serves destination on
                    `http://subdomain.devd.io/path`,
                (b) `subdomain=DEST` -- serves destination at root of
                    subdomain,
                (c) `/path=DEST` -- serves destination
                    on `http://localhost/path`,
                (d) `DEST` -- is the same as `/=DEST`.
                Destinations can be:
                (i) `./local/dir` -- serves files from filesystem,
                (ii) `http://host:12345/` -- proxy requests to specified host.
                Note: unlike in original `devd` we currently keep original
                `Host` in requests to proxy.
            ");
        ap.refer(&mut port)
            .add_option(&["-p", "--port"], Parse, "Listen on specified port");
        ap.refer(&mut show_config)
            .add_option(&["--show-config"], StoreTrue,
            "Show config for swindon that is generate by swindon-dev and
             exit");
        ap.add_option(&["--version"],
            Print(env!("CARGO_PKG_VERSION").to_string()),
            "Show version");
        ap.refer(&mut verbose)
            .add_option(&["--quiet"], StoreFalse,
            "Hide some user-friendly startup messages");
        ap.parse_args_or_exit();
    }

    let config = dev::generate_config(port, &routes);
    if show_config {
        print!("{}", config);
        exit(0);
    }

    let cfg = match config::ConfigCell::from_string(
        &config, "<swindon-dev cli>")
    {
        Ok(cfg) => cfg,
        Err(e) => {
            warn!("Unfortunately config we tried to generated is bad: {}. \
                This is a bug. Please report your command-line and run \
                `swindon-dev ... --show-config` to see the actual \
                generated text. ", e);
            exit(2);
        }
    };

    let mut lp = Core::new().unwrap();
    startup::populate_loop(&lp.handle(), &cfg, verbose);
    lp.run(futures::empty::<(), ()>()).unwrap();
}
<commit_msg>Same warning-silencing in main-dev<commit_after>// TODO(tailhook) until we fill all stabs
#![allow(dead_code)]

// I don't see **any** reason for this waring to enabled. We only build binary
// and most of these warnings do not apply to real visibility of types inside
// the crate
#![allow(private_in_public)]

#[macro_use] extern crate log;
#[macro_use] extern crate matches;
#[macro_use] extern crate quick_error;
#[macro_use] extern crate lazy_static;
extern crate env_logger;
extern crate futures;
extern crate futures_cpupool;
extern crate quire;
extern crate time;
extern crate argparse;
extern crate tokio_core;
extern crate tokio_service;
extern crate minihttp;
extern crate netbuf;
extern crate mime;
extern crate sha1;
extern crate mime_guess;
extern crate tk_sendfile;
extern crate tk_bufstream;
extern crate rustc_serialize;
extern crate tokio_curl;
extern crate curl;
extern crate byteorder;
extern crate httparse;
extern crate httpbin;
extern crate slab;
extern crate string_intern;

mod intern;
mod config;
mod handler;
mod handlers;
mod routing;
mod serializer;
mod default_error_page;
mod response;
mod websocket;
mod chat;
mod dev;
mod startup;

// Utils
mod short_circuit;
mod either;

use std::process::exit;
use std::env;

use argparse::{ArgumentParser, Parse, StoreTrue, Print, List, StoreFalse};
use tokio_core::reactor::Core;

pub use response::Pickler;

pub fn main() {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "warn");
    }
    env_logger::init().unwrap();

    let mut verbose = true;
    let mut show_config = false;
    let mut port = 8000;
    let mut routes = Vec::<dev::Route>::new();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Runs a web server, configured from the command-line, or in other
            words runs swindon in a devd emulation mode (not all devd options
            are supported yet).
        ");
        ap.refer(&mut routes)
            .add_argument("route", List, "
                Add a route. Routes can be:
                (a) `subdomain/path=DEST` -- serves destination on
                    `http://subdomain.devd.io/path`,
                (b) `subdomain=DEST` -- serves destination at root of
                    subdomain,
                (c) `/path=DEST` -- serves destination
                    on `http://localhost/path`,
                (d) `DEST` -- is the same as `/=DEST`.
                Destinations can be:
                (i) `./local/dir` -- serves files from filesystem,
                (ii) `http://host:12345/` -- proxy requests to specified host.
                Note: unlike in original `devd` we currently keep original
                `Host` in requests to proxy.
            ");
        ap.refer(&mut port)
            .add_option(&["-p", "--port"], Parse, "Listen on specified port");
        ap.refer(&mut show_config)
            .add_option(&["--show-config"], StoreTrue,
            "Show config for swindon that is generate by swindon-dev and
             exit");
        ap.add_option(&["--version"],
            Print(env!("CARGO_PKG_VERSION").to_string()),
            "Show version");
        ap.refer(&mut verbose)
            .add_option(&["--quiet"], StoreFalse,
            "Hide some user-friendly startup messages");
        ap.parse_args_or_exit();
    }

    let config = dev::generate_config(port, &routes);
    if show_config {
        print!("{}", config);
        exit(0);
    }

    let cfg = match config::ConfigCell::from_string(
        &config, "<swindon-dev cli>")
    {
        Ok(cfg) => cfg,
        Err(e) => {
            warn!("Unfortunately config we tried to generated is bad: {}. \
                This is a bug. Please report your command-line and run \
                `swindon-dev ... --show-config` to see the actual \
                generated text. ", e);
            exit(2);
        }
    };

    let mut lp = Core::new().unwrap();
    startup::populate_loop(&lp.handle(), &cfg, verbose);
    lp.run(futures::empty::<(), ()>()).unwrap();
}
<|endoftext|>


<commit_before>use js::value::{Value, ValueData, ResultValue, VNumber, VInteger, to_value, from_value};
use std::f64::{NAN, MAX_VALUE, MIN_VALUE, INFINITY, NEG_INFINITY, EPSILON};
/// Parse a float into a value
pub fn parse_float(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let parsed = from_str::<f64>(from_value::<StrBuf>(*args.get(0)).unwrap().into_owned());
	return Ok(to_value(match parsed {
		Some(v) => v,
		None => NAN
	}));
}
/// Parse an int into a value
pub fn parse_int(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let parsed = from_str::<i32>(from_value::<StrBuf>(*args.get(0)).unwrap().into_owned());
	return Ok(match parsed {
		Some(v) => to_value(v),
		None => to_value(NAN)
	});
}
/// Check if a value when converted to a number is finite
pub fn is_finite(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(to_value(if args.len() == 0 {
		false
	} else {
		from_value::<f64>(*args.get(0)).unwrap().is_finite()
	}))
}
/// Check if a number is finite
pub fn strict_is_finite(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(to_value(if args.len() == 0 {
		false
	} else {
		let num = args.get(0).borrow();
		match *num {
			VNumber(v) => v.is_finite(),
			VInteger(_) => true, // integers can't be infinite
			_ => false
		}
	}))
}
/// Check if a value when converted to a number is equal to NaN
pub fn is_nan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(to_value(if args.len() == 0 {
		false
	} else {
		from_value::<f64>(*args.get(0)).unwrap().is_nan()
	}))
}
/// Check if a number is equal to NaN
pub fn strict_is_nan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(to_value(if args.len() == 0 {
		false
	} else {
		let num = args.get(0).borrow();
		match *num {
			VNumber(v) => v.is_nan(),
			VInteger(_) => true, // integers can't be NaN
			_ => false
		}
	}))
}
/// Create a new `Number` object
pub fn _create(global:Value) -> Value {
	let number = ValueData::new_obj(Some(global));
	let number_ptr = number.borrow();
	number_ptr.set_field_slice("NaN", to_value(NAN));
	number_ptr.set_field_slice("MAX_VALUE", to_value(MAX_VALUE));
	number_ptr.set_field_slice("MIN_VALUE", to_value(MIN_VALUE));
	number_ptr.set_field_slice("POSITIVE_INFINITY", to_value(INFINITY));
	number_ptr.set_field_slice("NEGATIVE_INFINITY", to_value(NEG_INFINITY));
	number_ptr.set_field_slice("EPSILON", to_value(EPSILON));
	number_ptr.set_field_slice("parseFloat", to_value(parse_float));
	number_ptr.set_field_slice("parseInt", to_value(parse_int));
	number_ptr.set_field_slice("isFinite", to_value(strict_is_finite));
	number_ptr.set_field_slice("isNaN", to_value(strict_is_nan));
	number
}
/// Initialise the parse functions and `Number` on the global object
pub fn init(global:Value) {
	let global_ptr = global.borrow();
	global_ptr.set_field_slice("NaN", to_value(NAN));
	global_ptr.set_field_slice("Infinity", to_value(INFINITY));
	global_ptr.set_field_slice("parseFloat", to_value(parse_float));
	global_ptr.set_field_slice("parseInt", to_value(parse_int));
	global_ptr.set_field_slice("isFinite", to_value(is_finite));
	global_ptr.set_field_slice("isNaN", to_value(is_nan));
	global_ptr.set_field_slice("Number", _create(global));
}<commit_msg>Use slice instead of owned string in parsing functions<commit_after>use js::value::{Value, ValueData, ResultValue, VNumber, VInteger, to_value, from_value};
use std::f64::{NAN, MAX_VALUE, MIN_VALUE, INFINITY, NEG_INFINITY, EPSILON};
/// Parse a float into a value
pub fn parse_float(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let parsed = from_str::<f64>(from_value::<StrBuf>(*args.get(0)).unwrap().as_slice());
	return Ok(to_value(match parsed {
		Some(v) => v,
		None => NAN
	}));
}
/// Parse an int into a value
pub fn parse_int(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let parsed = from_str::<i32>(from_value::<StrBuf>(*args.get(0)).unwrap().as_slice());
	return Ok(match parsed {
		Some(v) => to_value(v),
		None => to_value(NAN)
	});
}
/// Check if a value when converted to a number is finite
pub fn is_finite(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(to_value(if args.len() == 0 {
		false
	} else {
		from_value::<f64>(*args.get(0)).unwrap().is_finite()
	}))
}
/// Check if a number is finite
pub fn strict_is_finite(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(to_value(if args.len() == 0 {
		false
	} else {
		let num = args.get(0).borrow();
		match *num {
			VNumber(v) => v.is_finite(),
			VInteger(_) => true, // integers can't be infinite
			_ => false
		}
	}))
}
/// Check if a value when converted to a number is equal to NaN
pub fn is_nan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(to_value(if args.len() == 0 {
		false
	} else {
		from_value::<f64>(*args.get(0)).unwrap().is_nan()
	}))
}
/// Check if a number is equal to NaN
pub fn strict_is_nan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(to_value(if args.len() == 0 {
		false
	} else {
		let num = args.get(0).borrow();
		match *num {
			VNumber(v) => v.is_nan(),
			VInteger(_) => true, // integers can't be NaN
			_ => false
		}
	}))
}
/// Create a new `Number` object
pub fn _create(global:Value) -> Value {
	let number = ValueData::new_obj(Some(global));
	let number_ptr = number.borrow();
	number_ptr.set_field_slice("NaN", to_value(NAN));
	number_ptr.set_field_slice("MAX_VALUE", to_value(MAX_VALUE));
	number_ptr.set_field_slice("MIN_VALUE", to_value(MIN_VALUE));
	number_ptr.set_field_slice("POSITIVE_INFINITY", to_value(INFINITY));
	number_ptr.set_field_slice("NEGATIVE_INFINITY", to_value(NEG_INFINITY));
	number_ptr.set_field_slice("EPSILON", to_value(EPSILON));
	number_ptr.set_field_slice("parseFloat", to_value(parse_float));
	number_ptr.set_field_slice("parseInt", to_value(parse_int));
	number_ptr.set_field_slice("isFinite", to_value(strict_is_finite));
	number_ptr.set_field_slice("isNaN", to_value(strict_is_nan));
	number
}
/// Initialise the parse functions and `Number` on the global object
pub fn init(global:Value) {
	let global_ptr = global.borrow();
	global_ptr.set_field_slice("NaN", to_value(NAN));
	global_ptr.set_field_slice("Infinity", to_value(INFINITY));
	global_ptr.set_field_slice("parseFloat", to_value(parse_float));
	global_ptr.set_field_slice("parseInt", to_value(parse_int));
	global_ptr.set_field_slice("isFinite", to_value(is_finite));
	global_ptr.set_field_slice("isNaN", to_value(is_nan));
	global_ptr.set_field_slice("Number", _create(global));
}<|endoftext|>


<commit_before>use sass::color_value::ColorValue;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use sass::op::Op;

use error::Result;
use tokenizer_utils::*;

use std::borrow::Cow::Borrowed;

#[derive(Debug)]
pub struct ValueTokenizer<'a> {
    toker: Toker<'a>,
}

impl<'a> ValueTokenizer<'a> {
    pub fn new(inner_str: &'a str) -> ValueTokenizer<'a> {
        ValueTokenizer {
            toker: Toker {
                inner_str: &inner_str,
                bytes: &inner_str.as_bytes(),
                offset: 0,
            },
        }
    }

    fn limit(&self) -> usize {
        self.toker.limit()
    }

    pub fn parse(&mut self) -> Result<Option<ValuePart<'a>>> {
        self.toker.skip_leading_whitespace();

        let start = self.toker.offset;
        let mut i = self.toker.offset;

        let ret = if start == self.limit() {
            None
        } else if is_operator(self.toker.bytes[start]) {
            self.toker.offset = start + 1;
            Some(ValuePart::Operator(self.toker.inner_str[start..start + 1].parse().unwrap_or(Op::Plus)))
        } else if is_number(self.toker.bytes[start]) {
            i += self.toker.scan_while_or_end(i, is_number);
            self.toker.offset = i;
            if i < self.limit() && valid_unit_char(self.toker.bytes[i]) {
                let unit_start = i;
                i += self.toker.scan_while_or_end(i, valid_unit_char);
                self.toker.offset = i;
                Some(ValuePart::Number(NumberValue::with_units(
                    self.toker.inner_str[start..unit_start].parse().unwrap_or(0.0),
                    Borrowed(&self.toker.inner_str[unit_start..i]),
                )))
            }
            else {
                Some(ValuePart::Number(NumberValue::from_scalar(
                    self.toker.inner_str[start..i].parse().unwrap_or(0.0)
                )))
            }
        } else if self.toker.bytes[start] == b'$' {
            i += self.toker.scan_while_or_end(i, isnt_space);
            self.toker.offset = i;
            Some(ValuePart::Variable(Borrowed(&self.toker.inner_str[start..i])))
        } else if self.toker.eat("#").is_ok() {
            i = self.toker.offset;
            i += self.toker.scan_while_or_end(i, valid_hex_char);
            self.toker.offset = i;
            match ColorValue::from_hex(Borrowed(&self.toker.inner_str[start..i])) {
                Ok(v) => Some(ValuePart::Color(v)),
                Err(e) => return Err(e),
            }
        } else if self.toker.eat("rgb(").is_ok() {
            let r = self.eat_color_u8();
            try!(self.toker.eat(","));
            self.toker.skip_leading_whitespace();
            let g = self.eat_color_u8();
            try!(self.toker.eat(","));
            self.toker.skip_leading_whitespace();
            let b = self.eat_color_u8();
            try!(self.toker.eat(")"));

            Some(ValuePart::Color(
                ColorValue {
                    red: r, green: g, blue: b,
                    computed: false,
                    original: Borrowed(&self.toker.inner_str[start..self.toker.offset]),
                }
            ))
        } else {
            i += self.toker.scan_while_or_end(start, isnt_space);
            self.toker.offset = i;
            Some(ValuePart::String(Borrowed(&self.toker.inner_str[start..i])))
        };

        Ok(ret)
    }

    fn eat_color_u8(&mut self) -> u8 {
        let mut i = self.toker.offset;
        let color_start = i;

        i += self.toker.scan_while_or_end(i, is_number);
        self.toker.offset = i;
        self.toker.inner_str[color_start..i].parse().unwrap_or(0)
    }
}

impl<'a> Iterator for ValueTokenizer<'a> {
    type Item = Result<ValuePart<'a>>;

    fn next(&mut self) -> Option<Result<ValuePart<'a>>> {
        if !self.toker.at_eof() {
            return match self.parse() {
                Ok(Some(v)) => Some(Ok(v)),
                Ok(None) => None,
                Err(e) => Some(Err(e)),
            }
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::color_value::ColorValue;
    use sass::value_part::ValuePart;
    use sass::number_value::NumberValue;
    use sass::op::Op;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_returns_string_part() {
        let mut vt = ValueTokenizer::new("foo");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_space_separated_string_parts() {
        let mut vt = ValueTokenizer::new("foo bar");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"bar")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_variable() {
        let mut vt = ValueTokenizer::new("$foo");
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$foo")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_variables_and_string_parts() {
        let mut vt = ValueTokenizer::new("foo $bar baz $quux");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$bar")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"baz")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$quux")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_number() {
        let mut vt = ValueTokenizer::new("3");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_two_numbers() {
        let mut vt = ValueTokenizer::new("3 8.9");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(8.9)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_units() {
        let mut vt = ValueTokenizer::new("3px");
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(3.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_units_but_not_parens() {
        let mut vt = ValueTokenizer::new("(3px)");
        assert_eq!(Some(Ok(ValuePart::Operator(Op::LeftParen))), vt.next());
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(3.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_percents_as_units() {
        let mut vt = ValueTokenizer::new("10px 8%");
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(10.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(8.0, Borrowed(&"%"))))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_operator() {
        let mut vt = ValueTokenizer::new("+");
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_and_operators() {
        let mut vt = ValueTokenizer::new("6 + 75.2");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(6.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(75.2)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_and_operators_without_spaces() {
        let mut vt = ValueTokenizer::new("6+75.2");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(6.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(75.2)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_does_stuff_with_parens() {
        let mut vt = ValueTokenizer::new("2+(3 4)");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(2.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::LeftParen))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(4.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_does_stuff_with_slash_separators() {
        let mut vt = ValueTokenizer::new("15 / 3 / 5");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(15.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Slash))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Slash))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(5.0)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_hex() {
        let mut vt = ValueTokenizer::new("#aabbcc");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 170, green: 187, blue: 204, computed: false, original: Borrowed("#aabbcc"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_short_hex() {
        let mut vt = ValueTokenizer::new("#cba");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 204, green: 187, blue: 170, computed: false, original: Borrowed("#cba"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_hex_is_separate_from_parens() {
        let mut vt = ValueTokenizer::new("#cba)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 204, green: 187, blue: 170, computed: false, original: Borrowed("#cba"),
            }))),
            vt.next()
        );
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_rgb() {
        let mut vt = ValueTokenizer::new("rgb(10,100,73)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 10, green: 100, blue: 73,
                computed: false, original: Borrowed("rgb(10,100,73)"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_rgb_with_spaces() {
        let mut vt = ValueTokenizer::new("rgb(10, 100, 73)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 10, green: 100, blue: 73,
                computed: false, original: Borrowed("rgb(10, 100, 73)"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }
}
<commit_msg>Differentiate between colors and interpolations<commit_after>use sass::color_value::ColorValue;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use sass::op::Op;

use error::Result;
use tokenizer_utils::*;

use std::borrow::Cow::Borrowed;

#[derive(Debug)]
pub struct ValueTokenizer<'a> {
    toker: Toker<'a>,
}

impl<'a> ValueTokenizer<'a> {
    pub fn new(inner_str: &'a str) -> ValueTokenizer<'a> {
        ValueTokenizer {
            toker: Toker {
                inner_str: &inner_str,
                bytes: &inner_str.as_bytes(),
                offset: 0,
            },
        }
    }

    fn limit(&self) -> usize {
        self.toker.limit()
    }

    pub fn parse(&mut self) -> Result<Option<ValuePart<'a>>> {
        self.toker.skip_leading_whitespace();

        let start = self.toker.offset;
        let mut i = self.toker.offset;

        let ret = if start == self.limit() {
            None
        } else if is_operator(self.toker.bytes[start]) {
            self.toker.offset = start + 1;
            Some(ValuePart::Operator(self.toker.inner_str[start..start + 1].parse().unwrap_or(Op::Plus)))
        } else if is_number(self.toker.bytes[start]) {
            i += self.toker.scan_while_or_end(i, is_number);
            self.toker.offset = i;
            if i < self.limit() && valid_unit_char(self.toker.bytes[i]) {
                let unit_start = i;
                i += self.toker.scan_while_or_end(i, valid_unit_char);
                self.toker.offset = i;
                Some(ValuePart::Number(NumberValue::with_units(
                    self.toker.inner_str[start..unit_start].parse().unwrap_or(0.0),
                    Borrowed(&self.toker.inner_str[unit_start..i]),
                )))
            }
            else {
                Some(ValuePart::Number(NumberValue::from_scalar(
                    self.toker.inner_str[start..i].parse().unwrap_or(0.0)
                )))
            }
        } else if self.toker.bytes[start] == b'$' {
            i += self.toker.scan_while_or_end(i, isnt_space);
            self.toker.offset = i;
            Some(ValuePart::Variable(Borrowed(&self.toker.inner_str[start..i])))
        } else if self.toker.eat("#").is_ok() {
            if self.toker.eat("{").is_ok() {
                i = self.toker.offset;
                let start_interpolation = i;
                i += self.toker.scan_while_or_end(i, (|c| c != b'}' ));
                self.toker.offset = i;
                try!(self.toker.eat("}"));
                Some(ValuePart::String(Borrowed(
                    &self.toker.inner_str[start_interpolation..i]
                )))
            } else {
                i = self.toker.offset;
                i += self.toker.scan_while_or_end(i, valid_hex_char);
                self.toker.offset = i;
                match ColorValue::from_hex(Borrowed(&self.toker.inner_str[start..i])) {
                    Ok(v) => Some(ValuePart::Color(v)),
                    Err(e) => return Err(e),
                }
            }
        } else if self.toker.eat("rgb(").is_ok() {
            let r = self.eat_color_u8();
            try!(self.toker.eat(","));
            self.toker.skip_leading_whitespace();
            let g = self.eat_color_u8();
            try!(self.toker.eat(","));
            self.toker.skip_leading_whitespace();
            let b = self.eat_color_u8();
            try!(self.toker.eat(")"));

            Some(ValuePart::Color(
                ColorValue {
                    red: r, green: g, blue: b,
                    computed: false,
                    original: Borrowed(&self.toker.inner_str[start..self.toker.offset]),
                }
            ))
        } else {
            i += self.toker.scan_while_or_end(start, isnt_space);
            self.toker.offset = i;
            Some(ValuePart::String(Borrowed(&self.toker.inner_str[start..i])))
        };

        Ok(ret)
    }

    fn eat_color_u8(&mut self) -> u8 {
        let mut i = self.toker.offset;
        let color_start = i;

        i += self.toker.scan_while_or_end(i, is_number);
        self.toker.offset = i;
        self.toker.inner_str[color_start..i].parse().unwrap_or(0)
    }
}

impl<'a> Iterator for ValueTokenizer<'a> {
    type Item = Result<ValuePart<'a>>;

    fn next(&mut self) -> Option<Result<ValuePart<'a>>> {
        if !self.toker.at_eof() {
            return match self.parse() {
                Ok(Some(v)) => Some(Ok(v)),
                Ok(None) => None,
                Err(e) => Some(Err(e)),
            }
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::color_value::ColorValue;
    use sass::value_part::ValuePart;
    use sass::number_value::NumberValue;
    use sass::op::Op;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_returns_string_part() {
        let mut vt = ValueTokenizer::new("foo");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_space_separated_string_parts() {
        let mut vt = ValueTokenizer::new("foo bar");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"bar")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_variable() {
        let mut vt = ValueTokenizer::new("$foo");
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$foo")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_variables_and_string_parts() {
        let mut vt = ValueTokenizer::new("foo $bar baz $quux");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$bar")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"baz")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$quux")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_number() {
        let mut vt = ValueTokenizer::new("3");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_two_numbers() {
        let mut vt = ValueTokenizer::new("3 8.9");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(8.9)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_units() {
        let mut vt = ValueTokenizer::new("3px");
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(3.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_units_but_not_parens() {
        let mut vt = ValueTokenizer::new("(3px)");
        assert_eq!(Some(Ok(ValuePart::Operator(Op::LeftParen))), vt.next());
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(3.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_percents_as_units() {
        let mut vt = ValueTokenizer::new("10px 8%");
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(10.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(8.0, Borrowed(&"%"))))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_operator() {
        let mut vt = ValueTokenizer::new("+");
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_and_operators() {
        let mut vt = ValueTokenizer::new("6 + 75.2");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(6.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(75.2)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_and_operators_without_spaces() {
        let mut vt = ValueTokenizer::new("6+75.2");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(6.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(75.2)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_does_stuff_with_parens() {
        let mut vt = ValueTokenizer::new("2+(3 4)");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(2.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::LeftParen))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(4.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_does_stuff_with_slash_separators() {
        let mut vt = ValueTokenizer::new("15 / 3 / 5");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(15.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Slash))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Slash))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(5.0)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_hex() {
        let mut vt = ValueTokenizer::new("#aabbcc");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 170, green: 187, blue: 204, computed: false, original: Borrowed("#aabbcc"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_short_hex() {
        let mut vt = ValueTokenizer::new("#cba");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 204, green: 187, blue: 170, computed: false, original: Borrowed("#cba"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_hex_is_separate_from_parens() {
        let mut vt = ValueTokenizer::new("#cba)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 204, green: 187, blue: 170, computed: false, original: Borrowed("#cba"),
            }))),
            vt.next()
        );
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_rgb() {
        let mut vt = ValueTokenizer::new("rgb(10,100,73)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 10, green: 100, blue: 73,
                computed: false, original: Borrowed("rgb(10,100,73)"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_rgb_with_spaces() {
        let mut vt = ValueTokenizer::new("rgb(10, 100, 73)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 10, green: 100, blue: 73,
                computed: false, original: Borrowed("rgb(10, 100, 73)"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }
}
<|endoftext|>


<commit_before>use iron::prelude::*;
use base::framework::{json_error_response, json_ok_response,
                      not_found_response};
use urlencoded::UrlEncodedBody;
use base::db::MyPool;
use base::validator::{Validator, Checker, Str, StrValue, Int, IntValue, Min};
use base::framework::LoginUser;
use iron_login::User as U;
use persistent::Read;
use chrono::*;
use mysql as my;
use regex::Regex;
use regex::Captures;
use base::config::Config;
use base::constant;

pub fn new(req: &mut Request) -> IronResult<Response> {
    let mut validator = Validator::new();
    validator
        .add_checker(Checker::new("article_id", Int, "文章ID") << Min(1))
        .add_checker(Checker::new("content", Str, "内容") << Min(7));

    validator.validate(req.get::<UrlEncodedBody>());
    if !validator.is_valid() {
        return json_error_response(&validator.messages[0]);
    }

    let article_id = validator.get_valid::<IntValue>("article_id").value() as u64;

    let pool = req.get::<Read<MyPool>>().unwrap().value();
    let mut trans = pool.start_transaction(false, None, None).unwrap();

    // check whether article exists
    let raw_row = trans.prep_exec("SELECT user_id from article where id=? for update",
                                  (&article_id,)).unwrap().next();
    if raw_row.is_none() {
            return not_found_response();
    };

    let article_user_id: u64 = my::from_row(raw_row.unwrap().unwrap());

    let content = validator.get_valid::<StrValue>("content").value();
    let login = LoginUser::get_login(req);
    let user = login.get_user().unwrap();
    let now = Local::now().naive_local();

    // parse mentions such as @foo @bar
    let re = Regex::new(r"\B@([\da-zA-Z_]+)").unwrap();
    let config = req.get::<Read<Config>>().unwrap();
    let app_path = config.get("app_path").as_str().unwrap();

    let mut mentions: Vec<u64> = Vec::new();
    let new_content = re.replace_all(&content, |cap: &Captures| {
        match handle_mention(&mut trans, cap.at(1).unwrap()) {
            Some(user_id) => {
                mentions.push(user_id);
                format!("[@{}]({}{}{})",
                        cap.at(1).unwrap(),
                        app_path,
                        "/user/",
                        user_id)
            },
            None => format!("@{}", cap.at(1).unwrap()),
        }
    });

    let comment_id = trans.prep_exec(
        "INSERT INTO comment(article_id, user_id, content, create_time) \
         VALUES (?, ?, ?, ?)",
        (article_id, user.id, new_content, now)).unwrap().last_insert_id();

    trans.prep_exec("UPDATE article set comments_count=comments_count+1 where id=?",
                    (article_id,)).unwrap();

    // send message to article's author
    trans.prep_exec("INSERT INTO message(article_id, comment_id, \
                     from_user_id, to_user_id, mode, \
                    status, create_time) VALUES (?, ?, ?, ?, ?, ?, ?)",
                   (article_id, comment_id, user.id, article_user_id,
                    constant::MESSAGE::MODE::REPLY_ARTICLE,
                    constant::MESSAGE::STATUS::INIT, now)).unwrap();

    // send message to mentions
    for mention in mentions {
        if mention == article_user_id {
            continue;
        }
        trans.prep_exec("INSERT INTO message(article_id, comment_id, \
                         from_user_id, to_user_id, mode, \
                         status, create_time) VALUES (?, ?, ?, ?, ?, ?, ?)",
                        (article_id, comment_id, user.id, mention,
                         constant::MESSAGE::MODE::MENTION,
                         constant::MESSAGE::STATUS::INIT, now)).unwrap();
    }

    trans.commit().unwrap();

    json_ok_response()
}

fn handle_mention(trans: &mut my::Transaction, username: &str) -> Option<u64> {

    trans.prep_exec("SELECT id from user where username=?", (username,)).unwrap()
        .next().map(|row| my::from_row(row.unwrap()))
}
<commit_msg>do not record my own replies as my messages.<commit_after>use iron::prelude::*;
use base::framework::{json_error_response, json_ok_response,
                      not_found_response};
use urlencoded::UrlEncodedBody;
use base::db::MyPool;
use base::validator::{Validator, Checker, Str, StrValue, Int, IntValue, Min};
use base::framework::LoginUser;
use iron_login::User as U;
use persistent::Read;
use chrono::*;
use mysql as my;
use regex::Regex;
use regex::Captures;
use base::config::Config;
use base::constant;

pub fn new(req: &mut Request) -> IronResult<Response> {
    let mut validator = Validator::new();
    validator
        .add_checker(Checker::new("article_id", Int, "文章ID") << Min(1))
        .add_checker(Checker::new("content", Str, "内容") << Min(7));

    validator.validate(req.get::<UrlEncodedBody>());
    if !validator.is_valid() {
        return json_error_response(&validator.messages[0]);
    }

    let article_id = validator.get_valid::<IntValue>("article_id").value() as u64;

    let pool = req.get::<Read<MyPool>>().unwrap().value();
    let mut trans = pool.start_transaction(false, None, None).unwrap();

    // check whether article exists
    let raw_row = trans.prep_exec("SELECT user_id from article where id=? for update",
                                  (&article_id,)).unwrap().next();
    if raw_row.is_none() {
            return not_found_response();
    };

    let article_user_id: u64 = my::from_row(raw_row.unwrap().unwrap());

    let content = validator.get_valid::<StrValue>("content").value();
    let login = LoginUser::get_login(req);
    let user = login.get_user().unwrap();
    let now = Local::now().naive_local();

    // parse mentions such as @foo @bar
    let re = Regex::new(r"\B@([\da-zA-Z_]+)").unwrap();
    let config = req.get::<Read<Config>>().unwrap();
    let app_path = config.get("app_path").as_str().unwrap();

    let mut mentions: Vec<u64> = Vec::new();
    let new_content = re.replace_all(&content, |cap: &Captures| {
        match handle_mention(&mut trans, cap.at(1).unwrap()) {
            Some(user_id) => {
                mentions.push(user_id);
                format!("[@{}]({}{}{})",
                        cap.at(1).unwrap(),
                        app_path,
                        "/user/",
                        user_id)
            },
            None => format!("@{}", cap.at(1).unwrap()),
        }
    });

    let comment_id = trans.prep_exec(
        "INSERT INTO comment(article_id, user_id, content, create_time) \
         VALUES (?, ?, ?, ?)",
        (article_id, user.id, new_content, now)).unwrap().last_insert_id();

    trans.prep_exec("UPDATE article set comments_count=comments_count+1 where id=?",
                    (article_id,)).unwrap();

    // send message to article's author
    if article_user_id != user.id {
        trans.prep_exec("INSERT INTO message(article_id, comment_id, \
                         from_user_id, to_user_id, mode, \
                         status, create_time) VALUES (?, ?, ?, ?, ?, ?, ?)",
                        (article_id, comment_id, user.id, article_user_id,
                         constant::MESSAGE::MODE::REPLY_ARTICLE,
                         constant::MESSAGE::STATUS::INIT, now)).unwrap();
    }

    // send message to mentions
    mentions.sort();
    mentions.dedup();
    for mention in mentions.iter().filter(|&x| *x != article_user_id && *x != user.id) {
        trans.prep_exec("INSERT INTO message(article_id, comment_id, \
                         from_user_id, to_user_id, mode, \
                         status, create_time) VALUES (?, ?, ?, ?, ?, ?, ?)",
                        (article_id, comment_id, user.id, mention,
                         constant::MESSAGE::MODE::MENTION,
                         constant::MESSAGE::STATUS::INIT, now)).unwrap();
    }

    trans.commit().unwrap();

    json_ok_response()
}

fn handle_mention(trans: &mut my::Transaction, username: &str) -> Option<u64> {

    trans.prep_exec("SELECT id from user where username=?", (username,)).unwrap()
        .next().map(|row| my::from_row(row.unwrap()))
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/strictly-palindromic-number/
pub fn is_strictly_palindromic(n: i32) -> bool {
    todo!()
}

fn main() {
    println!("{}", is_strictly_palindromic(9)); // false
    println!("{}", is_strictly_palindromic(4)); // false
}
<commit_msg>Solve problem 2396<commit_after>// https://leetcode.com/problems/strictly-palindromic-number/
pub fn is_strictly_palindromic(n: i32) -> bool {
    false
}

fn main() {
    println!("{}", is_strictly_palindromic(9)); // false
    println!("{}", is_strictly_palindromic(4)); // false
}
<|endoftext|>