<commit_before>use std::cmp::{max, min};
use std::isize;

const DATA: &'static str = include_str!("../data/input_22.txt");

pub fn main() -> Vec<String> {
    let hero = Character::wizard();
    let boss = Character::boss(DATA);
    let s1 = find_best_solution(&hero, &boss, 0, isize::MAX);
    let s2 = find_best_solution(&hero, &boss, 1, isize::MAX);
    vec![s1.unwrap().to_string(), s2.unwrap().to_string()]
}

#[derive(Clone)]
enum Effect {
    Shield {
        turns: usize,
        armor: isize,
    },
    Poison {
        turns: usize,
        damage: isize,
    },
    Recharge {
        turns: usize,
        mana: isize,
    },
}

enum Spell {
    MagicMissile,
    Drain,
    Shield,
    Poison,
    Recharge,
}

impl Spell {
    fn cost(&self) -> isize {
        match *self {
            Spell::MagicMissile => 53,
            Spell::Drain => 73,
            Spell::Shield => 113,
            Spell::Poison => 173,
            Spell::Recharge => 229,
        }
    }

    fn cast(&self, caster: &mut Character, enemy: &mut Character) {
        let cost = self.cost();
        caster.mana -= cost;
        caster.mana_spent += cost;
        match *self {
            Spell::MagicMissile => {
                // println!("Player casts Magic Missile, dealing 4 damage.");
                enemy.hp -= 4;
            }
            Spell::Drain => {
                // println!("Player casts Drain, dealing 2 damage, and healing 2 hit points.");
                enemy.hp -= 2;
                caster.hp += 2;
            }
            Spell::Shield => {
                // println!("Player casts Shield, increasing armor by 7.");
                caster.armor += 7;
                caster.install(Effect::Shield {
                    turns: 6,
                    armor: 7,
                })
            }
            Spell::Poison => {
                // println!("Player casts Poison.");
                caster.install(Effect::Poison {
                    turns: 6,
                    damage: 3,
                })
            }
            Spell::Recharge => {
                // println!("Player casts Recharge.");
                caster.install(Effect::Recharge {
                    turns: 5,
                    mana: 101,
                })
            }
        }
    }
}

#[derive(Clone)]
struct Character {
    hp: isize,
    damage: isize,
    armor: isize,
    mana: isize,
    // eh, not very general but that's OK
    shield: Option<Effect>,
    poison: Option<Effect>,
    recharge: Option<Effect>,
    mana_spent: isize,
}

impl Character {
    fn new() -> Character {
        Character {
            hp: 0,
            damage: 0,
            armor: 0,
            mana: 0,
            shield: None,
            poison: None,
            recharge: None,
            mana_spent: 0,
        }
    }

    fn wizard() -> Character {
        Character {
            hp: 50,
            mana: 500,
            ..Character::new()
        }
    }

    fn boss(data: &str) -> Character {
        let mut lines = data.lines();
        let hp = scan_fmt!(lines.next().unwrap(), "Hit Points: {}", isize).unwrap();
        let damage = scan_fmt!(lines.next().unwrap(), "Damage: {}", isize).unwrap();

        Character {
            hp: hp,
            damage: damage,
            ..Character::new()
        }
    }

    fn install(&mut self, effect: Effect) {
        match effect {
            s @ Effect::Shield{..} => self.shield = Some(s),
            p @ Effect::Poison{..} => self.poison = Some(p),
            r @ Effect::Recharge{..} => self.recharge = Some(r),
        }
    }

    fn run_effects(&mut self, boss: &mut Character) {
        let mut clear_shield = false;
        let mut clear_poison = false;
        let mut clear_recharge = false;

        if let Some(Effect::Shield{ref mut turns, armor}) = self.shield {
            *turns -= 1;
            // println!("Shield's timer is now {}.", turns);
            if *turns == 0 {
                // println!("Shield wears off, decreasing armor by 7.");
                self.armor -= armor;
                clear_shield = true;
            }
        }
        if clear_shield {
            self.shield = None;
        }

        if let Some(Effect::Poison{ref mut turns, damage}) = self.poison {
            *turns -= 1;
            // println!("Poison's deals {} damage; its timer is now {}.", damage, turns);
            boss.hp -= damage;
            if *turns == 0 {
                // println!("Poison wears off.");
                clear_poison = true;
            }
        }
        if clear_poison {
            self.poison = None;
        }

        if let Some(Effect::Recharge{ref mut turns, mana}) = self.recharge {
            *turns -= 1;
            // println!("Recharge provides {} mana; its timer is now {}.", mana, turns);
            self.mana += mana;
            if *turns == 0 {
                // println!("Recharge wears off.");
                clear_recharge = true;
            }
        }
        if clear_recharge {
            self.recharge = None;
        }
    }

    fn valid_spells(&self) -> Vec<Spell> {
        let mut choices = Vec::new();

        if self.mana >= Spell::MagicMissile.cost() {
            choices.push(Spell::MagicMissile);
        }
        if self.mana >= Spell::Drain.cost() {
            choices.push(Spell::Drain);
        }
        if self.mana >= Spell::Shield.cost() && self.shield.is_none() {
            choices.push(Spell::Shield);
        }
        if self.mana >= Spell::Poison.cost() && self.poison.is_none() {
            choices.push(Spell::Poison);
        }
        if self.mana >= Spell::Recharge.cost() && self.recharge.is_none() {
            choices.push(Spell::Recharge);
        }
        choices
    }
}

fn find_best_solution(h: &Character, b: &Character, hard: isize, mut best: isize) -> Option<isize> {
    if h.mana_spent >= best {
        return None;
    }

    let mut h1 = h.clone();
    let mut b1 = b.clone();

    // println!("\n-- Player turn --");
    // println!("- Player has {} hit points, {} armor, {} mana", hero.hp, hero.armor, hero.mana);
    // println!("- Boss has {} hit points", boss.hp);

    h1.hp -= hard;

    if h1.hp < 1 {
        return None;
    }

    h1.run_effects(&mut b1);

    if b1.hp < 1 {
        return Some(h1.mana_spent);
    }

    h1.valid_spells()
        .iter()
        .filter_map(|spell| {
            let mut hero = h1.clone();
            let mut boss = b1.clone();

            spell.cast(&mut hero, &mut boss);

            if boss.hp < 1 {
                // println!("This kills the boss, and the player wins");
                // println!("## total mana spent was {} ##", hero.mana_spent);
                return Some(hero.mana_spent);
            }

            // println!("\n-- Boss turn --");
            // println!("- Player has {} hit points, {} armor, {} mana", hero.hp, hero.armor, hero.mana);
            // println!("- Boss has {} hit points", boss.hp);

            hero.run_effects(&mut boss);

            if boss.hp < 1 {
                return Some(hero.mana_spent);
            }

            let damage = max(1, boss.damage - hero.armor);

            // println!("Boss attacks for {} - {} = {} damage!", boss.damage, hero.armor, damage);

            hero.hp -= damage;

            if hero.hp < 1 {
                // println!("This kills the player, and the boss wins");
                return None;
            }

            let r = find_best_solution(&hero, &boss, hard, best);
            if let Some(new_best) = r {
               best = min(best, new_best);
            }
            r
        })
        .min()
}
<commit_msg>day 22: better error handling on input file parsing<commit_after>use std::cmp::{max, min};
use std::isize;

const DATA: &'static str = include_str!("../data/input_22.txt");

pub fn main() -> Vec<String> {
    let hero = Character::wizard();
    let boss = Character::boss(DATA).unwrap();
    let s1 = find_best_solution(&hero, &boss, 0, isize::MAX);
    let s2 = find_best_solution(&hero, &boss, 1, isize::MAX);
    vec![s1.unwrap().to_string(), s2.unwrap().to_string()]
}

#[derive(Clone)]
enum Effect {
    Shield {
        turns: usize,
        armor: isize,
    },
    Poison {
        turns: usize,
        damage: isize,
    },
    Recharge {
        turns: usize,
        mana: isize,
    },
}

enum Spell {
    MagicMissile,
    Drain,
    Shield,
    Poison,
    Recharge,
}

impl Spell {
    fn cost(&self) -> isize {
        match *self {
            Spell::MagicMissile => 53,
            Spell::Drain => 73,
            Spell::Shield => 113,
            Spell::Poison => 173,
            Spell::Recharge => 229,
        }
    }

    fn cast(&self, caster: &mut Character, enemy: &mut Character) {
        let cost = self.cost();
        caster.mana -= cost;
        caster.mana_spent += cost;
        match *self {
            Spell::MagicMissile => {
                // println!("Player casts Magic Missile, dealing 4 damage.");
                enemy.hp -= 4;
            }
            Spell::Drain => {
                // println!("Player casts Drain, dealing 2 damage, and healing 2 hit points.");
                enemy.hp -= 2;
                caster.hp += 2;
            }
            Spell::Shield => {
                // println!("Player casts Shield, increasing armor by 7.");
                caster.armor += 7;
                caster.install(Effect::Shield {
                    turns: 6,
                    armor: 7,
                })
            }
            Spell::Poison => {
                // println!("Player casts Poison.");
                caster.install(Effect::Poison {
                    turns: 6,
                    damage: 3,
                })
            }
            Spell::Recharge => {
                // println!("Player casts Recharge.");
                caster.install(Effect::Recharge {
                    turns: 5,
                    mana: 101,
                })
            }
        }
    }
}

#[derive(Clone)]
struct Character {
    hp: isize,
    damage: isize,
    armor: isize,
    mana: isize,
    // eh, not very general but that's OK
    shield: Option<Effect>,
    poison: Option<Effect>,
    recharge: Option<Effect>,
    mana_spent: isize,
}

impl Character {
    fn new() -> Character {
        Character {
            hp: 0,
            damage: 0,
            armor: 0,
            mana: 0,
            shield: None,
            poison: None,
            recharge: None,
            mana_spent: 0,
        }
    }

    fn wizard() -> Character {
        Character {
            hp: 50,
            mana: 500,
            ..Character::new()
        }
    }

    fn boss(data: &str) -> Option<Character> {
        let mut lines = data.lines();

        if let (Some(hp), Some(damage)) = (lines.next().map_or(None, |l| {
            scan_fmt!(l, "Hit Points: {}", isize)
        }),
                                           lines.next().map_or(None, |l| {
            scan_fmt!(l, "Damage: {}", isize)
        })) {

            Some(Character {
                hp: hp,
                damage: damage,
                ..Character::new()
            })
        } else {
            None
        }
    }

    fn install(&mut self, effect: Effect) {
        match effect {
            s @ Effect::Shield{..} => self.shield = Some(s),
            p @ Effect::Poison{..} => self.poison = Some(p),
            r @ Effect::Recharge{..} => self.recharge = Some(r),
        }
    }

