<commit_before>
use std::{cmp, fmt};
use std::io;
use std::io::prelude::*;

#[derive(Copy,Clone,PartialEq,Eq,Debug)]
enum Character {
    Player,
    Boss,
}

#[derive(Copy,Clone)]
struct Stats {
    health: i32,
    attack: i32,
    armor: i32,
    mana: i32,
}

#[derive(Clone,PartialEq,Eq,Debug)]
struct Spell {
    name: String,
    cost: i32, // Cost to cast
    duration: i32, // 0 means instant
    damage: i32, // Damage done to enemy
    healing: i32, // Healing factor for yourself
    armor: i32, // Bonus armor amount
    mana: i32, // Recharge amount
}

impl Spell {
    fn new(name: &str,
           cost: i32,
           duration: i32,
           damage: i32,
           healing: i32,
           armor: i32,
           mana: i32)
           -> Spell {
        Spell {
            name: String::from(name),
            cost: cost,
            duration: duration,
            damage: damage,
            healing: healing,
            armor: armor,
            mana: mana,
        }
    }
}
impl Spell {
    fn print_initial_cast_message(&self) {
        print!("Player casts {}", self);
        if self.armor > 0 {
            print!(", increasing armor by {}", self.armor);
        }
        if self.damage > 0 && self.duration == 0 {
            print!(", dealing {} damage", self.damage);
        }
        if self.healing > 0 && self.duration == 0 {
            print!(", and healing {} hit points", self.healing);
        }
        println!(".");
    }
}
impl fmt::Display for Spell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name)
    }
}

#[derive(Clone)]
struct Effect {
    spell: Spell,
    turns_remaining: i32,
}

#[derive(Clone)]
struct BattleState {
    player: Stats,
    boss: Stats,
    effects: Vec<Effect>,
    mana_used: i32,
    turn: i32,
}
impl BattleState {
    fn print_state(&self, active_character: Character, verbose: bool) {
        if verbose {
            println!("");
        };
        if verbose {
            println!("--{:?} turn {}--", active_character, self.turn);
        };

        // Print stats
        if verbose {
            println!("Player has {} hit points, {} armor, {} mana",
                     self.player.health,
                     self.player.armor,
                     self.player.mana);
        };

        if verbose {
            println!("{} active spells", self.effects.len());
        }

        if verbose {
            println!("Boss has {} hit points", self.boss.health);
        };
    }

    fn apply_ongoing_effects(&mut self, verbose: bool) {
        for effect in self.effects.iter_mut() {
            effect.turns_remaining -= 1;

            if effect.spell.armor > 0 {
                if verbose {
                    println!("Shield's timer is now {}.", effect.turns_remaining);
                };
                if effect.turns_remaining > 0 {
                    self.player.armor = effect.spell.armor;
                } else {
                    if verbose {
                        println!("Shield wears off, decreasing armor by 7.");
                    };
                    self.player.armor -= effect.spell.armor;
                }
            }
            if effect.spell.damage > 0 {
                self.boss.health -= effect.spell.damage;
                if verbose {
                    println!("Poison deals 3 damage; its timer is now {}.",
                             effect.turns_remaining);
                };
                if verbose {
                    println!("Boss health now {}.", self.boss.health);
                };
            }
            if effect.spell.mana > 0 {
                self.player.mana += effect.spell.mana;
                if verbose {
                    println!("Recharge provides 101 mana (now {}); its timer is now {}",
                             self.player.mana,
                             effect.turns_remaining);
                };
            }
        }
        // Remove timed-out effects
        self.effects = self.effects.iter().filter(|s| s.turns_remaining > 0).cloned().collect();
    }

    fn is_spell_active(&self, spell: &Spell) -> bool {
        self.effects.iter().any(|ref s| s.spell.name == spell.name)
    }
}

fn pause() {
    // Read a single byte and discard
    let _ = io::stdin().read(&mut [0u8]).unwrap();
}

fn print_player_turn(initial_state: &BattleState, spell_to_cast: Option<&Spell>) {
    // Replay all state messages and effects on a copy of the battle.
    let mut state = initial_state.clone();

    state.print_state(Character::Player, true);
    state.apply_ongoing_effects(true);

    match spell_to_cast {
        Some(ref spell) => spell.print_initial_cast_message(),
        None => (),
    }

    if state.player.mana < 53 {
        println!("##### Insufficent mana of {}. Player died #####",
                 state.player.mana);
    }
    if state.player.health <= 0 {
        println!("##### Player died #####");
    }
    if state.boss.health <= 0 {
        println!("***** Boss died *****");
    }
    pause();
}

fn print_boss_turn(initial_state: BattleState, damage: i32) {
    // Replay all state messages and effects on a copy of the battle.
    let mut state = initial_state.clone();

    state.print_state(Character::Boss, true);
    state.apply_ongoing_effects(true);

    if state.boss.health <= 0 {
        println!("***** Boss died *****");
        return;
    }

    println!("Boss attacks for {} damage.", damage);
    state.player.health -= damage;
    if state.player.health <= 0 {
        println!("##### Player died #####");
    }
}

// Run a round of battle and return the lowest amount of mana used to win.
// i32::max_value indicates a loss.
fn take_turn(initial_state: BattleState,
             active_character: Character,
             possible_spells: &Vec<Spell>)
             -> i32 {

    let verbose = false;
    //let verbose = true;

    let mut state = initial_state.clone();
    state.apply_ongoing_effects(false);

    // Check for victory from spell effects
    if state.boss.health <= 0 {
        // Player wins
        if verbose {
            print_player_turn(&initial_state, None);
        }
        return 0;
    }

    // if Player is active, cast spell
    if active_character == Character::Player {

        if state.player.mana < 53 {
            if verbose {
                print_player_turn(&initial_state, None);
            }
            return i32::max_value();
        }

        // Player casts spell
        let mut current_lowest_cost = i32::max_value();
        for spell_to_cast in possible_spells {

            let mut next_state = state.clone();

            if spell_to_cast.cost <= next_state.player.mana &&
               !next_state.is_spell_active(&spell_to_cast) {

                // Check for victory from spell effects
                if next_state.boss.health <= 0 {
                    // Player wins
                    // Didn't need to cast any spells, so zero cost. No need to continue checking.
                    if verbose {
                        print_player_turn(&initial_state, Some(spell_to_cast));
                    }
                    return 0;
                }

                // Subtract casting cost
                next_state.player.mana -= spell_to_cast.cost;

                if spell_to_cast.duration > 0 {
                    // Store delayed effects
                    next_state.effects.push(Effect {
                        spell: spell_to_cast.clone(),
                        turns_remaining: spell_to_cast.duration,
                    });
                } else {
                    // Apply immediate effects
                    next_state.boss.health -= spell_to_cast.damage;
                    next_state.player.health += spell_to_cast.healing;
                }

                // If boss is still alive, continue battle
                if next_state.boss.health > 0 {
                    next_state.turn += 1;

                    if verbose {
                        print_player_turn(&initial_state, Some(spell_to_cast));
                    }
                    let recursive_result = take_turn(next_state, Character::Boss, &possible_spells);
                    let total_cost = i32::saturating_add(recursive_result, spell_to_cast.cost);

                    current_lowest_cost = cmp::min(total_cost, current_lowest_cost);
                } else {
                    // Player wins
                    if verbose {
                        print_player_turn(&initial_state, Some(spell_to_cast));
                        println!("***** Boss died *****");
                    }
                    current_lowest_cost = cmp::min(spell_to_cast.cost, current_lowest_cost);
                }
            }
        }
        return current_lowest_cost;
    } else {
        // Boss's turn
        let mut next_state = state.clone();

        // Calculate damage
        let damage = next_state.boss.attack - next_state.player.armor;
        let damage = cmp::max(1, damage);
        next_state.player.health -= damage;

        if verbose {
            print_boss_turn(initial_state, damage);
        }

        if next_state.player.health > 0 {
            // Player is still alive to take a turn
            next_state.turn += 1;
            let cost = take_turn(next_state, Character::Player, &possible_spells);
            return cost;
        } else {
            return i32::max_value();    // Player died
        }
    };
}

fn main() {

    // Magic Missile costs 53 mana. It instantly does 4 damage.
    // Drain costs 73 mana. It instantly does 2 damage and heals you for 2 hit points.
    // Shield costs 113 mana. It starts an effect that lasts for 6 turns. While it is active, your armor is increased by 7.
    // Poison costs 173 mana. It starts an effect that lasts for 6 turns. At the start of each turn while it is active, it deals the boss 3 damage.
    // Recharge costs 229 mana. It starts an effect that lasts for 5 turns. At the start of each turn while it is active, it gives you 101 new mana.

    // name, cost, duration, damage, healing, armor, mana
    let possible_spells = vec![
        Spell::new("Magic Missle", 53, 0, 4, 0, 0, 0),
        Spell::new("Drain",        73, 0, 2, 2, 0, 0),
        Spell::new("Shield",      113, 6, 0, 0, 7, 0),
        Spell::new("Poison",      173, 6, 3, 0, 0, 0),
        Spell::new("Recharge",    229, 5, 0, 0, 0, 101),
    ];

    // Hit Points: 71
    // Damage: 10
    let starting_boss = Stats {health: 71, attack: 10, armor: 0, mana: 0};

    // You start with 50 hit points and 500 mana points.
    let starting_player = Stats {health: 50, attack: 0, armor: 0, mana: 500};

    // // Test characters
    // let starting_boss = Stats {
        // health: 14,
        // attack: 8,
        // armor: 0,
        // mana: 0,
    // };
    // let starting_player = Stats {
        // health: 10,
        // attack: 0,
        // armor: 0,
        // mana: 250,
    // };

    let initial_initial_state = BattleState {
        player: starting_player,
        boss: starting_boss,
        effects: Vec::new(),
        mana_used: 0,
        turn: 0,
    };

    let mana_used = take_turn(initial_initial_state, Character::Player, &possible_spells);

    println!("\n######");
    println!("Final mana used: {:?}", mana_used);

    assert!(mana_used == 1824);
}
<commit_msg>Day 22, part 2<commit_after>
use std::{cmp, fmt};
use std::io;
use std::io::prelude::*;