    fn run_effects(&mut self, boss: &mut Character) {
        let mut clear_shield = false;
        let mut clear_poison = false;
        let mut clear_recharge = false;

        if let Some(Effect::Shield{ref mut turns, armor}) = self.shield {
            *turns -= 1;
            // println!("Shield's timer is now {}.", turns);
            if *turns == 0 {
                // println!("Shield wears off, decreasing armor by 7.");
                self.armor -= armor;
                clear_shield = true;
            }
        }
        if clear_shield {
            self.shield = None;
        }

        if let Some(Effect::Poison{ref mut turns, damage}) = self.poison {
            *turns -= 1;
            // println!("Poison's deals {} damage; its timer is now {}.", damage, turns);
            boss.hp -= damage;
            if *turns == 0 {
                // println!("Poison wears off.");
                clear_poison = true;
            }
        }
        if clear_poison {
            self.poison = None;
        }

        if let Some(Effect::Recharge{ref mut turns, mana}) = self.recharge {
            *turns -= 1;
            // println!("Recharge provides {} mana; its timer is now {}.", mana, turns);
            self.mana += mana;
            if *turns == 0 {
                // println!("Recharge wears off.");
                clear_recharge = true;
            }
        }
        if clear_recharge {
            self.recharge = None;
        }
    }

    fn valid_spells(&self) -> Vec<Spell> {
        let mut choices = Vec::new();

        if self.mana >= Spell::MagicMissile.cost() {
            choices.push(Spell::MagicMissile);
        }
        if self.mana >= Spell::Drain.cost() {
            choices.push(Spell::Drain);
        }
        if self.mana >= Spell::Shield.cost() && self.shield.is_none() {
            choices.push(Spell::Shield);
        }
        if self.mana >= Spell::Poison.cost() && self.poison.is_none() {
            choices.push(Spell::Poison);
        }
        if self.mana >= Spell::Recharge.cost() && self.recharge.is_none() {
            choices.push(Spell::Recharge);
        }
        choices
    }
}

fn find_best_solution(h: &Character, b: &Character, hard: isize, mut best: isize) -> Option<isize> {
    if h.mana_spent >= best {
        return None;
    }

    let mut h1 = h.clone();
    let mut b1 = b.clone();

    // println!("\n-- Player turn --");
    // println!("- Player has {} hit points, {} armor, {} mana", hero.hp, hero.armor, hero.mana);
    // println!("- Boss has {} hit points", boss.hp);

    h1.hp -= hard;

    if h1.hp < 1 {
        return None;
    }

    h1.run_effects(&mut b1);

    if b1.hp < 1 {
        return Some(h1.mana_spent);
    }

    h1.valid_spells()
        .iter()
        .filter_map(|spell| {
            let mut hero = h1.clone();
            let mut boss = b1.clone();

            spell.cast(&mut hero, &mut boss);

            if boss.hp < 1 {
                // println!("This kills the boss, and the player wins");
                // println!("## total mana spent was {} ##", hero.mana_spent);
                return Some(hero.mana_spent);
            }

            // println!("\n-- Boss turn --");
            // println!("- Player has {} hit points, {} armor, {} mana", hero.hp, hero.armor, hero.mana);
            // println!("- Boss has {} hit points", boss.hp);

            hero.run_effects(&mut boss);

            if boss.hp < 1 {
                return Some(hero.mana_spent);
            }

            let damage = max(1, boss.damage - hero.armor);

            // println!("Boss attacks for {} - {} = {} damage!", boss.damage, hero.armor, damage);

            hero.hp -= damage;

            if hero.hp < 1 {
                // println!("This kills the player, and the boss wins");
                return None;
            }

            let r = find_best_solution(&hero, &boss, hard, best);
            if let Some(new_best) = r {
               best = min(best, new_best);
            }
            r
        })
        .min()
}
<|endoftext|>


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

use scanner::Scanner;

/// Scan for email address starting from the trigger character "@".
///
/// Based on RFC 6531, but also scans invalid IDN. Doesn't match IP address in domain part or
/// quoting in local part.
pub struct EmailScanner {
    pub domain_must_have_dot: bool,
}

impl Scanner for EmailScanner {
    fn scan(&self, s: &str, at: usize) -> Option<Range<usize>> {
        if let Some(start) = self.find_start(s, at) {
            if let Some(end) = self.find_end(s, at + 1) {
                return Some(Range {
                    start: start,
                    end: end,
                });
            }
        }
        return None;
    }
}

impl EmailScanner {
    // See "Local-part" in RFC 5321, plus extensions in RFC 6531
    fn find_start(&self, s: &str, at: usize) -> Option<usize> {
        let mut first = None;
        let mut atom_boundary = true;
        for (i, c) in s[0..at].char_indices().rev() {
            if Self::local_atom_allowed(c) {
                first = Some(i);
                atom_boundary = false;
            } else if c == '.' {
                if atom_boundary {
                    break;
                }
                atom_boundary = true;
            } else {
                break;
            }
        }
        first
    }

    // See "Domain" in RFC 5321, plus extension of "sub-domain" in RFC 6531
    fn find_end(&self, s: &str, start: usize) -> Option<usize> {
        let mut first_in_sub_domain = true;
        let mut can_end_sub_domain = false;
        let mut first_dot = None;
        let mut last = None;

        for (i, c) in s[start..].char_indices() {
            if first_in_sub_domain {
                if Self::sub_domain_allowed(c) {
                    last = Some(i);
                    first_in_sub_domain = false;
                    can_end_sub_domain = true;
                } else {
                    break;
                }
            } else {
                if c == '.' {
                    if !can_end_sub_domain {
                        break;
                    }
                    first_in_sub_domain = true;
                    if first_dot.is_none() {
                        first_dot = Some(i);
                    }
                } else if c == '-' {
                    can_end_sub_domain = false;
                } else if Self::sub_domain_allowed(c) {
                    last = Some(i);
                    can_end_sub_domain = true;
                } else {
                    break;
                }
            }
        }

        if let Some(last) = last {
            if !self.domain_must_have_dot || first_dot.map(|d| d < last).unwrap_or(false) {
                Some(start + last + 1)
            } else {
                None
            }
        } else {
            None
        }
    }

    // See "Atom" in RFC 5321, "atext" in RFC 5322
    fn local_atom_allowed(c: char) -> bool {
        match c {
            'a' ... 'z' | 'A' ... 'Z' | '0' ... '9' | '!' | '#' | '$' | '%' | '&' | '\'' | '*' |
            '+' | '-' | '/' | '=' | '?' | '^' | '_' | '`' | '{' | '|' | '}' | '~' => true,
            _ => c >= '\u{80}',
        }
    }

    // See "sub-domain" in RFC 5321. Extension in RFC 6531 is simplified, this can also match invalid domains.
    fn sub_domain_allowed(c: char) -> bool {
        match c {
            'a' ... 'z' | 'A' ... 'Z' | '0' ... '9' => true,
            _ => c >= '\u{80}',
        }
    }
}
<commit_msg>Pass slices to email scanner methods as well<commit_after>use std::ops::Range;

use scanner::Scanner;

/// Scan for email address starting from the trigger character "@".
///
/// Based on RFC 6531, but also scans invalid IDN. Doesn't match IP address in domain part or
/// quoting in local part.
pub struct EmailScanner {
    pub domain_must_have_dot: bool,
}

impl Scanner for EmailScanner {
    fn scan(&self, s: &str, at: usize) -> Option<Range<usize>> {
        if let Some(start) = self.find_start(&s[0..at]) {
            let after = at + 1;
            if let Some(end) = self.find_end(&s[after..]) {
                return Some(Range {
                    start: start,
                    end: after + end,
                });
            }
        }
        return None;
    }
}

impl EmailScanner {
    // See "Local-part" in RFC 5321, plus extensions in RFC 6531
    fn find_start(&self, s: &str) -> Option<usize> {
        let mut first = None;
        let mut atom_boundary = true;
        for (i, c) in s.char_indices().rev() {
            if Self::local_atom_allowed(c) {
                first = Some(i);
                atom_boundary = false;
            } else if c == '.' {
                if atom_boundary {
                    break;
                }
                atom_boundary = true;
            } else {
                break;
            }
        }
        first
    }

    // See "Domain" in RFC 5321, plus extension of "sub-domain" in RFC 6531
    fn find_end(&self, s: &str) -> Option<usize> {
        let mut first_in_sub_domain = true;
        let mut can_end_sub_domain = false;
        let mut first_dot = None;
        let mut last = None;

        for (i, c) in s.char_indices() {
            if first_in_sub_domain {
                if Self::sub_domain_allowed(c) {
                    last = Some(i);
                    first_in_sub_domain = false;
                    can_end_sub_domain = true;
                } else {
                    break;
                }
            } else {
                if c == '.' {
                    if !can_end_sub_domain {
                        break;
                    }
                    first_in_sub_domain = true;
                    if first_dot.is_none() {
                        first_dot = Some(i);
                    }
                } else if c == '-' {
                    can_end_sub_domain = false;
                } else if Self::sub_domain_allowed(c) {
                    last = Some(i);
                    can_end_sub_domain = true;
                } else {
                    break;
                }
            }
        }

        if let Some(last) = last {
            if !self.domain_must_have_dot || first_dot.map(|d| d < last).unwrap_or(false) {
                Some(last + 1)
            } else {
                None
            }
        } else {
            None
        }
    }

    // See "Atom" in RFC 5321, "atext" in RFC 5322
    fn local_atom_allowed(c: char) -> bool {
        match c {
            'a' ... 'z' | 'A' ... 'Z' | '0' ... '9' | '!' | '#' | '$' | '%' | '&' | '\'' | '*' |
            '+' | '-' | '/' | '=' | '?' | '^' | '_' | '`' | '{' | '|' | '}' | '~' => true,
            _ => c >= '\u{80}',
        }
    }

    // See "sub-domain" in RFC 5321. Extension in RFC 6531 is simplified, this can also match invalid domains.
    fn sub_domain_allowed(c: char) -> bool {
        match c {
            'a' ... 'z' | 'A' ... 'Z' | '0' ... '9' => true,
            _ => c >= '\u{80}',
        }
    }
}
<|endoftext|>


<commit_before>#![macro_use]

pub enum Match<V, O: Enum> {
    Variant(V),
    Next(O),
}

pub trait Enum {
    type Variant;
    type Next: Enum;
}

impl Enum for ! {
    type Variant = !;
    type Next = !;
}

impl<V, E: Enum> Enum for Match<V, E> {
    type Variant = V;
    type Next = E;
}