#[derive(Copy,Clone,PartialEq,Eq,Debug)]
enum Character {
    Player,
    Boss,
}

#[derive(Copy,Clone)]
struct Stats {
    health: i32,
    attack: i32,
    armor: i32,
    mana: i32,
}

#[derive(Clone,PartialEq,Eq,Debug)]
struct Spell {
    name: String,
    cost: i32, // Cost to cast
    duration: i32, // 0 means instant
    damage: i32, // Damage done to enemy
    healing: i32, // Healing factor for yourself
    armor: i32, // Bonus armor amount
    mana: i32, // Recharge amount
}

impl Spell {
    fn new(name: &str,
           cost: i32,
           duration: i32,
           damage: i32,
           healing: i32,
           armor: i32,
           mana: i32)
           -> Spell {
        Spell {
            name: String::from(name),
            cost: cost,
            duration: duration,
            damage: damage,
            healing: healing,
            armor: armor,
            mana: mana,
        }
    }
}
impl Spell {
    fn print_initial_cast_message(&self) {
        print!("Player casts {}", self);
        if self.armor > 0 {
            print!(", increasing armor by {}", self.armor);
        }
        if self.damage > 0 && self.duration == 0 {
            print!(", dealing {} damage", self.damage);
        }
        if self.healing > 0 && self.duration == 0 {
            print!(", and healing {} hit points", self.healing);
        }
        println!(".");
    }
}
impl fmt::Display for Spell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name)
    }
}

#[derive(Clone)]
struct Effect {
    spell: Spell,
    turns_remaining: i32,
}

#[derive(Clone)]
struct BattleState {
    player: Stats,
    boss: Stats,
    effects: Vec<Effect>,
    mana_used: i32,
    turn: i32,
}
impl BattleState {
    fn print_state(&self, active_character: Character, verbose: bool) {
        if verbose {
            println!("");
        };
        if verbose {
            println!("--{:?} turn {}--", active_character, self.turn);
        };

        // Print stats
        if verbose {
            println!("Player has {} hit points, {} armor, {} mana",
                     self.player.health,
                     self.player.armor,
                     self.player.mana);
        };

        if verbose {
            println!("{} active spells", self.effects.len());
        }

        if verbose {
            println!("Boss has {} hit points", self.boss.health);
        };
    }

    fn apply_ongoing_effects(&mut self, verbose: bool) {
        for effect in self.effects.iter_mut() {
            effect.turns_remaining -= 1;

            if effect.spell.armor > 0 {
                if verbose {
                    println!("Shield's timer is now {}.", effect.turns_remaining);
                };
                if effect.turns_remaining > 0 {
                    self.player.armor = effect.spell.armor;
                } else {
                    if verbose {
                        println!("Shield wears off, decreasing armor by 7.");
                    };
                    self.player.armor -= effect.spell.armor;
                }
            }
            if effect.spell.damage > 0 {
                self.boss.health -= effect.spell.damage;
                if verbose {
                    println!("Poison deals 3 damage; its timer is now {}.",
                             effect.turns_remaining);
                };
                if verbose {
                    println!("Boss health now {}.", self.boss.health);
                };
            }
            if effect.spell.mana > 0 {
                self.player.mana += effect.spell.mana;
                if verbose {
                    println!("Recharge provides 101 mana (now {}); its timer is now {}",
                             self.player.mana,
                             effect.turns_remaining);
                };
            }
        }
        // Remove timed-out effects
        self.effects = self.effects.iter().filter(|s| s.turns_remaining > 0).cloned().collect();
    }

    fn is_spell_active(&self, spell: &Spell) -> bool {
        self.effects.iter().any(|ref s| s.spell.name == spell.name)
    }
}

fn pause() {
    // Read a single byte and discard
    let _ = io::stdin().read(&mut [0u8]).unwrap();
}

fn print_player_turn(initial_state: &BattleState, spell_to_cast: Option<&Spell>) {
    // Replay all state messages and effects on a copy of the battle.
    let mut state = initial_state.clone();

    state.print_state(Character::Player, true);
    state.apply_ongoing_effects(true);

    match spell_to_cast {
        Some(ref spell) => spell.print_initial_cast_message(),
        None => (),
    }

    if state.player.mana < 53 {
        println!("##### Insufficent mana of {}. Player died #####",
                 state.player.mana);
    }
    if state.player.health <= 0 {
        println!("##### Player died #####");
    }
    if state.boss.health <= 0 {
        println!("***** Boss died *****");
    }
    pause();
}

fn print_boss_turn(initial_state: &BattleState, damage: i32) {
    // Replay all state messages and effects on a copy of the battle.
    let mut state = initial_state.clone();

    state.print_state(Character::Boss, true);
    state.apply_ongoing_effects(true);

    if state.boss.health <= 0 {
        println!("***** Boss died *****");
        return;
    }

    println!("Boss attacks for {} damage.", damage);
    state.player.health -= damage;
    if state.player.health <= 0 {
        println!("##### Player died #####");
    }
}

// Run a round of battle and return the lowest amount of mana used to win.
// i32::max_value indicates a loss.
fn take_turn(initial_state: &BattleState,
             active_character: Character,
             possible_spells: &Vec<Spell>,
             is_hard_mode: bool)
             -> i32 {

    let verbose = false;
    // let verbose = true;

    let mut state = initial_state.clone();

    // Hard mode: subtract 1 HP at the start of each turn
    if is_hard_mode && active_character == Character::Player {
        state.player.health -= 1;
        if state.player.health <= 0 {
            return i32::max_value();
        }
    }

    state.apply_ongoing_effects(false);

    // Check for victory from spell effects
    if state.boss.health <= 0 {
        // Player wins
        if verbose {
            print_player_turn(&initial_state, None);
        }
        return 0;
    }

    // if Player is active, cast spell
    if active_character == Character::Player {

        if state.player.mana < 53 {
            if verbose {
                print_player_turn(&initial_state, None);
            }
            return i32::max_value();
        }

        // Player casts spell
        let mut current_lowest_cost = i32::max_value();
        for spell_to_cast in possible_spells {

            let mut next_state = state.clone();

            if spell_to_cast.cost <= next_state.player.mana &&
               !next_state.is_spell_active(&spell_to_cast) {

                // Check for victory from spell effects
                if next_state.boss.health <= 0 {
                    // Player wins
                    // Didn't need to cast any spells, so zero cost. No need to continue checking.
                    if verbose {
                        print_player_turn(&initial_state, Some(spell_to_cast));
                    }
                    return 0;
                }

                // Subtract casting cost
                next_state.player.mana -= spell_to_cast.cost;

                if spell_to_cast.duration > 0 {
                    // Store delayed effects
                    next_state.effects.push(Effect {
                        spell: spell_to_cast.clone(),
                        turns_remaining: spell_to_cast.duration,
                    });
                } else {
                    // Apply immediate effects
                    next_state.boss.health -= spell_to_cast.damage;
                    next_state.player.health += spell_to_cast.healing;
                }

                // If boss is still alive, continue battle
                if next_state.boss.health > 0 {
                    next_state.turn += 1;

                    if verbose {
                        print_player_turn(&initial_state, Some(spell_to_cast));
                    }
                    let recursive_result = take_turn(&next_state,
                                                     Character::Boss,
                                                     &possible_spells,
                                                     is_hard_mode);
                    let total_cost = i32::saturating_add(recursive_result, spell_to_cast.cost);

                    current_lowest_cost = cmp::min(total_cost, current_lowest_cost);
                } else {
                    // Player wins
                    if verbose {
                        print_player_turn(&initial_state, Some(spell_to_cast));
                        println!("***** Boss died *****");
                    }
                    current_lowest_cost = cmp::min(spell_to_cast.cost, current_lowest_cost);
                }
            }
        }
        return current_lowest_cost;
    } else {
        // Boss's turn
        let mut next_state = state.clone();

        // Calculate damage
        let damage = next_state.boss.attack - next_state.player.armor;
        let damage = cmp::max(1, damage);
        next_state.player.health -= damage;

        if verbose {
            print_boss_turn(&initial_state, damage);
        }

        if next_state.player.health > 0 {
            // Player is still alive to take a turn
            next_state.turn += 1;
            let cost = take_turn(&next_state,
                                 Character::Player,
                                 &possible_spells,
                                 is_hard_mode);
            return cost;
        } else {
            return i32::max_value();    // Player died
        }
    };
}

fn main() {

    // Magic Missile costs 53 mana. It instantly does 4 damage.
    // Drain costs 73 mana. It instantly does 2 damage and heals you for 2 hit points.
    // Shield costs 113 mana. It starts an effect that lasts for 6 turns. While it is active, your armor is increased by 7.
    // Poison costs 173 mana. It starts an effect that lasts for 6 turns. At the start of each turn while it is active, it deals the boss 3 damage.
    // Recharge costs 229 mana. It starts an effect that lasts for 5 turns. At the start of each turn while it is active, it gives you 101 new mana.

    // name, cost, duration, damage, healing, armor, mana
    let possible_spells = vec![
        Spell::new("Magic Missle", 53, 0, 4, 0, 0, 0),
        Spell::new("Drain",        73, 0, 2, 2, 0, 0),
        Spell::new("Shield",      113, 6, 0, 0, 7, 0),
        Spell::new("Poison",      173, 6, 3, 0, 0, 0),
        Spell::new("Recharge",    229, 5, 0, 0, 0, 101),
    ];

    // Hit Points: 71
    // Damage: 10
    let starting_boss = Stats {
        health: 71,
        attack: 10,
        armor: 0,
        mana: 0,
    };

    // You start with 50 hit points and 500 mana points.
    let starting_player = Stats {
        health: 50,
        attack: 0,
        armor: 0,
        mana: 500,
    };

    // // Test characters
    // let starting_boss = Stats {
    // health: 14,
    // attack: 8,
    // armor: 0,
    // mana: 0,
    // };
    // let starting_player = Stats {
    // health: 10,
    // attack: 0,
    // armor: 0,
    // mana: 250,
    // };

    let initial_initial_state = BattleState {
        player: starting_player,
        boss: starting_boss,
        effects: Vec::new(),
        mana_used: 0,
        turn: 0,
    };

    let mana_used_easy = take_turn(&initial_initial_state,
                                   Character::Player,
                                   &possible_spells,
                                   false);

    println!("######");
    println!("Final mana used on easy: {:?}", mana_used_easy);
    assert!(mana_used_easy == 1824);

    let mana_used_hard = take_turn(&initial_initial_state,
                                   Character::Player,
                                   &possible_spells,
                                   true);

    println!("######");
    println!("Final mana used on hard: {:?}", mana_used_hard);
    assert!(mana_used_hard == 1937);
}
<|endoftext|>


<commit_before>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;

use conduit::{header, Host, RequestExt, Scheme, StatusCode};
use conduit_cookie::RequestSession;
use sentry::Level;

use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

const FILTERED_HEADERS: &[&str] = &["Authorization", "Cookie", "X-Real-Ip", "X-Forwarded-For"];

#[derive(Default)]
pub(super) struct LogRequests();

struct OriginalPath(String);

impl Middleware for LogRequests {
    fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
        let path = OriginalPath(req.path().to_string());
        req.mut_extensions().insert(path);
        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        let response_time =
            if let Ok(start_ms) = request_header(req, "x-request-start").parse::<u128>() {
                let current_ms = SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .expect("Time went way backwards")
                    .as_millis();

                if current_ms > start_ms {
                    // The result will not be negative, and will only be truncated for requests
                    // lasting billions of years.
                    (current_ms - start_ms) as u64
                } else {
                    // Because our nginx proxy and app run on the same dyno in production, we
                    // shouldn't have to worry about clock drift. But if something goes wrong,
                    // calculate the response time based on when the request reached this app.
                    fallback_response_time(req)
                }
            } else {
                // X-Request-Start header couldn't be parsed.
                // We are probably running locally and not behind nginx.
                fallback_response_time(req)
            };

        println!(
            "{}",
            RequestLine {
                req,
                res: &res,
                response_time,
            }
        );

        report_to_sentry(req, &res, response_time);

        res
    }
}

/// Calculate the response time based on when the request reached the in-app web server.
///
/// This serves as a fallback in case the `X-Request-Start` header is missing or invalid.
fn fallback_response_time(req: &mut dyn RequestExt) -> u64 {
    let elapsed = req.elapsed();
    elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_nanos()) / 1_000_000
}

struct CustomMetadata {
    entries: Vec<(&'static str, String)>,
}

pub fn add_custom_metadata<V: Display>(req: &mut dyn RequestExt, key: &'static str, value: V) {
    if let Some(metadata) = req.mut_extensions().find_mut::<CustomMetadata>() {
        metadata.entries.push((key, value.to_string()));
    } else {
        let mut metadata = CustomMetadata {
            entries: Vec::new(),
        };
        metadata.entries.push((key, value.to_string()));
        req.mut_extensions().insert(metadata);
    }
}

#[derive(Debug, Clone)]
pub struct TimingRecorder {
    sections: Rc<RefCell<HashMap<&'static str, Duration>>>,
}

impl TimingRecorder {
    pub fn new() -> Self {
        Self {
            sections: Rc::new(RefCell::new(HashMap::new())),
        }
    }

    pub fn record<R>(&self, name: &'static str, f: impl FnOnce() -> R) -> R {
        let start = Instant::now();
        let res = f();
        self.sections
            .borrow_mut()
            .insert(name, Instant::now() - start);
        res
    }
}

fn report_to_sentry(req: &dyn RequestExt, res: &AfterResult, response_time: u64) {
    let (message, level) = match res {
        Err(e) => (e.to_string(), Level::Error),
        Ok(_) => return,
    };

    let config = |scope: &mut sentry::Scope| {
        let method = Some(req.method().as_str().to_owned());

        let scheme = match req.scheme() {
            Scheme::Http => "http",
            Scheme::Https => "https",
        };

        let host = match req.host() {
            Host::Name(name) => name.to_owned(),
            Host::Socket(addr) => addr.to_string(),
        };

        let path = &req.extensions().find::<OriginalPath>().unwrap().0;

        let url = format!("{}://{}{}", scheme, host, path).parse().ok();

        {
            let id = req.session().get("user_id").map(|str| str.to_string());

            let user = sentry::User {
                id,
                ..Default::default()
            };

            scope.set_user(Some(user));
        }

        {
            let headers = req
                .headers()
                .iter()
                .filter(|(k, _v)| !FILTERED_HEADERS.iter().any(|name| k == name))
                .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or_default().to_string()))
                .collect();

            let sentry_req = sentry::protocol::Request {
                url,
                method,
                headers,
                ..Default::default()
            };

            scope.add_event_processor(Box::new(move |mut event| {
                if event.request.is_none() {
                    event.request = Some(sentry_req.clone());
                }
                Some(event)
            }));
        }

        if let Some(request_id) = req
            .headers()
            .get("x-request-id")
            .and_then(|value| value.to_str().ok())
        {
            scope.set_tag("request.id", request_id);
        }

        {
            let status = res
                .as_ref()
                .map(|resp| resp.status())
                .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

            scope.set_tag("response.status", status.as_str());
        }

        scope.set_extra("Response time [ms]", response_time.into());

        if let Some(metadata) = req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                scope.set_extra(key, value.to_string().into());
            }
        }
    };

    sentry::with_scope(config, || sentry::capture_message(&message, level));
}

#[cfg(test)]
pub(crate) fn get_log_message(req: &dyn RequestExt, key: &'static str) -> String {
    // Unwrap shouldn't panic as no other code has access to the private struct to remove it
    for (k, v) in &req.extensions().find::<CustomMetadata>().unwrap().entries {
        if key == *k {
            return v.clone();
        }
    }
    panic!("expected log message for {} not found", key);
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
    response_time: u64,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let (at, status) = match self.res {
            Ok(resp) => ("info", resp.status()),
            Err(_) => ("error", StatusCode::INTERNAL_SERVER_ERROR),
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;
        line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;
        line.add_field("service", TimeMs(self.response_time))?;
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        if let Some(metadata) = self.req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                line.add_quoted_field(key, value)?;
            }
        }

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if self.response_time > SLOW_REQUEST_THRESHOLD_MS {
            line.add_marker("SLOW REQUEST")?;

            if let Some(timings) = self.req.extensions().find::<TimingRecorder>() {
                for (section, duration) in timings.sections.borrow().iter() {
                    line.add_quoted_field(
                        format!("timing_{}", section),
                        // Debug formatting rounds the duration to the most useful unit and adds
                        // the unit suffix. For example: 1.20s, 10.00ms, 8.35ns
                        format!("{:.2?}", duration),
                    )?;
                }
            }
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        write!(
            f,
            "{}",
            self.0.extensions().find::<OriginalPath>().unwrap().0
        )?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct TimeMs(u64);

impl Display for TimeMs {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)?;
        f.write_str("ms")?;
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<commit_msg>Tweak response time calculation and comments<commit_after>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;

use conduit::{header, Host, RequestExt, Scheme, StatusCode};
use conduit_cookie::RequestSession;
use sentry::Level;

use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

const FILTERED_HEADERS: &[&str] = &["Authorization", "Cookie", "X-Real-Ip", "X-Forwarded-For"];

#[derive(Default)]
pub(super) struct LogRequests();

struct OriginalPath(String);

impl Middleware for LogRequests {
    fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
        let path = OriginalPath(req.path().to_string());
        req.mut_extensions().insert(path);
        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        let response_time =
            if let Ok(start_ms) = request_header(req, "x-request-start").parse::<u128>() {
                let current_ms = SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .expect("Time went way backwards")
                    .as_millis();

                if current_ms > start_ms {
                    // The result cannot be negative
                    current_ms - start_ms
                } else {
                    // Because our nginx proxy and app run on the same dyno in production, we
                    // shouldn't have to worry about clock drift. But if something goes wrong,
                    // calculate the response time based on when the request reached this app.
                    fallback_response_time(req)
                }
            } else {
                // X-Request-Start header couldn't be parsed.
                // We are probably running locally and not behind nginx.
                fallback_response_time(req)
            };

        // This will only trucate for requests lasting > 500 million years
        let response_time = response_time as u64;

        println!(
            "{}",
            RequestLine {
                req,
                res: &res,
                response_time,
            }
        );

        report_to_sentry(req, &res, response_time);

        res
    }
}

/// Calculate the response time based on when the request reached the in-app web server.
///
/// This serves as a fallback in case the `X-Request-Start` header is missing or invalid.
fn fallback_response_time(req: &mut dyn RequestExt) -> u128 {
    req.elapsed().as_millis()
}