#[macro_export]
macro_rules! enums {
    ($head:ty, $($tail:ty),+) => {
        $crate::enums::Match<$head, enums![ $($tail),* ]>
    };

    ($head:ty) => {
        $crate::enums::Match<$head, !>
    };
}

#[cfg(test)]
mod tests {

    use super::{Match};
    #[test]
    fn enum_once() {
        use enums::Match::*;
        type Vars = enums![i32, &'static str, f64];
        let integer: Vars = Variant(42);
        let string = Next(Variant("Happy!"));
        let float = Next(Next(Variant(42.0)));

        let answers = ["I am an integer: 42", "I am Happy!", "I am exactly: 42.0"];
        for (item, answer) in [integer, string, float].into_iter().zip(answers.into_iter()) {
            let ans = match item {
                &Variant(i) => format!("I am an integer: {}", i),
                &Next(Variant(s)) => format!("I am {}", s),
                &Next(Next(Variant(f))) => format!("I am exactly: {:.1}", f),
            };
            assert_eq!(ans, *answer);
        }
    }
}
<commit_msg>Remove unused import<commit_after>#![macro_use]

pub enum Match<V, O: Enum> {
    Variant(V),
    Next(O),
}

pub trait Enum {
    type Variant;
    type Next: Enum;
}

impl Enum for ! {
    type Variant = !;
    type Next = !;
}

impl<V, E: Enum> Enum for Match<V, E> {
    type Variant = V;
    type Next = E;
}

#[macro_export]
macro_rules! enums {
    ($head:ty, $($tail:ty),+) => {
        $crate::enums::Match<$head, enums![ $($tail),* ]>
    };

    ($head:ty) => {
        $crate::enums::Match<$head, !>
    };
}

#[cfg(test)]
mod tests {

    #[test]
    fn enum_once() {
        use enums::Match::*;
        type Vars = enums![i32, &'static str, f64];
        let integer: Vars = Variant(42);
        let string = Next(Variant("Happy!"));
        let float = Next(Next(Variant(42.0)));

        let answers = ["I am an integer: 42", "I am Happy!", "I am exactly: 42.0"];
        for (item, answer) in [integer, string, float].into_iter().zip(answers.into_iter()) {
            let ans = match item {
                &Variant(i) => format!("I am an integer: {}", i),
                &Next(Variant(s)) => format!("I am {}", s),
                &Next(Next(Variant(f))) => format!("I am exactly: {:.1}", f),
            };
            assert_eq!(ans, *answer);
        }
    }
}
<|endoftext|>


<commit_before>// mod error
use std::error::{self, Error as Err};
use std::fmt::{self, Display};
use std::io;
use std::convert::From;
use std::net::AddrParseError;
use std::sync::PoisonError;
use std::result;
use escaping::unescape;

/// The standart result type of sqlib.
pub type Result<T> = result::Result<T, Error>;

/// A SQError contains a TS3 Server Query error.
///
/// # Example
/// ```
/// use sqlib::error::SQError;
///
/// let line = "error id=0 msg=ok".to_string();
///
/// let err_option = SQError::parse(&line);
/// let err = match err_option {
///     Some(err) => err,
///     None => { panic!("no error found"); },
/// };
/// assert_eq!(0, err.id());
/// ```
#[derive(Debug)]
pub struct SQError {
    id: u32,
    msg: String,
    full_msg: String,
}

// helping function for SQError::parse
fn is_seperator(c: char) -> bool {
    c == '=' || c.is_whitespace()
}

impl SQError {
    pub fn new(id: u32, msg: String) -> SQError {
        let full_msg_str = format!("error id={} msg={}", id, &msg);
        SQError {
            id: id,
            msg: msg,
            full_msg: full_msg_str,
        }
    }

    /// Creates an OK error.
    pub fn ok() -> SQError {
        SQError::new(0, "ok".to_string())
    }

    /// This function tries to parse a string into an Error.
    ///
    /// # Return values
    ///
    /// - If it fails to parse it returns Ok(false).
    /// - If it parses the string as an OK error it returns Ok(true).
    /// - If it parses the string as another error it returns Err(error).
    ///
    /// # Example
    /// ```
    /// use sqlib::error::{Error, SQError};
    ///
    /// let ok_str = "error id=0 msg=ok";
    /// let no_err_str = "this is no error";
    /// let err_str = "error id=1 msg=test";
    ///
    /// let test_err = SQError::new(1, "test".to_string());
    /// let to_test_error = match SQError::parse_is_ok(err_str).unwrap_err() {
    ///     Error::SQ(e) => e,
    ///     _ => SQError::ok(),
    /// };
    ///
    /// assert_eq!(SQError::parse_is_ok(ok_str).unwrap(), true);
    /// assert_eq!(SQError::parse_is_ok(no_err_str).unwrap(), false);
    /// assert_eq!(to_test_error, test_err);
    /// ```
    pub fn parse_is_ok(s: &str) -> Result<bool> {
        let err = match SQError::parse(s) {
            None => {
                return Ok(false);
            }
            Some(err) => err,
        };
        if err == SQError::ok() {
            Ok(true)
        } else {
            Err(Error::from(err))
        }
    }

    /// try to parse a String to a SQError
    pub fn parse(s: &str) -> Option<SQError> {
        // the str shouldn't be trimmed, because a real error is without
        // whitespace in the beginning
        let parts: Vec<&str> = s.splitn(6, is_seperator).collect();
        if parts.len() < 5 {
            return None;
        }
        if parts[0] != "error" {
            return None;
        }
        if parts[1] != "id" {
            return None;
        }
        let id_result = parts[2].clone().parse::<u32>();
        let id = match id_result {
            Err(_) => {
                return None;
            }
            Ok(val) => val,
        };
        if parts[3] != "msg" {
            return None;
        }
        let msg = parts[4].to_string().clone();
        Some(SQError::new(id, unescape(&msg)))
    }

    pub fn id(&self) -> u32 {
        self.id
    }

    pub fn msg(&self) -> String {
        self.msg.clone()
    }
}

impl PartialEq for SQError {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for SQError {}

impl Display for SQError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.full_msg)
    }
}

impl error::Error for SQError {
    fn description(&self) -> &str {
        &self.full_msg
    }
}