struct CustomMetadata {
    entries: Vec<(&'static str, String)>,
}

pub fn add_custom_metadata<V: Display>(req: &mut dyn RequestExt, key: &'static str, value: V) {
    if let Some(metadata) = req.mut_extensions().find_mut::<CustomMetadata>() {
        metadata.entries.push((key, value.to_string()));
    } else {
        let mut metadata = CustomMetadata {
            entries: Vec::new(),
        };
        metadata.entries.push((key, value.to_string()));
        req.mut_extensions().insert(metadata);
    }
}

#[derive(Debug, Clone)]
pub struct TimingRecorder {
    sections: Rc<RefCell<HashMap<&'static str, Duration>>>,
}

impl TimingRecorder {
    pub fn new() -> Self {
        Self {
            sections: Rc::new(RefCell::new(HashMap::new())),
        }
    }

    pub fn record<R>(&self, name: &'static str, f: impl FnOnce() -> R) -> R {
        let start = Instant::now();
        let res = f();
        self.sections
            .borrow_mut()
            .insert(name, Instant::now() - start);
        res
    }
}

fn report_to_sentry(req: &dyn RequestExt, res: &AfterResult, response_time: u64) {
    let (message, level) = match res {
        Err(e) => (e.to_string(), Level::Error),
        Ok(_) => return,
    };

    let config = |scope: &mut sentry::Scope| {
        let method = Some(req.method().as_str().to_owned());

        let scheme = match req.scheme() {
            Scheme::Http => "http",
            Scheme::Https => "https",
        };

        let host = match req.host() {
            Host::Name(name) => name.to_owned(),
            Host::Socket(addr) => addr.to_string(),
        };

        let path = &req.extensions().find::<OriginalPath>().unwrap().0;

        let url = format!("{}://{}{}", scheme, host, path).parse().ok();

        {
            let id = req.session().get("user_id").map(|str| str.to_string());

            let user = sentry::User {
                id,
                ..Default::default()
            };

            scope.set_user(Some(user));
        }

        {
            let headers = req
                .headers()
                .iter()
                .filter(|(k, _v)| !FILTERED_HEADERS.iter().any(|name| k == name))
                .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or_default().to_string()))
                .collect();

            let sentry_req = sentry::protocol::Request {
                url,
                method,
                headers,
                ..Default::default()
            };

            scope.add_event_processor(Box::new(move |mut event| {
                if event.request.is_none() {
                    event.request = Some(sentry_req.clone());
                }
                Some(event)
            }));
        }

        if let Some(request_id) = req
            .headers()
            .get("x-request-id")
            .and_then(|value| value.to_str().ok())
        {
            scope.set_tag("request.id", request_id);
        }

        {
            let status = res
                .as_ref()
                .map(|resp| resp.status())
                .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

            scope.set_tag("response.status", status.as_str());
        }

        scope.set_extra("Response time [ms]", response_time.into());

        if let Some(metadata) = req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                scope.set_extra(key, value.to_string().into());
            }
        }
    };

    sentry::with_scope(config, || sentry::capture_message(&message, level));
}

#[cfg(test)]
pub(crate) fn get_log_message(req: &dyn RequestExt, key: &'static str) -> String {
    // Unwrap shouldn't panic as no other code has access to the private struct to remove it
    for (k, v) in &req.extensions().find::<CustomMetadata>().unwrap().entries {
        if key == *k {
            return v.clone();
        }
    }
    panic!("expected log message for {} not found", key);
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
    response_time: u64,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let (at, status) = match self.res {
            Ok(resp) => ("info", resp.status()),
            Err(_) => ("error", StatusCode::INTERNAL_SERVER_ERROR),
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;
        line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;
        line.add_field("service", TimeMs(self.response_time))?;
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        if let Some(metadata) = self.req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                line.add_quoted_field(key, value)?;
            }
        }

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if self.response_time > SLOW_REQUEST_THRESHOLD_MS {
            line.add_marker("SLOW REQUEST")?;

            if let Some(timings) = self.req.extensions().find::<TimingRecorder>() {
                for (section, duration) in timings.sections.borrow().iter() {
                    line.add_quoted_field(
                        format!("timing_{}", section),
                        // Debug formatting rounds the duration to the most useful unit and adds
                        // the unit suffix. For example: 1.20s, 10.00ms, 8.35ns
                        format!("{:.2?}", duration),
                    )?;
                }
            }
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        write!(
            f,
            "{}",
            self.0.extensions().find::<OriginalPath>().unwrap().0
        )?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct TimeMs(u64);

impl Display for TimeMs {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)?;
        f.write_str("ms")?;
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::{mem, slice};
use allocator::*;

use super::entry_location::*;

#[derive(Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum EntryType {
    Alias = 0xA,
    Entry,
    Deleted,
}

#[repr(C)]
pub struct ByteStringEntryAlias {
    entry_type: EntryType,
    num_segments: usize,
    // sizeof(EntryLocation) * num_segments
}

#[repr(C)]
pub struct ByteStringEntry {
    entry_type: EntryType,
    data_size: usize,
    // data_size bytes of data
}

/// Decrement the ref count for the given byte string
/// Follow aliases to release all their byte strings
pub fn release_byte_string(entry: &EntryLocation, pool: &Pool) {
    match get_entry_type(entry, pool) {
        EntryType::Entry => {
            pool.release(entry.page_index);
        },
        EntryType::Deleted => {},
        EntryType::Alias => {
            for e in get_aliased_entries(entry, pool) {
                release_byte_string(e, pool);
            }
            // Once we've followed and release all the aliased
            // strings, release this alias.
            pool.release(entry.page_index);
        }
    }
}

/// Get the type of the entry pointed to by the location
fn get_entry_type(entry: &EntryLocation, pool: &Pool) -> EntryType {
    pool[entry.page_index]
        .transmute_segment::<EntryType>(entry.offset)
        .clone()
}

/// Returns a slice of the entries which are aliased by the given entry
pub fn get_aliased_entries<'a>(entry: &EntryLocation, pool: &'a Pool) -> &'a[EntryLocation] {
    let header: &ByteStringEntryAlias = pool[entry.page_index]
        .transmute_segment(entry.offset);
    assert_eq!(EntryType::Alias, header.entry_type);

    let start = entry.offset + mem::size_of::<ByteStringEntryAlias>();
    let start_ptr: *const u8 = &pool[entry.page_index][start];

    unsafe {
        let start_ptr: *const EntryLocation = mem::transmute(start_ptr);
        slice::from_raw_parts(start_ptr, header.num_segments)
    }
}

/// Treates the entry location as a ByteStringEntry
/// Panics if not given the correct entry
pub fn get_slice<'a>(entry: &EntryLocation, pool: &'a Pool) -> &'a[u8] {
    let header: &ByteStringEntry = pool[entry.page_index]
        .transmute_segment(entry.offset);
    assert_eq!(EntryType::Entry, header.entry_type);

    let start = entry.offset + mem::size_of::<ByteStringEntry>();
    &pool[entry.page_index][start..start+header.data_size]
}

/// Treates the entry location as a ByteStringEntry
/// Panics if not given the correct entry
pub fn get_slice_mut<'a>(entry: &EntryLocation, pool: &'a Pool) -> &'a mut [u8] {
    let header: &ByteStringEntry = pool[entry.page_index]
        .transmute_segment(entry.offset);
    assert_eq!(EntryType::Entry, header.entry_type);

    let start = entry.offset + mem::size_of::<ByteStringEntry>();

    let page: &mut Page = pool[entry.page_index].borrow_mut();
    &mut page[start..start+header.data_size]
}
<commit_msg>WIP zero-copy iteration support<commit_after>use std::{mem, slice};
use allocator::*;

use super::entry_location::*;

#[derive(Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum EntryType {
    Alias = 0xA,
    Entry,
    Deleted,
}

#[repr(C)]
pub struct ByteStringEntryAlias {
    entry_type: EntryType,
    num_segments: usize,
    // sizeof(EntryLocation) * num_segments
}

#[repr(C)]
pub struct ByteStringEntry {
    entry_type: EntryType,
    data_size: usize,
    // data_size bytes of data
}

/// Decrement the ref count for the given byte string
/// Follow aliases to release all their byte strings
pub fn release_byte_string(entry: &EntryLocation, pool: &Pool) {
    match get_entry_type(entry, pool) {
        EntryType::Entry => {
            pool.release(entry.page_index);
        },
        EntryType::Deleted => {},
        EntryType::Alias => {
            for e in get_aliased_entries(entry, pool) {
                release_byte_string(e, pool);
            }
            // Once we've followed and release all the aliased
            // strings, release this alias.
            pool.release(entry.page_index);
        }
    }
}

/// Get the type of the entry pointed to by the location
fn get_entry_type(entry: &EntryLocation, pool: &Pool) -> EntryType {
    pool[entry.page_index]
        .transmute_segment::<EntryType>(entry.offset)
        .clone()
}

/// Returns a slice of the entries which are aliased by the given entry
pub fn get_aliased_entries<'a>(entry: &EntryLocation, pool: &'a Pool) -> &'a[EntryLocation] {
    let header: &ByteStringEntryAlias = pool[entry.page_index]
        .transmute_segment(entry.offset);
    assert_eq!(EntryType::Alias, header.entry_type);

    let start = entry.offset + mem::size_of::<ByteStringEntryAlias>();
    let start_ptr: *const u8 = &pool[entry.page_index][start];

    unsafe {
        let start_ptr: *const EntryLocation = mem::transmute(start_ptr);
        slice::from_raw_parts(start_ptr, header.num_segments)
    }
}

/// Treates the entry location as a ByteStringEntry
/// Panics if not given the correct entry
pub fn get_slice<'a>(entry: &EntryLocation, pool: &'a Pool) -> &'a[u8] {
    let header: &ByteStringEntry = pool[entry.page_index]
        .transmute_segment(entry.offset);
    assert_eq!(EntryType::Entry, header.entry_type);

    let start = entry.offset + mem::size_of::<ByteStringEntry>();
    &pool[entry.page_index][start..start+header.data_size]
}

/// Treates the entry location as a ByteStringEntry
/// Panics if not given the correct entry
pub fn get_slice_mut<'a>(entry: &EntryLocation, pool: &'a Pool) -> &'a mut [u8] {
    let header: &ByteStringEntry = pool[entry.page_index]
        .transmute_segment(entry.offset);
    assert_eq!(EntryType::Entry, header.entry_type);

    let start = entry.offset + mem::size_of::<ByteStringEntry>();

    let page: &mut Page = pool[entry.page_index].borrow_mut();
    &mut page[start..start+header.data_size]
}

/// ITERATION
/// Provides byte string iters

pub struct ByteStringIter<'a> {
    entry: &'a EntryLocation,
    pool: &'a Pool,

    is_aliased: bool,
    current_page: &'a Page,
    curent_entry: &'a EntryLocation,
    current_string: &'a ByteStringEntry,
    alias_index: usize,
    byte_index: usize,
}

impl <'a> Iterator for ByteStringIter<'a> {
    type Item = &'a u8;

    fn next(&mut self) -> Option<&'a u8> {
        let current_byte = &self.current_page
            [self.current_entry.offset+self.byte_index];

        // Increment our count, and roll over if necessary
        self.byte_index += 1;
        if self.byte_index >= self.current_entry.data_size {
            if self.is_aliased {
                self.alias_index += 1;
                let entries = get_aliased_entries(self.entry, self.pool);
                if self.alias_index >= entries.len() {
                    return None
                }
                self.current_entry = &entries[self.alias_index];
                self.current_string = self.pool[self.current_entry.page_index]
                    .transmute_segment(self.current_entry.offset);
                self.byte_index = 0;
                self.current_page = self.pool[self.current_entry.page_index];
            } else {
                return None
            }
        }
        Some(current_byte)
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;

use node::Value;
use parser::{Error, Reader, Result};
use super::{Command, Number, Parameters, Position};

/// A [data][1] attribute.
///
/// [1]: https://www.w3.org/TR/SVG/paths.html#PathData
#[derive(Clone, Default)]
pub struct Data(Vec<Command>);

struct Parser<'l> {
    reader: Reader<'l>,
}

impl Data {
    /// Create a data attribute.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Parse a data attribute.
    #[inline]
    pub fn parse(content: &str) -> Result<Self> {
        Parser::new(content).process()
    }
}

macro_rules! implement {
    (@one #[$doc:meta] fn $method:ident($command:ident, $position:ident)) => (
        #[$doc]
        pub fn $method<T>(mut self, parameters: T) -> Self where T: Into<Parameters> {
            self.0.push(Command::$command(Position::$position, parameters.into()));
            self
        }
    );
    (@one #[$doc:meta] fn $method:ident($command:ident)) => (
        #[$doc]
        pub fn $method(mut self) -> Self {
            self.0.push(Command::$command);
            self
        }
    );
    ($(#[$doc:meta] fn $method:ident($($argument:tt)*))*) => (
        impl Data {
            $(implement! { @one #[$doc] fn $method($($argument)*) })*
        }
    );
}

implement! {
    #[doc = "Add an absolute `Command::Move` command."]
    fn move_to(Move, Absolute)

    #[doc = "Add a relative `Command::Move` command."]
    fn move_by(Move, Relative)

    #[doc = "Add an absolute `Command::Line` command."]
    fn line_to(Line, Absolute)

    #[doc = "Add a relative `Command::Line` command."]
    fn line_by(Line, Relative)

    #[doc = "Add an absolute `Command::HorizontalLine` command."]
    fn horizontal_line_to(HorizontalLine, Absolute)

    #[doc = "Add a relative `Command::HorizontalLine` command."]
    fn horizontal_line_by(HorizontalLine, Relative)

    #[doc = "Add an absolute `Command::VerticalLine` command."]
    fn vertical_line_to(VerticalLine, Absolute)

    #[doc = "Add a relative `Command::VerticalLine` command."]
    fn vertical_line_by(VerticalLine, Relative)

    #[doc = "Add an absolute `Command::QuadraticCurve` command."]
    fn quadratic_curve_to(QuadraticCurve, Absolute)

    #[doc = "Add a relative `Command::QuadraticCurve` command."]
    fn quadratic_curve_by(QuadraticCurve, Relative)

    #[doc = "Add an absolute `Command::SmoothQuadraticCurve` command."]
    fn smooth_quadratic_curve_to(SmoothQuadraticCurve, Absolute)

    #[doc = "Add a relative `Command::SmoothQuadraticCurve` command."]
    fn smooth_quadratic_curve_by(SmoothQuadraticCurve, Relative)

    #[doc = "Add an absolute `Command::CubicCurve` command."]
    fn cubic_curve_to(CubicCurve, Absolute)

    #[doc = "Add a relative `Command::CubicCurve` command."]
    fn cubic_curve_by(CubicCurve, Relative)

    #[doc = "Add an absolute `Command::SmoothCubicCurve` command."]
    fn smooth_cubic_curve_to(SmoothCubicCurve, Absolute)

    #[doc = "Add a relative `Command::SmoothCubicCurve` command."]
    fn smooth_cubic_curve_by(SmoothCubicCurve, Relative)

    #[doc = "Add an absolute `Command::EllipticalArc` command."]
    fn elliptical_arc_to(EllipticalArc, Absolute)

    #[doc = "Add a relative `Command::EllipticalArc` command."]
    fn elliptical_arc_by(EllipticalArc, Relative)

    #[doc = "Add a `Command::Close` command."]
    fn close(Close)
}

impl Deref for Data {
    type Target = [Command];

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<Vec<Command>> for Data {
    #[inline]
    fn from(commands: Vec<Command>) -> Self {
        Data(commands)
    }
}

impl From<Data> for Vec<Command> {
    #[inline]
    fn from(Data(commands): Data) -> Self {
        commands
    }
}

impl From<Data> for Value {
    #[inline]
    fn from(Data(mut inner): Data) -> Self {
        inner.drain(..).map(|value| String::from(value)).collect::<Vec<_>>().join(" ").into()
    }
}

macro_rules! raise(
    ($parser:expr, $($argument:tt)*) => (
        return Err(Error::new($parser.reader.position(), format!($($argument)*)));
    );
);

impl<'l> Parser<'l> {
    #[inline]
    fn new(content: &'l str) -> Self {
        Parser { reader: Reader::new(content) }
    }

    fn process(&mut self) -> Result<Data> {
        let mut commands = Vec::new();
        loop {
            self.reader.consume_whitespace();
            match try!(self.read_command()) {
                Some(command) => commands.push(command),
                _ => break,
            }
        }
        Ok(Data(commands))
    }

    fn read_command(&mut self) -> Result<Option<Command>> {
        use super::Command::*;
        use super::Position::*;

        let name = match self.reader.next() {
            Some(name) => match name {
                'A'...'Z' | 'a'...'z' => name,
                _ => raise!(self, "expected a path command"),
            },
            _ => return Ok(None),
        };
        self.reader.consume_whitespace();
        let parameters = try!(self.read_parameters()).into();
        Ok(Some(match name {
            'M' => Move(Absolute, parameters),
            'm' => Move(Relative, parameters),

            'L' => Line(Absolute, parameters),
            'l' => Line(Relative, parameters),

            'H' => HorizontalLine(Absolute, parameters),
            'h' => HorizontalLine(Relative, parameters),

            'V' => VerticalLine(Absolute, parameters),
            'v' => VerticalLine(Relative, parameters),

            'Q' => QuadraticCurve(Absolute, parameters),
            'q' => QuadraticCurve(Relative, parameters),

            'T' => SmoothQuadraticCurve(Absolute, parameters),
            't' => SmoothQuadraticCurve(Relative, parameters),

            'C' => CubicCurve(Absolute, parameters),
            'c' => CubicCurve(Relative, parameters),

            'S' => SmoothCubicCurve(Absolute, parameters),
            's' => SmoothCubicCurve(Relative, parameters),

            'A' => EllipticalArc(Absolute, parameters),
            'a' => EllipticalArc(Relative, parameters),

            'Z' | 'z' => Close,

            _ => raise!(self, "found an unknown path command '{}'", name),
        }))
    }

    fn read_parameters(&mut self) -> Result<Vec<Number>> {
        let mut parameters = Vec::new();
        loop {
            match try!(self.read_number()) {
                Some(number) => parameters.push(number),
                _ => break,
            }
            self.reader.consume_whitespace();
            self.reader.consume_char(',');
        }
        Ok(parameters)
    }

    pub fn read_number(&mut self) -> Result<Option<Number>> {
        self.reader.consume_whitespace();
        let number = self.reader.capture(|reader| reader.consume_number())
                                .and_then(|number| Some(String::from(number)));
        match number {
            Some(number) => match (&number).parse() {
                Ok(number) => Ok(Some(number)),
                _ => raise!(self, "failed to parse a number '{}'", number),
            },
            _ => Ok(None),
        }
    }
}

#[cfg(test)]
mod tests {
    use node::Value;
    use super::{Data, Parser};
    use super::super::Command::*;
    use super::super::Position::*;

    #[test]
    fn data_into_value() {
        let data = Data::new().line_to((1, 2)).cubic_curve_by((1, 2.5, 3, 4, 5, 6)).close();
        assert_eq!(Value::from(data).to_string(), "L1,2 c1,2.5,3,4,5,6 z");
    }

    #[test]
    fn data_parse() {
        let data = Data::parse("M1,2 l3,4").unwrap();
        assert_eq!(data.len(), 2);
        match data[0] {
            Move(Absolute, ref parameters) => assert_eq!(&parameters[..], &[1.0, 2.0]),
            _ => unreachable!(),
        }
        match data[1] {
            Line(Relative, ref parameters) => assert_eq!(&parameters[..], &[3.0, 4.0]),
            _ => unreachable!(),
        }
    }

    #[test]
    fn parser_read_command() {
        macro_rules! run(
            ($content:expr) => ({
                let mut parser = Parser::new($content);
                parser.read_command().unwrap().unwrap()
            });
        );

        macro_rules! test(
            ($content:expr, $command:ident, $position:ident, $parameters:expr) => (
                match run!($content) {
                    $command($position, parameters) => assert_eq!(&parameters[..], $parameters),
                    _ => unreachable!(),
                }
            );
            ($content:expr, $command:ident) => (
                match run!($content) {
                    $command => {},
                    _ => unreachable!(),
                }
            );
        );

        test!("M4,2", Move, Absolute, &[4.0, 2.0]);
        test!("m4,\n2", Move, Relative, &[4.0, 2.0]);

        test!("L7, 8  9", Line, Absolute, &[7.0, 8.0, 9.0]);
        test!("l 7,8 \n9", Line, Relative, &[7.0, 8.0, 9.0]);

        test!("H\t6,9", HorizontalLine, Absolute, &[6.0, 9.0]);
        test!("h6,  \t9", HorizontalLine, Relative, &[6.0, 9.0]);

        test!("V2.1,-3", VerticalLine, Absolute, &[2.1, -3.0]);
        test!("v\n2.1 -3", VerticalLine, Relative, &[2.1, -3.0]);

        test!("Q90.5 0", QuadraticCurve, Absolute, &[90.5, 0.0]);
        test!("q90.5\n, 0", QuadraticCurve, Relative, &[90.5, 0.0]);

        test!("T-1", SmoothQuadraticCurve, Absolute, &[-1.0]);
        test!("t -1", SmoothQuadraticCurve, Relative, &[-1.0]);

        test!("C0,1 0,2", CubicCurve, Absolute, &[0.0, 1.0, 0.0, 2.0]);
        test!("c0 ,1 0,  2", CubicCurve, Relative, &[0.0, 1.0, 0.0, 2.0]);

        test!("S42,0", SmoothCubicCurve, Absolute, &[42.0, 0.0]);
        test!("s \t 42,0", SmoothCubicCurve, Relative, &[42.0, 0.0]);

        test!("A2.6,0 -7", EllipticalArc, Absolute, &[2.6, 0.0, -7.0]);
        test!("a 2.6 ,0 -7", EllipticalArc, Relative, &[2.6, 0.0, -7.0]);

        test!("Z", Close);
        test!("z", Close);
    }

    #[test]
    fn parser_read_parameters() {
        let mut parser = Parser::new("1,2 3,4 5 6.7");
        let parameters = parser.read_parameters().unwrap();
        assert_eq!(&parameters[..], &[1.0, 2.0, 3.0, 4.0, 5.0, 6.7]);
    }

    #[test]
    fn parser_read_number() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut parser = Parser::new($content);
                assert_eq!(parser.read_number().unwrap().unwrap(), $value);
            });
        );

        test!("0.30000000000000004", 0.3);
        test!("1e-4", 1e-4);
        test!("-1E2", -1e2);
        test!("-0.00100E-002", -1e-5);
    }
}
<commit_msg>Refactor a test<commit_after>use std::ops::Deref;