/// Error is a custom Error type for the sqlib.
#[derive(Debug)]
pub enum Error {
    /// wraps io::Error
    Io(io::Error),
    /// server query error messages
    SQ(SQError),
    /// other errors
    Other(String),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::Io(ref err) => err.description(),
            &Error::SQ(ref err) => err.description(),
            &Error::Other(ref s) => s,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl<'a> From<&'a str> for Error {
    fn from(err: &'a str) -> Error {
        Error::Other(err.to_string())
    }
}

impl From<String> for Error {
    fn from(err: String) -> Error {
        Error::Other(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<SQError> for Error {
    fn from(err: SQError) -> Error {
        Error::SQ(err)
    }
}

impl From<AddrParseError> for Error {
    fn from(err: AddrParseError) -> Error {
        Error::Other(err.description().to_string())
    }
}

impl<T> From<PoisonError<T>> for Error {
    fn from(err: PoisonError<T>) -> Error {
        Error::Other(format!("{}", err))
    }
}
<commit_msg>adding module comment to sqlib::error<commit_after>//! error provides newtypes and Error's for sqlib.

use std::error::{self, Error as Err};
use std::fmt::{self, Display};
use std::io;
use std::convert::From;
use std::net::AddrParseError;
use std::sync::PoisonError;
use std::result;
use escaping::unescape;

/// The standart result type of sqlib.
pub type Result<T> = result::Result<T, Error>;

/// A SQError contains a TS3 Server Query error.
///
/// # Example
/// ```
/// use sqlib::error::SQError;
///
/// let line = "error id=0 msg=ok".to_string();
///
/// let err_option = SQError::parse(&line);
/// let err = match err_option {
///     Some(err) => err,
///     None => { panic!("no error found"); },
/// };
/// assert_eq!(0, err.id());
/// ```
#[derive(Debug)]
pub struct SQError {
    id: u32,
    msg: String,
    full_msg: String,
}

// helping function for SQError::parse
fn is_seperator(c: char) -> bool {
    c == '=' || c.is_whitespace()
}

impl SQError {
    pub fn new(id: u32, msg: String) -> SQError {
        let full_msg_str = format!("error id={} msg={}", id, &msg);
        SQError {
            id: id,
            msg: msg,
            full_msg: full_msg_str,
        }
    }

    /// Creates an OK error.
    pub fn ok() -> SQError {
        SQError::new(0, "ok".to_string())
    }

    /// This function tries to parse a string into an Error.
    ///
    /// # Return values
    ///
    /// - If it fails to parse it returns Ok(false).
    /// - If it parses the string as an OK error it returns Ok(true).
    /// - If it parses the string as another error it returns Err(error).
    ///
    /// # Example
    /// ```
    /// use sqlib::error::{Error, SQError};
    ///
    /// let ok_str = "error id=0 msg=ok";
    /// let no_err_str = "this is no error";
    /// let err_str = "error id=1 msg=test";
    ///
    /// let test_err = SQError::new(1, "test".to_string());
    /// let to_test_error = match SQError::parse_is_ok(err_str).unwrap_err() {
    ///     Error::SQ(e) => e,
    ///     _ => SQError::ok(),
    /// };
    ///
    /// assert_eq!(SQError::parse_is_ok(ok_str).unwrap(), true);
    /// assert_eq!(SQError::parse_is_ok(no_err_str).unwrap(), false);
    /// assert_eq!(to_test_error, test_err);
    /// ```
    pub fn parse_is_ok(s: &str) -> Result<bool> {
        let err = match SQError::parse(s) {
            None => {
                return Ok(false);
            }
            Some(err) => err,
        };
        if err == SQError::ok() {
            Ok(true)
        } else {
            Err(Error::from(err))
        }
    }

    /// try to parse a String to a SQError
    pub fn parse(s: &str) -> Option<SQError> {
        // the str shouldn't be trimmed, because a real error is without
        // whitespace in the beginning
        let parts: Vec<&str> = s.splitn(6, is_seperator).collect();
        if parts.len() < 5 {
            return None;
        }
        if parts[0] != "error" {
            return None;
        }
        if parts[1] != "id" {
            return None;
        }
        let id_result = parts[2].clone().parse::<u32>();
        let id = match id_result {
            Err(_) => {
                return None;
            }
            Ok(val) => val,
        };
        if parts[3] != "msg" {
            return None;
        }
        let msg = parts[4].to_string().clone();
        Some(SQError::new(id, unescape(&msg)))
    }

    pub fn id(&self) -> u32 {
        self.id
    }

    pub fn msg(&self) -> String {
        self.msg.clone()
    }
}

impl PartialEq for SQError {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for SQError {}

impl Display for SQError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.full_msg)
    }
}

impl error::Error for SQError {
    fn description(&self) -> &str {
        &self.full_msg
    }
}

/// Error is a custom Error type for the sqlib.
#[derive(Debug)]
pub enum Error {
    /// wraps io::Error
    Io(io::Error),
    /// server query error messages
    SQ(SQError),
    /// other errors
    Other(String),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::Io(ref err) => err.description(),
            &Error::SQ(ref err) => err.description(),
            &Error::Other(ref s) => s,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl<'a> From<&'a str> for Error {
    fn from(err: &'a str) -> Error {
        Error::Other(err.to_string())
    }
}

impl From<String> for Error {
    fn from(err: String) -> Error {
        Error::Other(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<SQError> for Error {
    fn from(err: SQError) -> Error {
        Error::SQ(err)
    }
}

impl From<AddrParseError> for Error {
    fn from(err: AddrParseError) -> Error {
        Error::Other(err.description().to_string())
    }
}

impl<T> From<PoisonError<T>> for Error {
    fn from(err: PoisonError<T>) -> Error {
        Error::Other(format!("{}", err))
    }
}
<|endoftext|>


<commit_before>//! Error and Result module.
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

use httparse;
use openssl::ssl::error::SslError;
use url;

use self::Error::{
    Method,
    Uri,
    Version,
    Header,
    Status,
    Io,
    Ssl,
    TooLarge
};

/// Result type often returned from methods that can have hyper `Error`s.
pub type Result<T> = ::std::result::Result<T, Error>;

/// A set of errors that can occur parsing HTTP streams.
#[derive(Debug)]
pub enum Error {
    /// An invalid `Method`, such as `GE,T`.
    Method,
    /// An invalid `RequestUri`, such as `exam ple.domain`.
    Uri(url::ParseError),
    /// An invalid `HttpVersion`, such as `HTP/1.1`
    Version,
    /// An invalid `Header`.
    Header,
    /// A message head is too large to be reasonable.
    TooLarge,
    /// An invalid `Status`, such as `1337 ELITE`.
    Status,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    Io(IoError),
    /// An error from the `openssl` library.
    Ssl(SslError)
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Method => "Invalid Method specified",
            Uri(_) => "Invalid Request URI specified",
            Version => "Invalid HTTP version specified",
            Header => "Invalid Header provided",
            TooLarge => "Message head is too large",
            Status => "Invalid Status provided",
            Io(ref e) => e.description(),
            Ssl(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Io(ref error) => Some(error),
            Ssl(ref error) => Some(error),
            Uri(ref error) => Some(error),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Io(err)
    }
}

impl From<url::ParseError> for Error {
    fn from(err: url::ParseError) -> Error {
        Uri(err)
    }
}

impl From<SslError> for Error {
    fn from(err: SslError) -> Error {
        match err {
            SslError::StreamError(err) => Io(err),
            err => Ssl(err),
        }
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Error {
        match err {
            httparse::Error::HeaderName => Header,
            httparse::Error::HeaderValue => Header,
            httparse::Error::NewLine => Header,
            httparse::Error::Status => Status,
            httparse::Error::Token => Header,
            httparse::Error::TooManyHeaders => TooLarge,
            httparse::Error::Version => Version,
        }
    }
}
<commit_msg>test(error): increasing test coverage of error module<commit_after>//! Error and Result module.
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

use httparse;
use openssl::ssl::error::SslError;
use url;

use self::Error::{
    Method,
    Uri,
    Version,
    Header,
    Status,
    Io,
    Ssl,
    TooLarge
};

/// Result type often returned from methods that can have hyper `Error`s.
pub type Result<T> = ::std::result::Result<T, Error>;

/// A set of errors that can occur parsing HTTP streams.
#[derive(Debug)]
pub enum Error {
    /// An invalid `Method`, such as `GE,T`.
    Method,
    /// An invalid `RequestUri`, such as `exam ple.domain`.
    Uri(url::ParseError),
    /// An invalid `HttpVersion`, such as `HTP/1.1`
    Version,
    /// An invalid `Header`.
    Header,
    /// A message head is too large to be reasonable.
    TooLarge,
    /// An invalid `Status`, such as `1337 ELITE`.
    Status,
    /// An `io::Error` that occurred while trying to read or write to a network stream.
    Io(IoError),
    /// An error from the `openssl` library.
    Ssl(SslError)
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Method => "Invalid Method specified",
            Version => "Invalid HTTP version specified",
            Header => "Invalid Header provided",
            TooLarge => "Message head is too large",
            Status => "Invalid Status provided",
            Uri(ref e) => e.description(),
            Io(ref e) => e.description(),
            Ssl(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Io(ref error) => Some(error),
            Ssl(ref error) => Some(error),
            Uri(ref error) => Some(error),
            _ => None,
        }
    }
}

impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Io(err)
    }
}

impl From<url::ParseError> for Error {
    fn from(err: url::ParseError) -> Error {
        Uri(err)
    }
}

impl From<SslError> for Error {
    fn from(err: SslError) -> Error {
        match err {
            SslError::StreamError(err) => Io(err),
            err => Ssl(err),
        }
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Error {
        match err {
            httparse::Error::HeaderName => Header,
            httparse::Error::HeaderValue => Header,
            httparse::Error::NewLine => Header,
            httparse::Error::Status => Status,
            httparse::Error::Token => Header,
            httparse::Error::TooManyHeaders => TooLarge,
            httparse::Error::Version => Version,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::error::Error as StdError;
    use std::io;
    use httparse;
    use openssl::ssl::error::SslError;
    use url;
    use super::Error;
    use super::Error::*;

    #[test]
    fn test_cause() {
        let orig = io::Error::new(io::ErrorKind::Other, "other");
        let desc = orig.description().to_owned();
        let e = Io(orig);
        assert_eq!(e.cause().unwrap().description(), desc);
    }

    macro_rules! from {
        ($from:expr => $error:pat) => {
            match Error::from($from) {
                $error => (),
                _ => panic!("{:?}", $from)
            }
        }
    }

    #[test]
    fn test_from() {

        from!(io::Error::new(io::ErrorKind::Other, "other") => Io(..));
        from!(url::ParseError::EmptyHost => Uri(..));

        from!(SslError::StreamError(io::Error::new(io::ErrorKind::Other, "ssl")) => Io(..));
        from!(SslError::SslSessionClosed => Ssl(..));

        from!(httparse::Error::HeaderName => Header);
        from!(httparse::Error::HeaderName => Header);
        from!(httparse::Error::HeaderValue => Header);
        from!(httparse::Error::NewLine => Header);
        from!(httparse::Error::Status => Status);
        from!(httparse::Error::Token => Header);
        from!(httparse::Error::TooManyHeaders => TooLarge);
        from!(httparse::Error::Version => Version);
    }
}
<|endoftext|>


<commit_before>use backtrace::Backtrace;
use hyper::status::StatusCode;
use rustc_serialize::base64::FromBase64Error;
use rustc_serialize::json::{DecoderError, Json, ParserError, ToJson};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::io::Error as IoError;

#[derive(PartialEq, Debug)]
pub enum ErrorStatus {
    ElementClickIntercepted,
    ElementNotInteractable,
    ElementNotSelectable,
    InsecureCertificate,
    InvalidArgument,
    InvalidCookieDomain,
    InvalidCoordinates,
    InvalidElementState,
    InvalidSelector,
    InvalidSessionId,
    JavascriptError,
    MoveTargetOutOfBounds,
    NoSuchAlert,
    NoSuchCookie,
    NoSuchElement,
    NoSuchFrame,
    NoSuchWindow,
    ScriptTimeout,
    SessionNotCreated,
    StaleElementReference,
    Timeout,
    UnableToCaptureScreen,
    UnableToSetCookie,
    UnexpectedAlertOpen,
    UnknownCommand,
    UnknownError,
    UnknownMethod,
    UnknownPath,
    UnsupportedOperation,
}

impl ErrorStatus {
    pub fn error_code(&self) -> &'static str {
        match *self {
            ErrorStatus::ElementClickIntercepted => "element click intercepted",
            ErrorStatus::ElementNotInteractable => "element not interactable",
            ErrorStatus::ElementNotSelectable => "element not selectable",
            ErrorStatus::InsecureCertificate => "insecure certificate",
            ErrorStatus::InvalidArgument => "invalid argument",
            ErrorStatus::InvalidCookieDomain => "invalid cookie domain",
            ErrorStatus::InvalidCoordinates => "invalid coordinates",
            ErrorStatus::InvalidElementState => "invalid element state",
            ErrorStatus::InvalidSelector => "invalid selector",
            ErrorStatus::InvalidSessionId => "invalid session id",
            ErrorStatus::JavascriptError => "javascript error",
            ErrorStatus::MoveTargetOutOfBounds => "move target out of bounds",
            ErrorStatus::NoSuchAlert => "no such alert",
            ErrorStatus::NoSuchCookie => "no such cookie",
            ErrorStatus::NoSuchElement => "no such element",
            ErrorStatus::NoSuchFrame => "no such frame",
            ErrorStatus::NoSuchWindow => "no such window",
            ErrorStatus::ScriptTimeout => "script timeout",
            ErrorStatus::SessionNotCreated => "session not created",
            ErrorStatus::StaleElementReference => "stale element reference",
            ErrorStatus::Timeout => "timeout",
            ErrorStatus::UnableToCaptureScreen => "unable to capture screen",
            ErrorStatus::UnableToSetCookie => "unable to set cookie",
            ErrorStatus::UnexpectedAlertOpen => "unexpected alert open",
            ErrorStatus::UnknownCommand |
            ErrorStatus::UnknownError => "unknown error",
            ErrorStatus::UnknownMethod => "unknown method",
            ErrorStatus::UnknownPath => "unknown command",
            ErrorStatus::UnsupportedOperation => "unsupported operation",
        }
    }

    pub fn http_status(&self) -> StatusCode {
        match *self {
            ErrorStatus::ElementClickIntercepted => StatusCode::BadRequest,
            ErrorStatus::ElementNotInteractable => StatusCode::BadRequest,
            ErrorStatus::ElementNotSelectable => StatusCode::BadRequest,
            ErrorStatus::InsecureCertificate => StatusCode::BadRequest,
            ErrorStatus::InvalidArgument => StatusCode::BadRequest,
            ErrorStatus::InvalidCookieDomain => StatusCode::BadRequest,
            ErrorStatus::InvalidCoordinates => StatusCode::BadRequest,
            ErrorStatus::InvalidElementState => StatusCode::BadRequest,
            ErrorStatus::InvalidSelector => StatusCode::BadRequest,
            ErrorStatus::InvalidSessionId => StatusCode::NotFound,
            ErrorStatus::JavascriptError => StatusCode::InternalServerError,
            ErrorStatus::MoveTargetOutOfBounds => StatusCode::InternalServerError,
            ErrorStatus::NoSuchAlert => StatusCode::BadRequest,
            ErrorStatus::NoSuchCookie => StatusCode::NotFound,
            ErrorStatus::NoSuchElement => StatusCode::NotFound,
            ErrorStatus::NoSuchFrame => StatusCode::BadRequest,
            ErrorStatus::NoSuchWindow => StatusCode::BadRequest,
            ErrorStatus::ScriptTimeout => StatusCode::RequestTimeout,
            ErrorStatus::SessionNotCreated => StatusCode::InternalServerError,
            ErrorStatus::StaleElementReference => StatusCode::BadRequest,
            ErrorStatus::Timeout => StatusCode::RequestTimeout,
            ErrorStatus::UnableToCaptureScreen => StatusCode::BadRequest,
            ErrorStatus::UnableToSetCookie => StatusCode::InternalServerError,
            ErrorStatus::UnexpectedAlertOpen => StatusCode::InternalServerError,
            ErrorStatus::UnknownCommand => StatusCode::NotFound,
            ErrorStatus::UnknownError => StatusCode::InternalServerError,
            ErrorStatus::UnknownMethod => StatusCode::MethodNotAllowed,
            ErrorStatus::UnknownPath => StatusCode::NotFound,
            ErrorStatus::UnsupportedOperation => StatusCode::InternalServerError,
        }
    }
}

pub type WebDriverResult<T> = Result<T, WebDriverError>;

#[derive(Debug)]
pub struct WebDriverError {
    pub error: ErrorStatus,
    pub message: Cow<'static, str>,
    pub backtrace: Backtrace,
    pub delete_session: bool,
}

impl fmt::Display for WebDriverError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.message.fmt(f)
    }
}

impl WebDriverError {
    pub fn new<S>(error: ErrorStatus, message: S) -> WebDriverError
        where S: Into<Cow<'static, str>>
    {
        WebDriverError {
            error: error,
            message: message.into(),
            backtrace: Backtrace::new(),
            delete_session: false,
        }
    }