use node::Value;
use parser::{Error, Reader, Result};
use super::{Command, Number, Parameters, Position};

/// A [data][1] attribute.
///
/// [1]: https://www.w3.org/TR/SVG/paths.html#PathData
#[derive(Clone, Default)]
pub struct Data(Vec<Command>);

struct Parser<'l> {
    reader: Reader<'l>,
}

impl Data {
    /// Create a data attribute.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Parse a data attribute.
    #[inline]
    pub fn parse(content: &str) -> Result<Self> {
        Parser::new(content).process()
    }
}

macro_rules! implement {
    (@one #[$doc:meta] fn $method:ident($command:ident, $position:ident)) => (
        #[$doc]
        pub fn $method<T>(mut self, parameters: T) -> Self where T: Into<Parameters> {
            self.0.push(Command::$command(Position::$position, parameters.into()));
            self
        }
    );
    (@one #[$doc:meta] fn $method:ident($command:ident)) => (
        #[$doc]
        pub fn $method(mut self) -> Self {
            self.0.push(Command::$command);
            self
        }
    );
    ($(#[$doc:meta] fn $method:ident($($argument:tt)*))*) => (
        impl Data {
            $(implement! { @one #[$doc] fn $method($($argument)*) })*
        }
    );
}

implement! {
    #[doc = "Add an absolute `Command::Move` command."]
    fn move_to(Move, Absolute)

    #[doc = "Add a relative `Command::Move` command."]
    fn move_by(Move, Relative)

    #[doc = "Add an absolute `Command::Line` command."]
    fn line_to(Line, Absolute)

    #[doc = "Add a relative `Command::Line` command."]
    fn line_by(Line, Relative)

    #[doc = "Add an absolute `Command::HorizontalLine` command."]
    fn horizontal_line_to(HorizontalLine, Absolute)

    #[doc = "Add a relative `Command::HorizontalLine` command."]
    fn horizontal_line_by(HorizontalLine, Relative)

    #[doc = "Add an absolute `Command::VerticalLine` command."]
    fn vertical_line_to(VerticalLine, Absolute)

    #[doc = "Add a relative `Command::VerticalLine` command."]
    fn vertical_line_by(VerticalLine, Relative)

    #[doc = "Add an absolute `Command::QuadraticCurve` command."]
    fn quadratic_curve_to(QuadraticCurve, Absolute)

    #[doc = "Add a relative `Command::QuadraticCurve` command."]
    fn quadratic_curve_by(QuadraticCurve, Relative)

    #[doc = "Add an absolute `Command::SmoothQuadraticCurve` command."]
    fn smooth_quadratic_curve_to(SmoothQuadraticCurve, Absolute)

    #[doc = "Add a relative `Command::SmoothQuadraticCurve` command."]
    fn smooth_quadratic_curve_by(SmoothQuadraticCurve, Relative)

    #[doc = "Add an absolute `Command::CubicCurve` command."]
    fn cubic_curve_to(CubicCurve, Absolute)

    #[doc = "Add a relative `Command::CubicCurve` command."]
    fn cubic_curve_by(CubicCurve, Relative)

    #[doc = "Add an absolute `Command::SmoothCubicCurve` command."]
    fn smooth_cubic_curve_to(SmoothCubicCurve, Absolute)

    #[doc = "Add a relative `Command::SmoothCubicCurve` command."]
    fn smooth_cubic_curve_by(SmoothCubicCurve, Relative)

    #[doc = "Add an absolute `Command::EllipticalArc` command."]
    fn elliptical_arc_to(EllipticalArc, Absolute)

    #[doc = "Add a relative `Command::EllipticalArc` command."]
    fn elliptical_arc_by(EllipticalArc, Relative)

    #[doc = "Add a `Command::Close` command."]
    fn close(Close)
}

impl Deref for Data {
    type Target = [Command];

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<Vec<Command>> for Data {
    #[inline]
    fn from(commands: Vec<Command>) -> Self {
        Data(commands)
    }
}

impl From<Data> for Vec<Command> {
    #[inline]
    fn from(Data(commands): Data) -> Self {
        commands
    }
}

impl From<Data> for Value {
    #[inline]
    fn from(Data(mut inner): Data) -> Self {
        inner.drain(..).map(|value| String::from(value)).collect::<Vec<_>>().join(" ").into()
    }
}

macro_rules! raise(
    ($parser:expr, $($argument:tt)*) => (
        return Err(Error::new($parser.reader.position(), format!($($argument)*)));
    );
);

impl<'l> Parser<'l> {
    #[inline]
    fn new(content: &'l str) -> Self {
        Parser { reader: Reader::new(content) }
    }

    fn process(&mut self) -> Result<Data> {
        let mut commands = Vec::new();
        loop {
            self.reader.consume_whitespace();
            match try!(self.read_command()) {
                Some(command) => commands.push(command),
                _ => break,
            }
        }
        Ok(Data(commands))
    }

    fn read_command(&mut self) -> Result<Option<Command>> {
        use super::Command::*;
        use super::Position::*;

        let name = match self.reader.next() {
            Some(name) => match name {
                'A'...'Z' | 'a'...'z' => name,
                _ => raise!(self, "expected a path command"),
            },
            _ => return Ok(None),
        };
        self.reader.consume_whitespace();
        let parameters = try!(self.read_parameters()).into();
        Ok(Some(match name {
            'M' => Move(Absolute, parameters),
            'm' => Move(Relative, parameters),

            'L' => Line(Absolute, parameters),
            'l' => Line(Relative, parameters),

            'H' => HorizontalLine(Absolute, parameters),
            'h' => HorizontalLine(Relative, parameters),

            'V' => VerticalLine(Absolute, parameters),
            'v' => VerticalLine(Relative, parameters),

            'Q' => QuadraticCurve(Absolute, parameters),
            'q' => QuadraticCurve(Relative, parameters),

            'T' => SmoothQuadraticCurve(Absolute, parameters),
            't' => SmoothQuadraticCurve(Relative, parameters),

            'C' => CubicCurve(Absolute, parameters),
            'c' => CubicCurve(Relative, parameters),

            'S' => SmoothCubicCurve(Absolute, parameters),
            's' => SmoothCubicCurve(Relative, parameters),

            'A' => EllipticalArc(Absolute, parameters),
            'a' => EllipticalArc(Relative, parameters),

            'Z' | 'z' => Close,

            _ => raise!(self, "found an unknown path command '{}'", name),
        }))
    }

    fn read_parameters(&mut self) -> Result<Vec<Number>> {
        let mut parameters = Vec::new();
        loop {
            match try!(self.read_number()) {
                Some(number) => parameters.push(number),
                _ => break,
            }
            self.reader.consume_whitespace();
            self.reader.consume_char(',');
        }
        Ok(parameters)
    }

    pub fn read_number(&mut self) -> Result<Option<Number>> {
        self.reader.consume_whitespace();
        let number = self.reader.capture(|reader| reader.consume_number())
                                .and_then(|number| Some(String::from(number)));
        match number {
            Some(number) => match (&number).parse() {
                Ok(number) => Ok(Some(number)),
                _ => raise!(self, "failed to parse a number '{}'", number),
            },
            _ => Ok(None),
        }
    }
}

#[cfg(test)]
mod tests {
    use node::Value;
    use super::{Data, Parser};
    use super::super::Command::*;
    use super::super::Position::*;

    #[test]
    fn data_into_value() {
        let data = Data::new().line_to((1, 2)).cubic_curve_by((1, 2.5, 3, 4, 5, 6)).close();
        assert_eq!(Value::from(data).to_string(), "L1,2 c1,2.5,3,4,5,6 z");
    }

    #[test]
    fn data_parse() {
        let data = Data::parse("M1,2 l3,4").unwrap();
        assert_eq!(data.len(), 2);
        match data[0] {
            Move(Absolute, ref parameters) => assert_eq!(&parameters[..], &[1.0, 2.0]),
            _ => unreachable!(),
        }
        match data[1] {
            Line(Relative, ref parameters) => assert_eq!(&parameters[..], &[3.0, 4.0]),
            _ => unreachable!(),
        }
    }

    #[test]
    fn parser_read_command() {
        macro_rules! run(
            ($content:expr) => ({
                let mut parser = Parser::new($content);
                parser.read_command().unwrap().unwrap()
            });
        );

        macro_rules! test(
            ($content:expr, $command:ident, $position:ident, $parameters:expr) => (
                match run!($content) {
                    $command($position, parameters) => assert_eq!(&parameters[..], $parameters),
                    _ => unreachable!(),
                }
            );
            ($content:expr, $command:ident) => (
                match run!($content) {
                    $command => {},
                    _ => unreachable!(),
                }
            );
        );

        test!("M4,2", Move, Absolute, &[4.0, 2.0]);
        test!("m4,\n2", Move, Relative, &[4.0, 2.0]);

        test!("L7, 8  9", Line, Absolute, &[7.0, 8.0, 9.0]);
        test!("l 7,8 \n9", Line, Relative, &[7.0, 8.0, 9.0]);

        test!("H\t6,9", HorizontalLine, Absolute, &[6.0, 9.0]);
        test!("h6,  \t9", HorizontalLine, Relative, &[6.0, 9.0]);

        test!("V2.1,-3", VerticalLine, Absolute, &[2.1, -3.0]);
        test!("v\n2.1 -3", VerticalLine, Relative, &[2.1, -3.0]);

        test!("Q90.5 0", QuadraticCurve, Absolute, &[90.5, 0.0]);
        test!("q90.5\n, 0", QuadraticCurve, Relative, &[90.5, 0.0]);

        test!("T-1", SmoothQuadraticCurve, Absolute, &[-1.0]);
        test!("t -1", SmoothQuadraticCurve, Relative, &[-1.0]);

        test!("C0,1 0,2", CubicCurve, Absolute, &[0.0, 1.0, 0.0, 2.0]);
        test!("c0 ,1 0,  2", CubicCurve, Relative, &[0.0, 1.0, 0.0, 2.0]);

        test!("S42,0", SmoothCubicCurve, Absolute, &[42.0, 0.0]);
        test!("s \t 42,0", SmoothCubicCurve, Relative, &[42.0, 0.0]);

        test!("A2.6,0 -7", EllipticalArc, Absolute, &[2.6, 0.0, -7.0]);
        test!("a 2.6 ,0 -7", EllipticalArc, Relative, &[2.6, 0.0, -7.0]);

        test!("Z", Close);
        test!("z", Close);
    }

    #[test]
    fn parser_read_parameters() {
        macro_rules! test(
            ($content:expr, $parameters:expr) => ({
                let mut parser = Parser::new($content);
                let parameters = parser.read_parameters().unwrap();
                assert_eq!(&parameters[..], $parameters);
            });
        );

        test!("1,2 3,4 5 6.7", &[1.0, 2.0, 3.0, 4.0, 5.0, 6.7]);
    }

    #[test]
    fn parser_read_number() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut parser = Parser::new($content);
                assert_eq!(parser.read_number().unwrap().unwrap(), $value);
            });
        );

        test!("0.30000000000000004", 0.3);
        test!("1e-4", 1e-4);
        test!("-1E2", -1e2);
        test!("-0.00100E-002", -1e-5);
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate drag_controller;
extern crate sdl2_window;

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

use graphics::ImageSize;
use drag_controller::{
    DragController,
    Drag
};
use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window as Window;
use piston::window::{ WindowSettings, Size };
use piston::event::*;

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,
        WindowSettings::new(
            "piston-example-deform".to_string(),
            Size { width: 300, height: 300 }
        )
        .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 = Rc::new(RefCell::new(window));
    for e in window.events() {
        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::new_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>Removed `Rc/RefCell`<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 graphics::ImageSize;
use drag_controller::{
    DragController,
    Drag
};
use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window as Window;
use piston::window::{ WindowSettings, Size };
use piston::event::*;

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,
        WindowSettings::new(
            "piston-example-deform".to_string(),
            Size { width: 300, height: 300 }
        )
        .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);
    for e in window.events() {
        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::new_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>use std::io;

#[deriving(Eq)]
enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| c == ' ' || c == ')');
	let pos = match end {
		Some(end) => end+1,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if input[i] as char == ')' => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| c != ' ' && c != ')').to_owned_vec());
	let len = atom.len();
	printfln!("atom: %s | %u", atom, len);
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len() || input.is_whitespace() || input.slice(start, input.len()).is_whitespace()) {
		return None
	}

	match input[start] as char {
		' ' => read_value(input, start+1),
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		c => read_atom(input, start)
	}
}