    pub fn status_code(&self) -> &'static str {
        self.error.status_code()
    }

    pub fn http_status(&self) -> StatusCode {
        self.error.http_status()
    }

    pub fn to_json_string(&self) -> String {
        self.to_json().to_string()
    }
}

impl ToJson for WebDriverError {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        data.insert("error".into(), self.status_code().to_json());
        data.insert("message".into(), self.message.to_json());
        data.insert("stacktrace".into(),
                    format!("{:?}", self.backtrace).to_json());
        let mut wrapper = BTreeMap::new();
        wrapper.insert("value".into(), Json::Object(data));
        Json::Object(wrapper)
    }
}

impl Error for WebDriverError {
    fn description(&self) -> &str {
        self.status_code()
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl From<ParserError> for WebDriverError {
    fn from(err: ParserError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<IoError> for WebDriverError {
    fn from(err: IoError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<DecoderError> for WebDriverError {
    fn from(err: DecoderError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<FromBase64Error> for WebDriverError {
    fn from(err: FromBase64Error) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<Box<Error>> for WebDriverError {
    fn from(err: Box<Error>) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}
<commit_msg>error: rename WebDriverError.status_code to error_code<commit_after>use backtrace::Backtrace;
use hyper::status::StatusCode;
use rustc_serialize::base64::FromBase64Error;
use rustc_serialize::json::{DecoderError, Json, ParserError, ToJson};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::io::Error as IoError;

#[derive(PartialEq, Debug)]
pub enum ErrorStatus {
    ElementClickIntercepted,
    ElementNotInteractable,
    ElementNotSelectable,
    InsecureCertificate,
    InvalidArgument,
    InvalidCookieDomain,
    InvalidCoordinates,
    InvalidElementState,
    InvalidSelector,
    InvalidSessionId,
    JavascriptError,
    MoveTargetOutOfBounds,
    NoSuchAlert,
    NoSuchCookie,
    NoSuchElement,
    NoSuchFrame,
    NoSuchWindow,
    ScriptTimeout,
    SessionNotCreated,
    StaleElementReference,
    Timeout,
    UnableToCaptureScreen,
    UnableToSetCookie,
    UnexpectedAlertOpen,
    UnknownCommand,
    UnknownError,
    UnknownMethod,
    UnknownPath,
    UnsupportedOperation,
}

impl ErrorStatus {
    pub fn error_code(&self) -> &'static str {
        match *self {
            ErrorStatus::ElementClickIntercepted => "element click intercepted",
            ErrorStatus::ElementNotInteractable => "element not interactable",
            ErrorStatus::ElementNotSelectable => "element not selectable",
            ErrorStatus::InsecureCertificate => "insecure certificate",
            ErrorStatus::InvalidArgument => "invalid argument",
            ErrorStatus::InvalidCookieDomain => "invalid cookie domain",
            ErrorStatus::InvalidCoordinates => "invalid coordinates",
            ErrorStatus::InvalidElementState => "invalid element state",
            ErrorStatus::InvalidSelector => "invalid selector",
            ErrorStatus::InvalidSessionId => "invalid session id",
            ErrorStatus::JavascriptError => "javascript error",
            ErrorStatus::MoveTargetOutOfBounds => "move target out of bounds",
            ErrorStatus::NoSuchAlert => "no such alert",
            ErrorStatus::NoSuchCookie => "no such cookie",
            ErrorStatus::NoSuchElement => "no such element",
            ErrorStatus::NoSuchFrame => "no such frame",
            ErrorStatus::NoSuchWindow => "no such window",
            ErrorStatus::ScriptTimeout => "script timeout",
            ErrorStatus::SessionNotCreated => "session not created",
            ErrorStatus::StaleElementReference => "stale element reference",
            ErrorStatus::Timeout => "timeout",
            ErrorStatus::UnableToCaptureScreen => "unable to capture screen",
            ErrorStatus::UnableToSetCookie => "unable to set cookie",
            ErrorStatus::UnexpectedAlertOpen => "unexpected alert open",
            ErrorStatus::UnknownCommand |
            ErrorStatus::UnknownError => "unknown error",
            ErrorStatus::UnknownMethod => "unknown method",
            ErrorStatus::UnknownPath => "unknown command",
            ErrorStatus::UnsupportedOperation => "unsupported operation",
        }
    }

    pub fn http_status(&self) -> StatusCode {
        match *self {
            ErrorStatus::ElementClickIntercepted => StatusCode::BadRequest,
            ErrorStatus::ElementNotInteractable => StatusCode::BadRequest,
            ErrorStatus::ElementNotSelectable => StatusCode::BadRequest,
            ErrorStatus::InsecureCertificate => StatusCode::BadRequest,
            ErrorStatus::InvalidArgument => StatusCode::BadRequest,
            ErrorStatus::InvalidCookieDomain => StatusCode::BadRequest,
            ErrorStatus::InvalidCoordinates => StatusCode::BadRequest,
            ErrorStatus::InvalidElementState => StatusCode::BadRequest,
            ErrorStatus::InvalidSelector => StatusCode::BadRequest,
            ErrorStatus::InvalidSessionId => StatusCode::NotFound,
            ErrorStatus::JavascriptError => StatusCode::InternalServerError,
            ErrorStatus::MoveTargetOutOfBounds => StatusCode::InternalServerError,
            ErrorStatus::NoSuchAlert => StatusCode::BadRequest,
            ErrorStatus::NoSuchCookie => StatusCode::NotFound,
            ErrorStatus::NoSuchElement => StatusCode::NotFound,
            ErrorStatus::NoSuchFrame => StatusCode::BadRequest,
            ErrorStatus::NoSuchWindow => StatusCode::BadRequest,
            ErrorStatus::ScriptTimeout => StatusCode::RequestTimeout,
            ErrorStatus::SessionNotCreated => StatusCode::InternalServerError,
            ErrorStatus::StaleElementReference => StatusCode::BadRequest,
            ErrorStatus::Timeout => StatusCode::RequestTimeout,
            ErrorStatus::UnableToCaptureScreen => StatusCode::BadRequest,
            ErrorStatus::UnableToSetCookie => StatusCode::InternalServerError,
            ErrorStatus::UnexpectedAlertOpen => StatusCode::InternalServerError,
            ErrorStatus::UnknownCommand => StatusCode::NotFound,
            ErrorStatus::UnknownError => StatusCode::InternalServerError,
            ErrorStatus::UnknownMethod => StatusCode::MethodNotAllowed,
            ErrorStatus::UnknownPath => StatusCode::NotFound,
            ErrorStatus::UnsupportedOperation => StatusCode::InternalServerError,
        }
    }
}

pub type WebDriverResult<T> = Result<T, WebDriverError>;

#[derive(Debug)]
pub struct WebDriverError {
    pub error: ErrorStatus,
    pub message: Cow<'static, str>,
    pub backtrace: Backtrace,
    pub delete_session: bool,
}

impl fmt::Display for WebDriverError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.message.fmt(f)
    }
}

impl WebDriverError {
    pub fn new<S>(error: ErrorStatus, message: S) -> WebDriverError
        where S: Into<Cow<'static, str>>
    {
        WebDriverError {
            error: error,
            message: message.into(),
            backtrace: Backtrace::new(),
            delete_session: false,
        }
    }

    pub fn error_code(&self) -> &'static str {
        self.error.error_code()
    }

    pub fn http_status(&self) -> StatusCode {
        self.error.http_status()
    }

    pub fn to_json_string(&self) -> String {
        self.to_json().to_string()
    }
}

impl ToJson for WebDriverError {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        data.insert("error".into(), self.error_code().to_json());
        data.insert("message".into(), self.message.to_json());
        data.insert("stacktrace".into(),
                    format!("{:?}", self.backtrace).to_json());
        let mut wrapper = BTreeMap::new();
        wrapper.insert("value".into(), Json::Object(data));
        Json::Object(wrapper)
    }
}

impl Error for WebDriverError {
    fn description(&self) -> &str {
        self.error_code()
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl From<ParserError> for WebDriverError {
    fn from(err: ParserError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<IoError> for WebDriverError {
    fn from(err: IoError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<DecoderError> for WebDriverError {
    fn from(err: DecoderError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<FromBase64Error> for WebDriverError {
    fn from(err: FromBase64Error) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<Box<Error>> for WebDriverError {
    fn from(err: Box<Error>) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}
<|endoftext|>


<commit_before>//! Abstractions for the events passed back from i3.

use reply;
use serde::json;
use std::str::FromStr;
use common;

use event::inner::*;

/// An event passed back from i3.
pub enum Event {
    WorkspaceEvent(WorkspaceEventInfo),
    OutputEvent(OutputEventInfo),
    ModeEvent(ModeEventInfo),
    WindowEvent(WindowEventInfo),
    BarConfigEvent(BarConfigEventInfo),
    BindingEvent(BindingEventInfo),
}

/// Data for `WorkspaceEvent`.
pub struct WorkspaceEventInfo {
    /// The type of change.
    pub change: WorkspaceChange,
    /// Will be `Some` if the type of event affects the workspace.
    pub current: Option<reply::Node>,
    /// Will be `Some` only when `change == Focus` *and* there was a previous workspace.
    /// Note that if the previous workspace was empty it will get destroyed when switching, but
    /// will still appear here.
    pub old: Option<reply::Node>
}

impl FromStr for WorkspaceEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(WorkspaceEventInfo {
            change: match val.find("change").unwrap().as_string().unwrap().as_ref() {
                "focus" => WorkspaceChange::Focus,
                "init" => WorkspaceChange::Init,
                "empty" => WorkspaceChange::Empty,
                "urgent" => WorkspaceChange::Urgent,
                _ => unreachable!()
            },
            current: match val.find("current").unwrap().clone() {
                json::Value::Null => None,
                val => Some(common::build_tree(&val))
            },
            old: match val.find("old") {
                Some(o) => match o.clone() {
                    json::Value::Null => None,
                    val => Some(common::build_tree(&val))
                },
                None => None
            }
        })
    }
}

/// Data for `OutputEvent`.
pub struct OutputEventInfo {
    /// The type of change.
    pub change: OutputChange
}

impl FromStr for OutputEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(OutputEventInfo {
            change: match val.find("change").unwrap().as_string().unwrap().as_ref() {
                "unspecified" => OutputChange::Unspecified,
                _ => unreachable!()
            }
        })
    }
}

/// Data for `ModeEvent`.
pub struct ModeEventInfo {
    /// The name of current mode in use. It is the same as specified in config when creating a
    /// mode. The default mode is simply named default.
    pub change: String
}

impl FromStr for ModeEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(ModeEventInfo {
            change: val.find("change").unwrap().as_string().unwrap().to_owned()
        })
    }
}

/// Data for `WindowEvent`.
pub struct WindowEventInfo {
    /// Indicates the type of change
    pub change: WindowChange,
    /// The window's parent container. Be aware that for the "new" event, the container will hold
    /// the initial name of the newly reparented window (e.g. if you run urxvt with a shell that
    /// changes the title, you will still at this point get the window title as "urxvt").
    pub container: reply::Node
}

impl FromStr for WindowEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(WindowEventInfo {
            change: match val.find("change").unwrap().as_string().unwrap().as_ref() {
                "new" => WindowChange::New,
                "close" => WindowChange::Close,
                "focus" => WindowChange::Focus,
                "title" => WindowChange::Title,
                "fullscreen_mode" => WindowChange::FullscreenMode,
                "move" => WindowChange::Move,
                "floating" => WindowChange::Floating,
                "urgent" => WindowChange::Urgent,
                _ => unreachable!()
            },
            container: common::build_tree(val.find("container").unwrap())
        })
    }
}

/// Data for `BarConfigEvent`.
pub struct BarConfigEventInfo {
    /// The new i3 bar configuration.
    pub bar_config: reply::BarConfig
}

impl FromStr for BarConfigEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(BarConfigEventInfo {
            bar_config: common::build_bar_config(&val)
        })
    }
}

/// Data for `BindingEvent`.
///
/// Reports on the details of a binding that ran a command because of user input.
pub struct BindingEventInfo {
    /// Indicates what sort of binding event was triggered (right now it will always be "run" but
    /// that may be expanded in the future).
    pub change: BindingChange,
    pub binding: Binding
}

impl FromStr for BindingEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// Less important types
pub mod inner {
    /// The kind of workspace change.
    pub enum WorkspaceChange {
        Focus,
        Init,
        Empty,
        Urgent
    }

    /// The kind of output change.
    pub enum OutputChange {
        Unspecified
    }

    /// The kind of window change.
    pub enum WindowChange {
        /// The window has become managed by i3.
        New,
        /// The window has closed>.
        Close,
        /// The window has received input focus.
        Focus,
        /// The window's title has changed.
        Title,
        /// The window has entered or exited fullscreen mode.
        FullscreenMode,
        /// The window has changed its position in the tree.
        Move,
        /// The window has transitioned to or from floating.
        Floating,
        /// The window has become urgent or lost its urgent status.
        Urgent
    }

    /// Either keyboard or mouse.
    pub enum InputType {
        Keyboard,
        Mouse
    }

    /// Contains details about the binding that was run.
    pub struct Binding {
        /// The i3 command that is configured to run for this binding.
        pub command: String,

        /// The modifier keys that were configured with this binding.
        pub mods: Vec<String>,

        /// If the binding was configured with blindcode, this will be the key code that was given for
        /// the binding. If the binding is a mouse binding, it will be the number of times the mouse
        /// button was pressed. Otherwise it will be 0.
        pub input_code: i32,

        /// If this is a keyboard binding that was configured with bindsym, this field will contain the
        /// given symbol. Otherwise it will be None.
        pub symbol: Option<String>,

        /// Will be Keyboard or Mouse depending on whether this was a keyboard or mouse binding.
        pub input_type: InputType
    }

    /// The kind of binding change.
    pub enum BindingChange {
        Run
    }
}
<commit_msg>Implement BindingEventInfo::from_str<commit_after>//! Abstractions for the events passed back from i3.

use reply;
use serde::json;
use std::str::FromStr;
use common;

use event::inner::*;

/// An event passed back from i3.
pub enum Event {
    WorkspaceEvent(WorkspaceEventInfo),
    OutputEvent(OutputEventInfo),
    ModeEvent(ModeEventInfo),
    WindowEvent(WindowEventInfo),
    BarConfigEvent(BarConfigEventInfo),
    BindingEvent(BindingEventInfo),
}

/// Data for `WorkspaceEvent`.
pub struct WorkspaceEventInfo {
    /// The type of change.
    pub change: WorkspaceChange,
    /// Will be `Some` if the type of event affects the workspace.
    pub current: Option<reply::Node>,
    /// Will be `Some` only when `change == Focus` *and* there was a previous workspace.
    /// Note that if the previous workspace was empty it will get destroyed when switching, but
    /// will still appear here.
    pub old: Option<reply::Node>
}

impl FromStr for WorkspaceEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(WorkspaceEventInfo {
            change: match val.find("change").unwrap().as_string().unwrap().as_ref() {
                "focus" => WorkspaceChange::Focus,
                "init" => WorkspaceChange::Init,
                "empty" => WorkspaceChange::Empty,
                "urgent" => WorkspaceChange::Urgent,
                _ => unreachable!()
            },
            current: match val.find("current").unwrap().clone() {
                json::Value::Null => None,
                val => Some(common::build_tree(&val))
            },
            old: match val.find("old") {
                Some(o) => match o.clone() {
                    json::Value::Null => None,
                    val => Some(common::build_tree(&val))
                },
                None => None
            }
        })
    }
}

/// Data for `OutputEvent`.
pub struct OutputEventInfo {
    /// The type of change.
    pub change: OutputChange
}

impl FromStr for OutputEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(OutputEventInfo {
            change: match val.find("change").unwrap().as_string().unwrap().as_ref() {
                "unspecified" => OutputChange::Unspecified,
                _ => unreachable!()
            }
        })
    }
}

/// Data for `ModeEvent`.
pub struct ModeEventInfo {
    /// The name of current mode in use. It is the same as specified in config when creating a
    /// mode. The default mode is simply named default.
    pub change: String
}

impl FromStr for ModeEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(ModeEventInfo {
            change: val.find("change").unwrap().as_string().unwrap().to_owned()
        })
    }
}

/// Data for `WindowEvent`.
pub struct WindowEventInfo {
    /// Indicates the type of change
    pub change: WindowChange,
    /// The window's parent container. Be aware that for the "new" event, the container will hold
    /// the initial name of the newly reparented window (e.g. if you run urxvt with a shell that
    /// changes the title, you will still at this point get the window title as "urxvt").
    pub container: reply::Node
}

impl FromStr for WindowEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(WindowEventInfo {
            change: match val.find("change").unwrap().as_string().unwrap().as_ref() {
                "new" => WindowChange::New,
                "close" => WindowChange::Close,
                "focus" => WindowChange::Focus,
                "title" => WindowChange::Title,
                "fullscreen_mode" => WindowChange::FullscreenMode,
                "move" => WindowChange::Move,
                "floating" => WindowChange::Floating,
                "urgent" => WindowChange::Urgent,
                _ => unreachable!()
            },
            container: common::build_tree(val.find("container").unwrap())
        })
    }
}

/// Data for `BarConfigEvent`.
pub struct BarConfigEventInfo {
    /// The new i3 bar configuration.
    pub bar_config: reply::BarConfig
}

impl FromStr for BarConfigEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        Ok(BarConfigEventInfo {
            bar_config: common::build_bar_config(&val)
        })
    }
}

/// Data for `BindingEvent`.
///
/// Reports on the details of a binding that ran a command because of user input.
pub struct BindingEventInfo {
    /// Indicates what sort of binding event was triggered (right now it will always be "run" but
    /// that may be expanded in the future).
    pub change: BindingChange,
    pub binding: Binding
}

impl FromStr for BindingEventInfo {
    type Err = json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val: json::Value = try!(json::from_str(s));
        let bind = val.find("binding").unwrap();
        Ok(BindingEventInfo {
            change: match val.find("change").unwrap().as_string().unwrap().as_ref() {
                "run" => BindingChange::Run,
                _ => unreachable!()
            },
            binding: Binding {
                command: bind.find("command").unwrap().as_string().unwrap().to_owned(),
                mods: bind.find("mods").unwrap()
                         .as_array().unwrap().iter()
                         .map(|m| m.as_string().unwrap().to_owned())
                         .collect(),
                input_code: bind.find("input_code").unwrap().as_i64().unwrap() as i32,
                symbol: match bind.find("symbol").unwrap().clone() {
                    json::Value::String(s) => Some(s),
                    json::Value::Null => None,
                    _ => unreachable!()
                },
                input_type: match bind.find("input_type").unwrap().as_string().unwrap().as_ref() {
                    "keyboard" => InputType::Keyboard,
                    "mouse" => InputType::Mouse,
                    _ => unreachable!()
                }
            }
        })
    }
}

/// Less important types
pub mod inner {
    /// The kind of workspace change.
    pub enum WorkspaceChange {
        Focus,
        Init,
        Empty,
        Urgent
    }