fn parse(input: &str) -> Option<Value> {
	/*do io::with_str_reader(input) |r| {
		//let c =
		println("blah: " + input + " -> " + read_token(r));
		List(~[])
	}*/
	match read_value(input, 0) {
		Some((v,_)) => {
			println(fmt!("v: %?", *v));
			Some(*v)
		}
		None => None
	}
}

#[test]
fn test_sexp() {
	assert_eq!(parse(""), None);
	assert_eq!(parse("123"), Some(Num(123.0)));
	assert_eq!(parse("()"), Some(List(~[])));
	assert_eq!(parse("3.14159265358"), Some(Num(3.14159265358)));
	assert_eq!(parse("(hi)"), Some(List(~[Atom(~"hi")])));
	assert_eq!(parse("(1)"), Some(List(~[Num(1.0)])));
	assert_eq!(parse("(hi there)"), Some(List(~[Atom(~"hi"), Atom(~"there")])));
	assert_eq!(parse("(hi (there))"), Some(List(~[Atom(~"hi"), List(~[Atom(~"there")])])));
}<commit_msg>fix read_number and add tests<commit_after>use std::io;

#[deriving(Eq)]
enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| c == ' ' || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None if input[i] as char == ')' => return Some((~List(list), i)),
			None => return None
		}
	}
}

fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| c != ' ' && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len() || input.is_whitespace() || input.slice(start, input.len()).is_whitespace()) {
		return None
	}

	match input[start] as char {
		' ' => read_value(input, start+1),
		'(' => read_list(input, start+1),
		')' => None,
		c if c.is_digit() || c == '.' => read_number(input, start),
		c => read_atom(input, start)
	}
}

fn parse(input: &str) -> Option<Value> {
	/*do io::with_str_reader(input) |r| {
		//let c =
		println("blah: " + input + " -> " + read_token(r));
		List(~[])
	}*/
	match read_value(input, 0) {
		Some((v,_)) => {
			println(fmt!("v: %?", *v));
			Some(*v)
		}
		None => None
	}
}

#[test]
fn test_sexp() {
	assert_eq!(parse(""), None);
	assert_eq!(parse("123"), Some(Num(123.0)));
	assert_eq!(parse("()"), Some(List(~[])));
	assert_eq!(parse("3.14159265358"), Some(Num(3.14159265358)));
	assert_eq!(parse("(hi)"), Some(List(~[Atom(~"hi")])));
	assert_eq!(parse("(1)"), Some(List(~[Num(1.0)])));
	assert_eq!(parse("(hi there)"), Some(List(~[Atom(~"hi"), Atom(~"there")])));
	assert_eq!(parse("(hi (there))"), Some(List(~[Atom(~"hi"), List(~[Atom(~"there")])])));
	assert_eq!(parse("(hi 123456)"), Some(List(~[Atom(~"hi"), Num(123456.0)])));
	assert_eq!(parse("(())"), Some(List(~[List(~[])])));
	assert_eq!(parse("(hi (there (fellow (human-bot!))))"), Some(
		List(~[Atom(~"hi"),
			List(~[Atom(~"there"),
				List(~[Atom(~"fellow"),
					List(~[Atom(~"human-bot!")])])])])
	));
}<|endoftext|>