    /// The kind of output change.
    pub enum OutputChange {
        Unspecified
    }

    /// The kind of window change.
    pub enum WindowChange {
        /// The window has become managed by i3.
        New,
        /// The window has closed>.
        Close,
        /// The window has received input focus.
        Focus,
        /// The window's title has changed.
        Title,
        /// The window has entered or exited fullscreen mode.
        FullscreenMode,
        /// The window has changed its position in the tree.
        Move,
        /// The window has transitioned to or from floating.
        Floating,
        /// The window has become urgent or lost its urgent status.
        Urgent
    }

    /// Either keyboard or mouse.
    pub enum InputType {
        Keyboard,
        Mouse
    }

    /// Contains details about the binding that was run.
    pub struct Binding {
        /// The i3 command that is configured to run for this binding.
        pub command: String,

        /// The modifier keys that were configured with this binding.
        pub mods: Vec<String>,

        /// If the binding was configured with blindcode, this will be the key code that was given for
        /// the binding. If the binding is a mouse binding, it will be the number of times the mouse
        /// button was pressed. Otherwise it will be 0.
        pub input_code: i32,

        /// If this is a keyboard binding that was configured with bindsym, this field will contain the
        /// given symbol. Otherwise it will be None.
        pub symbol: Option<String>,

        /// Will be Keyboard or Mouse depending on whether this was a keyboard or mouse binding.
        pub input_type: InputType
    }

    /// The kind of binding change.
    pub enum BindingChange {
        Run
    }
}
<|endoftext|>


<commit_before>use ::{Guard, Nav};
use ::traversal::Queue;
use ::util::{ChildIndex, SiblingIndex};

use std::clone::Clone;
use std::iter::Iterator;

/// Fixed-layout tree with good memory locality guarantees.
///
/// This tree structure does not provide methods for arbitrarily modifying its
/// topology, but it does provide good memory locality guarantees. Internally,
/// tree data is kept in a single heap-allocated region. Records of tree edges
/// are also kept in contiguous regions of memory, so tree navigation should be
/// fast.
///
/// If the tree is extended with additional children, it may reallocate its
/// entire structure.
pub struct Tree<T> {
    data: Vec<T>, offsets: Vec<usize>, children: Vec<usize>,
}

impl<T> Tree<T> {
    /// Constructs a tree based on the ordering imposed by a traversal.
    ///
    /// In the resulting tree, nodes will be laid out in memory in the same
    /// order in which they are visited by the traversal imposed by `queue`.
    pub fn from_traversal<Q, I>(mut queue: Q, data: T, children: I) -> Self
        where Q: Queue<(usize, usize, T, I)>, I: Iterator<Item=(T, I)> {
            let mut tree = Tree { data: Vec::new(), offsets: Vec::new(), children: Vec::new(), };
            tree.data.push(data);
            tree.offsets.push(0);
            {
                let mut child_index = 0usize;
                for (data, children) in children {
                    queue.unshift((0, child_index, data, children));
                    child_index += 1;
                    tree.children.push(0);
                }
            }
            loop {
                match queue.shift() {
                    None => return tree,
                    Some((parent_index, index, data, children)) => {
                        tree.data.push(data);
                        tree.offsets.push(tree.children.len());
                        tree.children[tree.offsets[parent_index] + index] = index;
                        let mut child_index = 0usize;
                        for (data, children) in children {
                            queue.unshift((index, child_index, data, children));
                            child_index += 1;
                            tree.children.push(0);
                        }
                    }
                }
            }
        }

    /// Constructs a new tree with no children and the given data.
    pub fn leaf(data: T) -> Self {
        Tree { data: vec![data], offsets: vec![0], children: Vec::new(), }
    }

    /// Returns the number of nodes in this tree.
    pub fn size(&self) -> usize {
        self.data.len()
    }

    /// Returns a borrowed view of the nodes, in the order in which they are
    /// stored.
    pub fn nodes(&self) -> &[T] {
        &self.data
    }

    /// Returns a borrowed mutable view of the nodes, in the order in which they
    /// are stored.
    pub fn nodes_mut(&mut self) -> &mut [T] {
        &mut self.data
    }

    fn child_count(&self, index: usize) -> usize {
        match index.checked_add(1) {
            None =>
                panic!["numerical overflow in computing child count"],
            Some(x) if x > self.size() =>
                panic!["no such child {} (only {} nodes in tree)", index, self.size()],
            Some(x) if x == self.size() =>
                self.size() - self.offsets[index],
            Some(x) =>
                self.offsets[x] - self.offsets[index],
        }
    }

    fn child_of(&self, parent: usize, index: usize) -> usize {
        assert![parent < self.size()];
        match self.offsets[parent].checked_add(index) {
            Some(x) => self.children[x],
            None => panic!["numerical overflow in computing child offset"],
        }
    }
}

pub struct DataGuard<'a, T: 'a> {
    tree: &'a Tree<T>, index: usize,
}

impl<'a, T: 'a> Guard<'a, T> for DataGuard<'a, T> {
    fn super_deref<'s>(&'s self) -> &'a T {
        &self.tree.data[self.index]
    }
}

pub struct Navigator<'a, T: 'a> {
    tree: &'a Tree<T>, path: Vec<usize>,
}

impl<'a, T: 'a> Navigator<'a, T> {
    fn index(&self) -> usize {
        self.path[self.path.len() - 1]
    }
}

impl<'a, T: 'a> Clone for Navigator<'a, T> {
    fn clone(&self) -> Self {
        Navigator { tree: self.tree, path: self.path.clone(), }
    }
}

impl<'a, T: 'a> Nav<'a> for Navigator<'a, T> {
    type Data = T;
    type DataGuard = DataGuard<'a, T>;

    fn seek_sibling(&mut self, offset: isize) {
        let new_index =
            if self.path.len() < 1 {
                SiblingIndex::Root
            } else {
                let parent = self.path[self.path.len() - 1];
                SiblingIndex::compute(self.tree.child_count(parent),
                                      parent,
                                      offset)
            }.unwrap();
        let offset_index = match self.path.pop() {
            Some(parent) =>
                self.tree.child_of(parent, new_index),
            None =>
                panic!["tree corruption"],
        };
        self.path.push(offset_index);
    }

    fn seek_child(&mut self, index: usize) {
        let new_index =
            ChildIndex::compute(self.child_count(), index).unwrap();
        let offset = self.tree.offsets[self.index()];
        let child = self.tree.children[offset + new_index];
        self.path.push(child);
    }

    fn child_count(&self) -> usize {
        self.tree.child_count(self.index())
    }

    fn at_root(&self) -> bool {
        self.path.len() == 1
    }

    fn to_parent(&mut self) {
        assert![self.path.len() <= 1, "Already at root"];
        self.path.pop();
    }

    fn to_root(&mut self) {
        self.path.clear();
        self.path.push(0);
    }

    fn data(&self) -> DataGuard<'a, T> {
        DataGuard { tree: self.tree, index: self.index(), }
    }
}
<commit_msg>Clarification in docstring.<commit_after>use ::{Guard, Nav};
use ::traversal::Queue;
use ::util::{ChildIndex, SiblingIndex};

use std::clone::Clone;
use std::iter::Iterator;

/// Fixed-layout tree with good memory locality guarantees.
///
/// This tree structure does not provide methods for arbitrarily modifying its
/// topology, but it does provide good memory locality guarantees. Internally,
/// tree data is kept in a single heap-allocated region. Records of tree edges
/// are also kept in contiguous regions of memory, so tree navigation should be
/// fast.
///
/// If the tree is extended with additional children, it may reallocate its
/// entire structure.
pub struct Tree<T> {
    data: Vec<T>, offsets: Vec<usize>, children: Vec<usize>,
}

impl<T> Tree<T> {
    /// Constructs a tree based on the ordering imposed by a traversal.
    ///
    /// In the resulting tree, node data will be laid out in memory in the same
    /// order in which they are visited by the traversal imposed by `queue`.
    pub fn from_traversal<Q, I>(mut queue: Q, data: T, children: I) -> Self
        where Q: Queue<(usize, usize, T, I)>, I: Iterator<Item=(T, I)> {
            let mut tree = Tree { data: Vec::new(), offsets: Vec::new(), children: Vec::new(), };
            tree.data.push(data);
            tree.offsets.push(0);
            {
                let mut child_index = 0usize;
                for (data, children) in children {
                    queue.unshift((0, child_index, data, children));
                    child_index += 1;
                    tree.children.push(0);
                }
            }
            loop {
                match queue.shift() {
                    None => return tree,
                    Some((parent_index, index, data, children)) => {
                        tree.data.push(data);
                        tree.offsets.push(tree.children.len());
                        tree.children[tree.offsets[parent_index] + index] = index;
                        let mut child_index = 0usize;
                        for (data, children) in children {
                            queue.unshift((index, child_index, data, children));
                            child_index += 1;
                            tree.children.push(0);
                        }
                    }
                }
            }
        }

    /// Constructs a new tree with no children and the given data.
    pub fn leaf(data: T) -> Self {
        Tree { data: vec![data], offsets: vec![0], children: Vec::new(), }
    }

    /// Returns the number of nodes in this tree.
    pub fn size(&self) -> usize {
        self.data.len()
    }

    /// Returns a borrowed view of the nodes, in the order in which they are
    /// stored.
    pub fn nodes(&self) -> &[T] {
        &self.data
    }

    /// Returns a borrowed mutable view of the nodes, in the order in which they
    /// are stored.
    pub fn nodes_mut(&mut self) -> &mut [T] {
        &mut self.data
    }

    fn child_count(&self, index: usize) -> usize {
        match index.checked_add(1) {
            None =>
                panic!["numerical overflow in computing child count"],
            Some(x) if x > self.size() =>
                panic!["no such child {} (only {} nodes in tree)", index, self.size()],
            Some(x) if x == self.size() =>
                self.size() - self.offsets[index],
            Some(x) =>
                self.offsets[x] - self.offsets[index],
        }
    }

    fn child_of(&self, parent: usize, index: usize) -> usize {
        assert![parent < self.size()];
        match self.offsets[parent].checked_add(index) {
            Some(x) => self.children[x],
            None => panic!["numerical overflow in computing child offset"],
        }
    }
}

pub struct DataGuard<'a, T: 'a> {
    tree: &'a Tree<T>, index: usize,
}

impl<'a, T: 'a> Guard<'a, T> for DataGuard<'a, T> {
    fn super_deref<'s>(&'s self) -> &'a T {
        &self.tree.data[self.index]
    }
}

pub struct Navigator<'a, T: 'a> {
    tree: &'a Tree<T>, path: Vec<usize>,
}

impl<'a, T: 'a> Navigator<'a, T> {
    fn index(&self) -> usize {
        self.path[self.path.len() - 1]
    }
}