<commit_before>//
//  0 1 0  Mnemosyne: a functional systems programming language.
//  0 0 1  (c) 2015 Hawk Weisman
//  1 1 1  hi@hawkweisman.me
//
//  Mnemosyne is released under the MIT License. Please refer to
//  the LICENSE file at the top-level directory of this distribution
//  or at https://github.com/hawkw/mnemosyne/.
//
use rustc::lib::llvm;
use rustc::lib::llvm::*;

use std::ffi::CString;

use libc::{c_char, c_uint};

use ::errors::{ExpectICE, UnwrapICE};

// pub struct Context(llvm::ContextRef);
//
// pub struct Builder(llvm::BuilderRef);

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

trait LLVMWrapper {
    type Ref;
    fn to_ref(&self) -> Self::Ref;
    fn from_ref(r: Self::Ref) -> Self;
}

macro_rules! llvm_wrapper {
    ( $($name:ident wrapping $wrapped:path),*) => {$(
        pub struct $name ($wrapped);

        impl LLVMWrapper for $name {
            type Ref = $wrapped;

            fn to_ref(&self) -> Self::Ref {
                not_null!(self.0)
            }

            fn from_ref(r: $wrapped) -> Self {
                $name( not_null!(r) )
            }
        }
    )*};
    ( $($name:ident wrapping $wrapped:path, dropped by $drop:path),*) => {$(
        llvm_wrapper!{ $name wrapping $wrapped }

        impl Drop for $name {
            fn drop(&mut self) {
                unsafe { $drop(self.0) }
            }
        }
    )*}
}

llvm_wrapper! {
    Context wrapping llvm::ContextRef, dropped by llvm::LLVMContextDispose,
    Builder wrapping llvm::BuilderRef, dropped by llvm::LLVMDisposeBuilder
}

llvm_wrapper! {
    BasicBlock wrapping llvm::BasicBlockRef,
    Value wrapping llvm::ValueRef
}

impl Context {
    /// Construct a new Builder within this `Context`.
    pub fn create_builder(&self) -> Builder {
        unsafe {
            Builder::from_ref(LLVMCreateBuilderInContext(self.to_ref()))
        }
    }
}

impl Builder {
    //---- positioning --------------------------------------------------------
    /// Wrapper for `LLVMPositionBuilder`.
    pub fn position(&mut self, block: &mut BasicBlock, inst: &Value)
                   -> &mut Self {
        unsafe {
            LLVMPositionBuilder(self.to_ref(), block.to_ref(), inst.to_ref());
        }
        self
    }
    /// Wrapper for `LLVMPositionBuilderBefore`.
    pub fn position_before(&mut self, inst: &Value) -> &mut Self {
        unsafe { LLVMPositionBuilderBefore(self.to_ref(), inst.to_ref()) }
        self
    }
    /// Wrapper for `LLVMPositionBuilderAtEnd`.
    pub fn position_at_end(&mut self, block: &mut BasicBlock) -> &mut Self {
        unsafe { LLVMPositionBuilderAtEnd(self.to_ref(), block.to_ref()) }
        self
    }

    //---- insertion ----------------------------------------------------------
    pub fn get_insert_block(&mut self) -> BasicBlock {
        unsafe { BasicBlock::from_ref(LLVMGetInsertBlock(self.to_ref())) }
    }
    pub fn clear_insertion_position(&mut self) -> &mut Self {
        unsafe { LLVMClearInsertionPosition(self.to_ref()) }
        self
    }
    pub fn insert(&mut self, inst: &mut Value) -> &mut Self {
        unsafe { LLVMInsertIntoBuilder(self.to_ref(), inst.to_ref()) }
        self
    }
    pub fn insert_with_name(&mut self, inst: &mut Value, name: &str)
                            -> &mut Self {
        let cname = CString::new(name).expect_ice(
                    format!("Couldn't create CString for {}", name).as_ref());
        unsafe {
            LLVMInsertIntoBuilderWithName( self.to_ref()
                                         , inst.to_ref()
                                         , cname.as_ptr() as *const c_char)
        }
        self
    }
}
<commit_msg>[core] Start on build...() methods for LLVM builder<commit_after>//
//  0 1 0  Mnemosyne: a functional systems programming language.
//  0 0 1  (c) 2015 Hawk Weisman
//  1 1 1  hi@hawkweisman.me
//
//  Mnemosyne is released under the MIT License. Please refer to
//  the LICENSE file at the top-level directory of this distribution
//  or at https://github.com/hawkw/mnemosyne/.
//
use rustc::lib::llvm;
use rustc::lib::llvm::*;

use std::ffi::CString;

use libc::{c_char, c_uint};

use ::errors::{ExpectICE, UnwrapICE};

// pub struct Context(llvm::ContextRef);
//
// pub struct Builder(llvm::BuilderRef);

/// because we are in the Raw Pointer Sadness Zone (read: unsafe),
/// it is necessary that we assert that everything exists.
macro_rules! not_null {
    ($target:expr) => ({
        let e = $target;
        if e.is_null() {
            ice!( "assertion failed: {} returned null!"
                , stringify!($target)
                );
        } else { e }
    })
}

trait LLVMWrapper {
    type Ref;
    fn to_ref(&self) -> Self::Ref;
    fn from_ref(r: Self::Ref) -> Self;
}

macro_rules! llvm_wrapper {
    ( $($name:ident wrapping $wrapped:path),*) => {$(
        pub struct $name ($wrapped);

        impl LLVMWrapper for $name {
            type Ref = $wrapped;

            fn to_ref(&self) -> Self::Ref {
                not_null!(self.0)
            }

            fn from_ref(r: $wrapped) -> Self {
                $name( not_null!(r) )
            }
        }
    )*};
    ( $($name:ident wrapping $wrapped:path, dropped by $drop:path),*) => {$(
        llvm_wrapper!{ $name wrapping $wrapped }

        impl Drop for $name {
            fn drop(&mut self) {
                unsafe { $drop(self.0) }
            }
        }
    )*}
}

llvm_wrapper! {
    Context wrapping llvm::ContextRef, dropped by llvm::LLVMContextDispose,
    Builder wrapping llvm::BuilderRef, dropped by llvm::LLVMDisposeBuilder
}

llvm_wrapper! {
    BasicBlock wrapping llvm::BasicBlockRef,
    Value wrapping llvm::ValueRef
}

impl Context {
    /// Construct a new Builder within this `Context`.
    pub fn create_builder(&self) -> Builder {
        unsafe {
            Builder::from_ref(LLVMCreateBuilderInContext(self.to_ref()))
        }
    }
}

impl Builder {
    //---- positioning --------------------------------------------------------
    /// Wrapper for `LLVMPositionBuilder`.
    pub fn position(&mut self, block: &mut BasicBlock, inst: &Value)
                   -> &mut Self {
        unsafe {
            LLVMPositionBuilder(self.to_ref(), block.to_ref(), inst.to_ref());
        }
        self
    }

    /// Wrapper for `LLVMPositionBuilderBefore`.
    pub fn position_before(&mut self, inst: &Value) -> &mut Self {
        unsafe { LLVMPositionBuilderBefore(self.to_ref(), inst.to_ref()) }
        self
    }

    /// Wrapper for `LLVMPositionBuilderAtEnd`.
    pub fn position_at_end(&mut self, block: &mut BasicBlock) -> &mut Self {
        unsafe { LLVMPositionBuilderAtEnd(self.to_ref(), block.to_ref()) }
        self
    }

    //---- insertion ----------------------------------------------------------
    pub fn get_insert_block(&mut self) -> BasicBlock {
        unsafe { BasicBlock::from_ref(LLVMGetInsertBlock(self.to_ref())) }
    }

    pub fn clear_insertion_position(&mut self) -> &mut Self {
        unsafe { LLVMClearInsertionPosition(self.to_ref()) }
        self
    }

    pub fn insert(&mut self, inst: &mut Value) -> &mut Self {
        unsafe { LLVMInsertIntoBuilder(self.to_ref(), inst.to_ref()) }
        self
    }

    pub fn insert_with_name(&mut self, inst: &mut Value, name: &str)
                            -> &mut Self {
        let cname = CString::new(name).expect_ice(
                    format!("Couldn't create CString for {}", name).as_ref());
        unsafe {
            LLVMInsertIntoBuilderWithName( self.to_ref()
                                         , inst.to_ref()
                                         , cname.as_ptr() as *const c_char)
        }
        self
    }
    //---- building ----------------------------------------------------------
    pub fn build_ret_void(&mut self) -> Value {
        unsafe { Value::from_ref( LLVMBuildRetVoid(self.to_ref()) ) }
    }

    pub fn build_ret(&mut self, v: &Value) -> Value {
        unsafe {
            Value::from_ref( LLVMBuildRet(self.to_ref(), value.to_ref()) )
        }
    }

    pub fn build_br(&mut self, dest: &BasicBlock) -> Value {
        unsafe {
            Value::from_ref( LLVMBuildBr(self.to_ref(), dest.to_ref()) )
        }
    }

    pub fn build_cond_br( &mut self
                        , condition: Value
                        , then_block: &BasicBlock
                        , else_block: &BasicBlock )
                        -> Value {
        unsafe {
            let val = LLVMBuildCondBr( self.to_ref()
                                     , condition.to_ref()
                                     , then_block.to_ref()
                                     , else_block.to_ref() );
        }
        Value::from_ref(val)
    }

    pub fn build_switch_br( &mut self
                          , on: Value
                          , else_block: &BasicBlock
                          , num_cases: u32 )
                          -> Value {
        unsafe {
            Value::from_ref(LLVMBuildSwitch( self.to_ref()
                                            , on.to_ref()
                                            , else_block.to_ref()
                                            , num_cases))
        }

    }

}
<|endoftext|>