impl<'a, T: 'a> Clone for Navigator<'a, T> {
    fn clone(&self) -> Self {
        Navigator { tree: self.tree, path: self.path.clone(), }
    }
}

impl<'a, T: 'a> Nav<'a> for Navigator<'a, T> {
    type Data = T;
    type DataGuard = DataGuard<'a, T>;

    fn seek_sibling(&mut self, offset: isize) {
        let new_index =
            if self.path.len() < 1 {
                SiblingIndex::Root
            } else {
                let parent = self.path[self.path.len() - 1];
                SiblingIndex::compute(self.tree.child_count(parent),
                                      parent,
                                      offset)
            }.unwrap();
        let offset_index = match self.path.pop() {
            Some(parent) =>
                self.tree.child_of(parent, new_index),
            None =>
                panic!["tree corruption"],
        };
        self.path.push(offset_index);
    }

    fn seek_child(&mut self, index: usize) {
        let new_index =
            ChildIndex::compute(self.child_count(), index).unwrap();
        let offset = self.tree.offsets[self.index()];
        let child = self.tree.children[offset + new_index];
        self.path.push(child);
    }

    fn child_count(&self) -> usize {
        self.tree.child_count(self.index())
    }

    fn at_root(&self) -> bool {
        self.path.len() == 1
    }

    fn to_parent(&mut self) {
        assert![self.path.len() <= 1, "Already at root"];
        self.path.pop();
    }

    fn to_root(&mut self) {
        self.path.clear();
        self.path.push(0);
    }

    fn data(&self) -> DataGuard<'a, T> {
        DataGuard { tree: self.tree, index: self.index(), }
    }
}
<|endoftext|>


<commit_before>//! Glyph caching

extern crate rusttype as rt;

use std::io;
use std::path::{Path};
use std::collections::hash_map::{ HashMap, Entry };
use graphics::character::{ CharacterCache, Character };
use graphics::types::{FontSize, Scalar};
use { gfx, Texture, TextureSettings };
use gfx::core::factory::CombinedError;

/// An enum to represent various possible run-time errors that may occur.
#[derive(Debug)]
pub enum Error {
    /// An error happened when creating a gfx texture.
    Texture(CombinedError),
    /// An io error happened when reading font files.
    IoError(io::Error),
}

impl From<CombinedError> for Error {
    fn from(tex_err: CombinedError) -> Self {
        Error::Texture(tex_err)
    }
}

impl From<io::Error> for Error {
    fn from(io_error: io::Error) -> Self {
        Error::IoError(io_error)
    }
}

/// A struct used for caching a rendered font.
pub struct GlyphCache<R, F> where R: gfx::Resources {
    /// The font.
    pub font: rt::Font<'static>,
    factory: F,
    // Maps from fontsize and character to offset, size and texture.
    data: HashMap<(FontSize, char), ([Scalar; 2], [Scalar; 2], Texture<R>)>
}

impl<R, F> GlyphCache<R, F> where R: gfx::Resources {
     /// Constructor for a GlyphCache.
    pub fn new<P>(font_path: P, factory: F) -> Result<Self, Error>
        where P: AsRef<Path>    {

        use std::io::Read;
        use std::fs::File;

        let mut file = try!(File::open(font_path));
        let mut file_buffer = Vec::new();
        try!(file.read_to_end(&mut file_buffer));

        let collection = rt::FontCollection::from_bytes(file_buffer);
        let font = collection.into_font().unwrap(); // only succeeds if collection consists of one font

        Ok(GlyphCache {
            font: font,
            factory: factory,
            data: HashMap::new(),
        })
    }
}

impl<R, F> CharacterCache for GlyphCache<R, F> where
    R: gfx::Resources,
    F: gfx::Factory<R>,
{
    type Texture = Texture<R>;

    fn character<'a>(
        &'a mut self,
        size: FontSize,
        ch: char
    ) -> Character<'a, Self::Texture> {
        match self.data.entry((size, ch)) {
            //returning `into_mut()' to get reference with 'a lifetime
            Entry::Occupied(v) => {
                let &mut (offset, size, ref texture) = v.into_mut();
                Character {
                    offset: offset,
                    size: size,
                    texture: texture
                }
            }
            Entry::Vacant(v) => {
                let glyph = self.font.glyph(ch).unwrap();
                let glyph = glyph.scaled(rt::Scale::uniform(size as f32));
                let h_metrics = glyph.h_metrics();
                let bounding_box = glyph.exact_bounding_box().unwrap_or(rt::Rect{min: rt::Point{x: 0.0, y: 0.0}, max: rt::Point{x: 0.0, y: 0.0} });
                let glyph = glyph.positioned(rt::point(0.0, 0.0));
                let pixel_bounding_box = glyph.pixel_bounding_box().unwrap_or(rt::Rect{min: rt::Point{x: 0, y: 0}, max: rt::Point{x: 0, y: 0} });
                let pixel_bb_width = pixel_bounding_box.width();
                let pixel_bb_height = pixel_bounding_box.height();

                let mut image_buffer = Vec::<u8>::new();
                image_buffer.resize((pixel_bb_width * pixel_bb_height) as usize, 0);
                glyph.draw(|x, y, v| {
                   let pos = (x + y * (pixel_bb_width as u32)) as usize;
                   image_buffer[pos] = (255.0 * v) as u8;
                });

                let &mut (offset, size, ref texture) = v.insert((
                    [
                        bounding_box.min.x as Scalar,
                        -pixel_bounding_box.min.y as Scalar,
                    ],
                    [
                        h_metrics.advance_width as Scalar,
                        0 as Scalar,
                    ],
                    {
                        if pixel_bb_width == 0 || pixel_bb_height == 0 {
                            Texture::empty(&mut self.factory)
                                    .unwrap()
                        } else {
                            Texture::from_memory_alpha(
                                &mut self.factory,
                                &image_buffer,
                                pixel_bb_width as u32,
                                pixel_bb_height as u32,
                                &TextureSettings::new()
                            ).unwrap()
                        }
                    },
                ));
                Character {
                    offset: offset,
                    size: size,
                    texture: texture
                }
            }
        }
    }
}
<commit_msg>Adapt font size to freetype<commit_after>//! Glyph caching

extern crate rusttype as rt;

use std::io;
use std::path::{Path};
use std::collections::hash_map::{ HashMap, Entry };
use graphics::character::{ CharacterCache, Character };
use graphics::types::{FontSize, Scalar};
use { gfx, Texture, TextureSettings };
use gfx::core::factory::CombinedError;

/// An enum to represent various possible run-time errors that may occur.
#[derive(Debug)]
pub enum Error {
    /// An error happened when creating a gfx texture.
    Texture(CombinedError),
    /// An io error happened when reading font files.
    IoError(io::Error),
}

impl From<CombinedError> for Error {
    fn from(tex_err: CombinedError) -> Self {
        Error::Texture(tex_err)
    }
}

impl From<io::Error> for Error {
    fn from(io_error: io::Error) -> Self {
        Error::IoError(io_error)
    }
}

/// A struct used for caching a rendered font.
pub struct GlyphCache<R, F> where R: gfx::Resources {
    /// The font.
    pub font: rt::Font<'static>,
    factory: F,
    // Maps from fontsize and character to offset, size and texture.
    data: HashMap<(FontSize, char), ([Scalar; 2], [Scalar; 2], Texture<R>)>
}

impl<R, F> GlyphCache<R, F> where R: gfx::Resources {
     /// Constructor for a GlyphCache.
    pub fn new<P>(font_path: P, factory: F) -> Result<Self, Error>
        where P: AsRef<Path>    {

        use std::io::Read;
        use std::fs::File;

        let mut file = try!(File::open(font_path));
        let mut file_buffer = Vec::new();
        try!(file.read_to_end(&mut file_buffer));

        let collection = rt::FontCollection::from_bytes(file_buffer);
        let font = collection.into_font().unwrap(); // only succeeds if collection consists of one font

        Ok(GlyphCache {
            font: font,
            factory: factory,
            data: HashMap::new(),
        })
    }
}

impl<R, F> CharacterCache for GlyphCache<R, F> where
    R: gfx::Resources,
    F: gfx::Factory<R>,
{
    type Texture = Texture<R>;

    fn character<'a>(
        &'a mut self,
        size: FontSize,
        ch: char
    ) -> Character<'a, Self::Texture> {
        let size = ((size as f32) * 1.333).round() as u32 ; // convert points to pixels

        match self.data.entry((size, ch)) {
            //returning `into_mut()' to get reference with 'a lifetime
            Entry::Occupied(v) => {
                let &mut (offset, size, ref texture) = v.into_mut();
                Character {
                    offset: offset,
                    size: size,
                    texture: texture
                }
            }
            Entry::Vacant(v) => {
                let glyph = self.font.glyph(ch).unwrap();
                let glyph = glyph.scaled(rt::Scale::uniform(size as f32));
                let h_metrics = glyph.h_metrics();
                let bounding_box = glyph.exact_bounding_box().unwrap_or(rt::Rect{min: rt::Point{x: 0.0, y: 0.0}, max: rt::Point{x: 0.0, y: 0.0} });
                let glyph = glyph.positioned(rt::point(0.0, 0.0));
                let pixel_bounding_box = glyph.pixel_bounding_box().unwrap_or(rt::Rect{min: rt::Point{x: 0, y: 0}, max: rt::Point{x: 0, y: 0} });
                let pixel_bb_width = pixel_bounding_box.width();
                let pixel_bb_height = pixel_bounding_box.height();

                let mut image_buffer = Vec::<u8>::new();
                image_buffer.resize((pixel_bb_width * pixel_bb_height) as usize, 0);
                glyph.draw(|x, y, v| {
                   let pos = (x + y * (pixel_bb_width as u32)) as usize;
                   image_buffer[pos] = (255.0 * v) as u8;
                });

                let &mut (offset, size, ref texture) = v.insert((
                    [
                        bounding_box.min.x as Scalar,
                        -pixel_bounding_box.min.y as Scalar,
                    ],
                    [
                        h_metrics.advance_width as Scalar,
                        0 as Scalar,
                    ],
                    {
                        if pixel_bb_width == 0 || pixel_bb_height == 0 {
                            Texture::empty(&mut self.factory)
                                    .unwrap()
                        } else {
                            Texture::from_memory_alpha(
                                &mut self.factory,
                                &image_buffer,
                                pixel_bb_width as u32,
                                pixel_bb_height as u32,
                                &TextureSettings::new()
                            ).unwrap()
                        }
                    },
                ));
                Character {
                    offset: offset,
                    size: size,
                    texture: texture
                }
            }
        }
    }
}
<|endoftext|>