<commit_before>use std::cmp::max;

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

pub fn main() -> Vec<String> {
    let boss = Character::boss(DATA);
    vec![least_expensive_win(&boss).unwrap().to_string(),
         most_expensive_loss(&boss).unwrap().to_string()]
}

#[derive(Debug, PartialEq)]
struct Item<'a> {
    name: &'a str,
    cost: usize,
    damage: isize,
    armor: isize,
}

macro_rules! item {
    ($n:expr, $c:expr, $d:expr, $a:expr) =>
        (Item { name: $n, cost: $c, damage: $d, armor: $a })
}

static WEAPONS: [Item<'static>; 5] = [item!("Dagger", 8, 4, 0),
                                      item!("Shortsword", 10, 5, 0),
                                      item!("Warhammer", 25, 6, 0),
                                      item!("Longsword", 40, 7, 0),
                                      item!("Greataxe", 74, 8, 0)];

static ARMOR: [Item<'static>; 6] = [item!("NONE", 0, 0, 0),
                                    item!("Leather", 13, 0, 1),
                                    item!("Chainmail", 31, 0, 2),
                                    item!("Splintmail", 53, 0, 3),
                                    item!("Bandedmail", 75, 0, 4),
                                    item!("Platemail", 102, 0, 5)];

static RINGS: [Item<'static>; 8] = [item!("NONE 1", 0, 0, 0),
                                    item!("NONE 2", 0, 0, 0),
                                    item!("Damage +1", 25, 1, 0),
                                    item!("Damage +2", 50, 2, 0),
                                    item!("Damage +3", 100, 3, 0),
                                    item!("Defense +1", 20, 0, 1),
                                    item!("Defense +2", 40, 0, 2),
                                    item!("Defense +3", 80, 0, 3)];

struct Character {
    hp: isize,
    damage: isize,
    armor: isize,
}

impl Character {
    fn new() -> Character {
        Character {
            hp: 100,
            damage: 0,
            armor: 0,
        }
    }

    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();
        let armor = scan_fmt!(lines.next().unwrap(), "Armor: {}", isize).unwrap();

        Character {
            hp: hp,
            damage: damage,
            armor: armor,
        }
    }

    fn reset(&mut self) {
        self.damage = 0;
        self.armor = 0;
    }

    fn equip(&mut self, items: &[&Item]) {
        self.reset();
        for item in items {
            self.damage += item.damage;
            self.armor += item.armor;
        }
    }

    fn attack(&self, boss: &Character) -> bool {
        let damage = max(1, self.damage - boss.armor);
        let boss_damage = max(1, boss.damage - self.armor);
        let mut hp = self.hp;
        let mut boss_hp = boss.hp;
        loop {
            boss_hp -= damage;
            if boss_hp < 1 {
                return true;
            }
            hp -= boss_damage;
            if hp < 1 {
                return false;
            }
        }
    }
}

fn equipment_builds() -> Box<Iterator<Item = [&'static Item<'static>; 4]>> {
    box RINGS.iter()
             .flat_map(move |r1| {
                 RINGS.iter()
                      .filter(move |&r2| r2 != r1)
                      .flat_map(move |r2| {
                          WEAPONS.iter()
                                 .flat_map(move |w| {
                                     ARMOR.iter()
                                          .map(move |a| [w, a, r1, r2])
                                 })
                      })
             })
}

fn least_expensive_win(boss: &Character) -> Option<usize> {
    let mut hero = Character::new();

    equipment_builds()
        .filter(|e| {
            hero.equip(e);
            hero.attack(&boss)
        })
        .map(|e| e.iter().fold(0, |cost, &i| cost + i.cost))
        .min()
}

fn most_expensive_loss(boss: &Character) -> Option<usize> {
    let mut hero = Character::new();

    equipment_builds()
        .filter(|e| {
            hero.equip(e);
            !hero.attack(&boss)
        })
        .map(|e| e.iter().fold(0, |cost, &i| cost + i.cost))
        .max()
}
<commit_msg>day 21: move placeholder items out of item lists<commit_after>use std::iter;
use std::cmp::max;

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

pub fn main() -> Vec<String> {
    let boss = Character::boss(DATA);
    vec![least_expensive_win(&boss).unwrap().to_string(),
         most_expensive_loss(&boss).unwrap().to_string()]
}

#[derive(Debug, PartialEq)]
struct Item<'a> {
    name: &'a str,
    cost: usize,
    damage: isize,
    armor: isize,
}

macro_rules! item {
    ($n:expr, $c:expr, $d:expr, $a:expr) =>
        (Item { name: $n, cost: $c, damage: $d, armor: $a })
}

static WEAPONS: [Item<'static>; 5] = [item!("Dagger", 8, 4, 0),
                                      item!("Shortsword", 10, 5, 0),
                                      item!("Warhammer", 25, 6, 0),
                                      item!("Longsword", 40, 7, 0),
                                      item!("Greataxe", 74, 8, 0)];

static ARMOR: [Item<'static>; 5] = [item!("Leather", 13, 0, 1),
                                    item!("Chainmail", 31, 0, 2),
                                    item!("Splintmail", 53, 0, 3),
                                    item!("Bandedmail", 75, 0, 4),
                                    item!("Platemail", 102, 0, 5)];

static RINGS: [Item<'static>; 6] = [item!("Damage +1", 25, 1, 0),
                                    item!("Damage +2", 50, 2, 0),
                                    item!("Damage +3", 100, 3, 0),
                                    item!("Defense +1", 20, 0, 1),
                                    item!("Defense +2", 40, 0, 2),
                                    item!("Defense +3", 80, 0, 3)];

struct Character {
    hp: isize,
    damage: isize,
    armor: isize,
}

impl Character {
    fn new() -> Character {
        Character {
            hp: 100,
            damage: 0,
            armor: 0,
        }
    }

    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();
        let armor = scan_fmt!(lines.next().unwrap(), "Armor: {}", isize).unwrap();

        Character {
            hp: hp,
            damage: damage,
            armor: armor,
        }
    }

    fn reset(&mut self) {
        self.damage = 0;
        self.armor = 0;
    }

    fn equip(&mut self, items: &[&Item]) {
        self.reset();
        for item in items {
            self.damage += item.damage;
            self.armor += item.armor;
        }
    }

    fn attack(&self, boss: &Character) -> bool {
        let damage = max(1, self.damage - boss.armor);
        let boss_damage = max(1, boss.damage - self.armor);
        let mut hp = self.hp;
        let mut boss_hp = boss.hp;
        loop {
            boss_hp -= damage;
            if boss_hp < 1 {
                return true;
            }
            hp -= boss_damage;
            if hp < 1 {
                return false;
            }
        }
    }
}

// added to item lists when item use is optional (not weapons)
static NONE: Item<'static> = item!("NONE", 0, 0, 0);

fn equipment_builds() -> Box<Iterator<Item = [&'static Item<'static>; 4]>> {
    box RINGS.iter()
             .chain(iter::once(&NONE))
             .flat_map(move |r1| {
                 RINGS.iter()
                      .chain(iter::once(&NONE))
                      .filter(move |&r2| r2 != r1 || r2 == &NONE)
                      .flat_map(move |r2| {
                          WEAPONS.iter()
                                 .flat_map(move |w| {
                                     ARMOR.iter()
                                          .chain(iter::once(&NONE))
                                          .map(move |a| [w, a, r1, r2])
                                 })
                      })
             })
}

fn least_expensive_win(boss: &Character) -> Option<usize> {
    let mut hero = Character::new();

    equipment_builds()
        .filter(|e| {
            hero.equip(e);
            hero.attack(&boss)
        })
        .map(|e| e.iter().fold(0, |cost, &i| cost + i.cost))
        .min()
}

fn most_expensive_loss(boss: &Character) -> Option<usize> {
    let mut hero = Character::new();

    equipment_builds()
        .filter(|e| {
            hero.equip(e);
            !hero.attack(&boss)
        })
        .map(|e| e.iter().fold(0, |cost, &i| cost + i.cost))
        .max()
}
<|endoftext|>


<commit_before>//! Delays
//!
//! # Implementation details
//!
//! This module uses the TIM7 peripheral and the `_tim7` interrupt under the
//! hood.

use peripheral;

/// Blocks for `n` ms
pub fn ms(n: u16) {
    unsafe {
        let tim7 = peripheral::tim7_mut();

        // The alarm (the "update event") will set off in `n` "ticks".
        // One tick = 1 ms (see `init`)
        tim7.arr.write(|w| w.arr(n));

        // Generate an update event to update the autoreload register
        tim7.egr.write(|w| w.ug(true));

        // Clear any previous "update" event by clearing the update event flag
        tim7.sr.write(|w| w);

        // CEN: Enable the counter
        tim7.cr1.modify(|_, w| w.cen(true));

        // Wait until the alarm goes off (the "update event" occurs)
        while !tim7.sr.read().uif() {}

        // Clear the "update" flag
        tim7.sr.write(|w| w);
    }
}

/// Initializes the necessary stuff to be able to use delays
///
/// # Safety
///
/// - Must be called once
/// - Must be called in an interrupt-free environment
pub unsafe fn init() {
    let rcc = peripheral::rcc_mut();
    let tim7 = peripheral::tim7_mut();

    // RCC: Enable TIM7
    rcc.apb1enr.modify(|_, w| w.tim7en(true));

    // CEN: Disable the clock
    // OPM. Enable One Pulse Mode. Stop the counter after the next update event.
    tim7.cr1.write(|w| w.cen(false).opm(true));

    // Set pre-scaler to 8_000 -> Frequency = 1 KHz
    tim7.psc.write(|w| w.psc(7_999));
}
<commit_msg>fix delay in release (+LTO) mode<commit_after>//! Delays
//!
//! # Implementation details
//!
//! This module uses the TIM7 peripheral and the `_tim7` interrupt under the
//! hood.

use peripheral;

/// Blocks for `n` ms
pub fn ms(n: u16) {
    unsafe {
        let tim7 = peripheral::tim7_mut();

        // The alarm (the "update event") will set off in `n` "ticks".
        // One tick = 1 ms (see `init`)
        tim7.arr.write(|w| w.arr(n));

        // Generate an update event to update the autoreload register
        tim7.egr.write(|w| w.ug(true));

        // Clear any previous "update" event by clearing the update event flag
        tim7.sr.read();
        tim7.sr.write(|w| w);

        // CEN: Enable the counter
        tim7.cr1.modify(|_, w| w.cen(true));

        // Wait until the alarm goes off (the "update event" occurs)
        while !tim7.sr.read().uif() {}

        // Clear the "update" flag
        tim7.sr.write(|w| w);
    }
}

/// Initializes the necessary stuff to be able to use delays
///
/// # Safety
///
/// - Must be called once
/// - Must be called in an interrupt-free environment
pub unsafe fn init() {
    let rcc = peripheral::rcc_mut();
    let tim7 = peripheral::tim7_mut();

    // RCC: Enable TIM7
    rcc.apb1enr.modify(|_, w| w.tim7en(true));

    // CEN: Disable the clock
    // OPM. Enable One Pulse Mode. Stop the counter after the next update event.
    tim7.cr1.write(|w| w.cen(false).opm(true));

    // Set pre-scaler to 8_000 -> Frequency = 1 KHz
    tim7.psc.write(|w| w.psc(7_999));
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#![cfg(test)]

use model::{Board, Color, FieldCoord};

fn perft(board: &Board, depth: u8) -> u32 {
    if depth == 0 {
        1
    } else {
        let mut sum = 0;
        for mv in board.generate_moves() {
            let mut new_board = *board;
            new_board.apply_move(&mv);
            sum += perft(&new_board, depth - 1);
        }
        sum
    }
}

#[test]
fn perft_depth_4() {
    let counts = [48, 2304, 110304, 5280654];
    let board = Board::new();

    for (i, &count) in counts.iter().enumerate() {
        assert_eq!(count, perft(&board, i as u8 + 1));
    }
}

#[test]
fn fieldcoord_index_reflextivity() {
    for index in 0..57 {
        let white = FieldCoord::from_index(index as u8, Color::White);
        assert_eq!(index, white.to_index());

        let black = FieldCoord::from_index(index as u8, Color::Black);
        assert_eq!(index, black.to_index());
    }
}
<commit_msg>Add perft depth 5 test and disclaimer<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#![cfg(test)]

use model::{Board, Color, FieldCoord};

fn perft(board: &Board, depth: u8) -> u32 {
    if depth == 0 {
        1
    } else {
        let mut sum = 0;
        for mv in board.generate_moves() {
            let mut new_board = *board;
            new_board.apply_move(&mv);
            sum += perft(&new_board, depth - 1);
        }
        sum
    }
}

#[test]
fn perft_depth_4() {
    // These counts have not been verified by an external source. They only test for consistency
    // with earlier versions of the program.
    let counts = [48, 2304, 110304, 5280654];
    let board = Board::new();

    for (i, &count) in counts.iter().enumerate() {
        assert_eq!(count, perft(&board, i as u8 + 1));
    }
}

#[test]
#[ignore]
fn perft_depth_5() {
    // These counts have not been verified by an external source. They only test for consistency
    // with earlier versions of the program.
    let counts = [48, 2304, 110304, 5280654, 254945184];
    let board = Board::new();

    for (i, &count) in counts.iter().enumerate() {
        assert_eq!(count, perft(&board, i as u8 + 1));
    }
}

#[test]
fn fieldcoord_index_reflextivity() {
    for index in 0..57 {
        let white = FieldCoord::from_index(index as u8, Color::White);
        assert_eq!(index, white.to_index());

        let black = FieldCoord::from_index(index as u8, Color::Black);
        assert_eq!(index, black.to_index());
    }
}
<|endoftext|>


<commit_before>use super::Checked;

// Test a unary operator
macro_rules! test_unop {
    ($name:ident $t:ty: $op:tt $expr1:tt == $expr2:tt) => {
        #[test]
        fn $name() {
            let x = Checked::<$t>::from($expr1);
            let y = Checked::<$t>::from($expr2);
            assert_eq!($op x, y);
            assert_eq!($op &x, y);
        }
    };
}

// Test a binary operator
macro_rules! test_binop {
    ($name:ident $t:ty: $expr1:tt $op:tt $expr2:tt == $expr3:tt) => {
        #[test]
        fn $name() {
            let x1 = Checked::<$t>::from($expr1);
            let y1 = Checked::<$t>::from($expr2);
            let x2 = $expr1 as $t;
            let y2 = $expr2 as $t;
            let z = Checked::<$t>::from($expr3);
            assert_eq!(x1 $op y1, z);
            assert_eq!(x2 $op y1, z);
            assert_eq!(x1 $op y2, z);
            assert_eq!(&x1 $op y1, z);
            assert_eq!(&x2 $op y1, z);
            assert_eq!(&x1 $op y2, z);
            assert_eq!(x1 $op &y1, z);
            assert_eq!(x2 $op &y1, z);
            assert_eq!(x1 $op &y2, z);
            assert_eq!(&x1 $op &y1, z);
            assert_eq!(&x2 $op &y1, z);
            assert_eq!(&x1 $op &y2, z);
        }
    };

    ($name:ident $t:ty, $u:ty: $expr1:tt $op:tt $expr2:tt == $expr3:tt) => {
        #[test]
        fn $name() {
            let x1 = Checked::<$t>::from($expr1);
            let y1 = Checked::<$u>::from($expr2);
            let x2 = $expr1 as $t;
            let y2 = $expr2 as $u;
            let z = Checked::<$t>::from($expr3);
            assert_eq!(x1 $op y1, z);
            assert_eq!(x2 $op y1, z);
            assert_eq!(x1 $op y2, z);
            assert_eq!(&x1 $op y1, z);
            assert_eq!(&x2 $op y1, z);
            assert_eq!(&x1 $op y2, z);
            assert_eq!(x1 $op &y1, z);
            assert_eq!(x2 $op &y1, z);
            assert_eq!(x1 $op &y2, z);
            assert_eq!(&x1 $op &y1, z);
            assert_eq!(&x2 $op &y1, z);
            assert_eq!(&x1 $op &y2, z);
        }
    };

    ($name:ident $t:ty, $u:ty, $v:ty: $expr1:tt $op:tt $expr2:tt == $expr3:tt) => {
        #[test]
        fn $name() {
            let x1 = Checked::<$t>::from($expr1);
            let y1 = Checked::<$u>::from($expr2);
            let x2 = $expr1 as $t;
            let y2 = $expr2 as $u;
            let z = Checked::<$v>::from($expr3);
            assert_eq!(x1 $op y1, z);
            assert_eq!(x2 $op y1, z);
            assert_eq!(x1 $op y2, z);
            assert_eq!(&x1 $op y1, z);
            assert_eq!(&x2 $op y1, z);
            assert_eq!(&x1 $op y2, z);
            assert_eq!(x1 $op &y1, z);
            assert_eq!(x2 $op &y1, z);
            assert_eq!(x1 $op &y2, z);
            assert_eq!(&x1 $op &y1, z);
            assert_eq!(&x2 $op &y1, z);
            assert_eq!(&x1 $op &y2, z);
        }
    };
}

// These tests use None to indicate over/underflow.
test_binop! (add1 u8: 5 + 6 == 11);
test_binop! (add2 u32: 3_000_000_000 + 2_000_000_000 == None);
test_binop! (add3 i32: (-2_000_000_000) + (-2_000_000_000) == None);
test_binop! (sub u8: 5 - 6 == None);
test_binop! (mul1 u8: 5 * 6 == 30);
test_binop! (mul2 i32: 2_000_000_000 * 3 == None);
test_binop! (div1 u8: 10 / 3 == 3);
test_binop! (div2 u8: 10 / 0 == None);
test_binop! (and u8: 5 & 6 == 4);
test_binop! (xor u8: 5 ^ 6 == 3);
test_binop! (or u8: 5 | 6 == 7);
test_binop! (rem u8: 10 % 3 == 1);
test_binop! (shl u8, u32: 10 << 3 == 80);
test_binop! (shr u8, u32: 80 >> 3 == 10);
test_unop! (neg1 u8: - 5 == None);
test_unop! (neg2 i8: - 5 == (-5));
test_unop! (not i8: ! 5 == (-6));

#[test]
fn order() {
    assert!(Checked::from(1_000_u32) <= Checked::from(10_000_u32));
    assert!(!(Checked::from(1_000_u32) <= Checked::from(None)));
    assert!((Checked::from(None) <= Checked::from(1_000_u32)));
}

#[test]
fn new_checked() {
    assert_eq!(Checked::new(100), Checked(Some(100)))
}

#[test]
fn from_checked() {
    assert_eq!(Checked::from(100_u32), Checked(Some(100_u32)));
    assert_eq!(Checked::from(Some(100_u32)), Checked(Some(100_u32)));
    assert_eq!(Checked::<u64>::from(None), Checked::<u64>(None));
}

#[test]
fn consuming_option_methods() {
    let x = Checked::from(1_000_i64);
    assert_eq!(x.expect("AHH!!!"), 1_000);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.unwrap(), 1_000);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.unwrap_or(10), 1_000);

    let x = Checked::<i64>::from(None);
    assert_eq!(x.unwrap_or(10), 10);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.unwrap_or_else(|| 10), 1_000);

    let x = Checked::<i64>::from(None);
    assert_eq!(x.unwrap_or_else(|| 10), 10);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.map(|x| x + 15), Some(1_015));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.map(|x| x + 15), None);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.map_or(10, |x| x + 15), 1_015);

    let x = Checked::<i64>::from(None);
    assert_eq!(x.map_or(10, |x| x + 15), 10);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.map_or_else(|| 10, |x| x + 15), 1_015);

    let x = Checked::<i64>::from(None);
    assert_eq!(x.map_or_else(|| 10, |x| x + 15), 10);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.ok_or(14), Ok(1_000));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.ok_or(14), Err(14));

    let x = Checked::from(1_000_i64);
    assert_eq!(x.ok_or_else(|| 14), Ok(1_000));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.ok_or_else(|| 14), Err(14));

    let x = Checked::from(1_000_i64);
    assert_eq!(x.and(Some(19)), Some(19));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.and(Some(19)), None);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.and_then(|x| Some(x + 15)), Some(1_015));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.and_then(|x| Some(x + 15)), None);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.or(Some(19)), Some(1_000));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.or(Some(19)), Some(19));

    let x = Checked::from(1_000_i64);
    assert_eq!(x.or_else(|| Some(19)), Some(1_000));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.or_else(|| Some(19)), Some(19));
}

#[test]
fn ref_option_methods() {
    let x = Checked::from(1_000_i64);
    let y = Checked::<i64>::from(None);

    assert!(x.is_some());
    assert!(!y.is_some());

    assert!(!x.is_none());
    assert!(y.is_none());

    // More thorough testing is done in the docs, this mostly just checks to see if it works at all.
    Option::as_ref(&x);
    Option::as_ref(&y);

    println!("Numbers in x: ");
    for t in x.iter() {
        println!("{:?}", t);
    }

    println!("Numbers in y: ");
    for t in y.iter() {
        println!("{:?}", t);
    }
}

#[test]
fn mut_ref_option_methods() {
    let mut x = Checked::from(1_000_i64);
    let mut y = Checked::<i64>::from(None);

    Option::as_mut(&mut x);
    Option::as_mut(&mut y);

    println!("Numbers in x: ");
    for t in x.iter_mut() {
        println!("{:?}", t);
    }

    println!("Numbers in y: ");
    for t in y.iter_mut() {
        println!("{:?}", t);
    }

    let z = x.take();

    assert_eq!(z, Some(1_000_i64));
    assert_eq!(x, Checked::<i64>::from(None));

    let w = y.take();
    assert_eq!(w, None);
    assert_eq!(y, Checked::<i64>::from(None));
}
<commit_msg>Added the README example as a test, to make sure it works<commit_after>use super::Checked;

#[test]
fn readme_example() {
    let x = Checked::from(1_000_000_000_u32) * 3 + 2_000_000_000;
    match *x {
        Some(y) => println!("Didn't overflow: x is {}.", y),
        None => println!("The arithmetic overflowed."),
    }
}

// Test a unary operator
macro_rules! test_unop {
    ($name:ident $t:ty: $op:tt $expr1:tt == $expr2:tt) => {
        #[test]
        fn $name() {
            let x = Checked::<$t>::from($expr1);
            let y = Checked::<$t>::from($expr2);
            assert_eq!($op x, y);
            assert_eq!($op &x, y);
        }
    };
}

// Test a binary operator
macro_rules! test_binop {
    ($name:ident $t:ty: $expr1:tt $op:tt $expr2:tt == $expr3:tt) => {
        #[test]
        fn $name() {
            let x1 = Checked::<$t>::from($expr1);
            let y1 = Checked::<$t>::from($expr2);
            let x2 = $expr1 as $t;
            let y2 = $expr2 as $t;
            let z = Checked::<$t>::from($expr3);
            assert_eq!(x1 $op y1, z);
            assert_eq!(x2 $op y1, z);
            assert_eq!(x1 $op y2, z);
            assert_eq!(&x1 $op y1, z);
            assert_eq!(&x2 $op y1, z);
            assert_eq!(&x1 $op y2, z);
            assert_eq!(x1 $op &y1, z);
            assert_eq!(x2 $op &y1, z);
            assert_eq!(x1 $op &y2, z);
            assert_eq!(&x1 $op &y1, z);
            assert_eq!(&x2 $op &y1, z);
            assert_eq!(&x1 $op &y2, z);
        }
    };

    ($name:ident $t:ty, $u:ty: $expr1:tt $op:tt $expr2:tt == $expr3:tt) => {
        #[test]
        fn $name() {
            let x1 = Checked::<$t>::from($expr1);
            let y1 = Checked::<$u>::from($expr2);
            let x2 = $expr1 as $t;
            let y2 = $expr2 as $u;
            let z = Checked::<$t>::from($expr3);
            assert_eq!(x1 $op y1, z);
            assert_eq!(x2 $op y1, z);
            assert_eq!(x1 $op y2, z);
            assert_eq!(&x1 $op y1, z);
            assert_eq!(&x2 $op y1, z);
            assert_eq!(&x1 $op y2, z);
            assert_eq!(x1 $op &y1, z);
            assert_eq!(x2 $op &y1, z);
            assert_eq!(x1 $op &y2, z);
            assert_eq!(&x1 $op &y1, z);
            assert_eq!(&x2 $op &y1, z);
            assert_eq!(&x1 $op &y2, z);
        }
    };

    ($name:ident $t:ty, $u:ty, $v:ty: $expr1:tt $op:tt $expr2:tt == $expr3:tt) => {
        #[test]
        fn $name() {
            let x1 = Checked::<$t>::from($expr1);
            let y1 = Checked::<$u>::from($expr2);
            let x2 = $expr1 as $t;
            let y2 = $expr2 as $u;
            let z = Checked::<$v>::from($expr3);
            assert_eq!(x1 $op y1, z);
            assert_eq!(x2 $op y1, z);
            assert_eq!(x1 $op y2, z);
            assert_eq!(&x1 $op y1, z);
            assert_eq!(&x2 $op y1, z);
            assert_eq!(&x1 $op y2, z);
            assert_eq!(x1 $op &y1, z);
            assert_eq!(x2 $op &y1, z);
            assert_eq!(x1 $op &y2, z);
            assert_eq!(&x1 $op &y1, z);
            assert_eq!(&x2 $op &y1, z);
            assert_eq!(&x1 $op &y2, z);
        }
    };
}

// These tests use None to indicate over/underflow.
test_binop! (add1 u8: 5 + 6 == 11);
test_binop! (add2 u32: 3_000_000_000 + 2_000_000_000 == None);
test_binop! (add3 i32: (-2_000_000_000) + (-2_000_000_000) == None);
test_binop! (sub u8: 5 - 6 == None);
test_binop! (mul1 u8: 5 * 6 == 30);
test_binop! (mul2 i32: 2_000_000_000 * 3 == None);
test_binop! (div1 u8: 10 / 3 == 3);
test_binop! (div2 u8: 10 / 0 == None);
test_binop! (and u8: 5 & 6 == 4);
test_binop! (xor u8: 5 ^ 6 == 3);
test_binop! (or u8: 5 | 6 == 7);
test_binop! (rem u8: 10 % 3 == 1);
test_binop! (shl u8, u32: 10 << 3 == 80);
test_binop! (shr u8, u32: 80 >> 3 == 10);
test_unop! (neg1 u8: - 5 == None);
test_unop! (neg2 i8: - 5 == (-5));
test_unop! (not i8: ! 5 == (-6));

#[test]
fn order() {
    assert!(Checked::from(1_000_u32) <= Checked::from(10_000_u32));
    assert!(!(Checked::from(1_000_u32) <= Checked::from(None)));
    assert!((Checked::from(None) <= Checked::from(1_000_u32)));
}

#[test]
fn new_checked() {
    assert_eq!(Checked::new(100), Checked(Some(100)))
}

#[test]
fn from_checked() {
    assert_eq!(Checked::from(100_u32), Checked(Some(100_u32)));
    assert_eq!(Checked::from(Some(100_u32)), Checked(Some(100_u32)));
    assert_eq!(Checked::<u64>::from(None), Checked::<u64>(None));
}

#[test]
fn consuming_option_methods() {
    let x = Checked::from(1_000_i64);
    assert_eq!(x.expect("AHH!!!"), 1_000);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.unwrap(), 1_000);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.unwrap_or(10), 1_000);

    let x = Checked::<i64>::from(None);
    assert_eq!(x.unwrap_or(10), 10);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.unwrap_or_else(|| 10), 1_000);

    let x = Checked::<i64>::from(None);
    assert_eq!(x.unwrap_or_else(|| 10), 10);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.map(|x| x + 15), Some(1_015));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.map(|x| x + 15), None);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.map_or(10, |x| x + 15), 1_015);

    let x = Checked::<i64>::from(None);
    assert_eq!(x.map_or(10, |x| x + 15), 10);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.map_or_else(|| 10, |x| x + 15), 1_015);

    let x = Checked::<i64>::from(None);
    assert_eq!(x.map_or_else(|| 10, |x| x + 15), 10);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.ok_or(14), Ok(1_000));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.ok_or(14), Err(14));

    let x = Checked::from(1_000_i64);
    assert_eq!(x.ok_or_else(|| 14), Ok(1_000));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.ok_or_else(|| 14), Err(14));

    let x = Checked::from(1_000_i64);
    assert_eq!(x.and(Some(19)), Some(19));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.and(Some(19)), None);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.and_then(|x| Some(x + 15)), Some(1_015));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.and_then(|x| Some(x + 15)), None);

    let x = Checked::from(1_000_i64);
    assert_eq!(x.or(Some(19)), Some(1_000));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.or(Some(19)), Some(19));

    let x = Checked::from(1_000_i64);
    assert_eq!(x.or_else(|| Some(19)), Some(1_000));

    let x = Checked::<i64>::from(None);
    assert_eq!(x.or_else(|| Some(19)), Some(19));
}

#[test]
fn ref_option_methods() {
    let x = Checked::from(1_000_i64);
    let y = Checked::<i64>::from(None);

    assert!(x.is_some());
    assert!(!y.is_some());

    assert!(!x.is_none());
    assert!(y.is_none());

    // More thorough testing is done in the docs, this mostly just checks to see if it works at all.
    Option::as_ref(&x);
    Option::as_ref(&y);

    println!("Numbers in x: ");
    for t in x.iter() {
        println!("{:?}", t);
    }

    println!("Numbers in y: ");
    for t in y.iter() {
        println!("{:?}", t);
    }
}

#[test]
fn mut_ref_option_methods() {
    let mut x = Checked::from(1_000_i64);
    let mut y = Checked::<i64>::from(None);

    Option::as_mut(&mut x);
    Option::as_mut(&mut y);

    println!("Numbers in x: ");
    for t in x.iter_mut() {
        println!("{:?}", t);
    }

    println!("Numbers in y: ");
    for t in y.iter_mut() {
        println!("{:?}", t);
    }

    let z = x.take();

    assert_eq!(z, Some(1_000_i64));
    assert_eq!(x, Checked::<i64>::from(None));

    let w = y.take();
    assert_eq!(w, None);
    assert_eq!(y, Checked::<i64>::from(None));
}
<|endoftext|>


<commit_before>/* vim: set et: */

use hyper::client::Client;
use hyper::header::Headers;
use std::default::Default;
use std::fmt;
use std::io::Read;
use std::ops::Deref;
use url::Url;
use url::percent_encoding::percent_decode;
use urls::EVUrl;
use std::vec;

use std::iter::{repeat,Chain,Filter,FlatMap,Repeat,Map,Zip};

#[allow(unused_imports)]
use rustc_serialize::{json,Decodable,Decoder};

macro_rules! json_field {
    ($name:expr, $decoder:expr) => {
        try!($decoder.read_struct_field($name, 0, |d| Decodable::decode(d)))
    }
}

/// Describes an id of an folder
pub enum FolderId {
    Root,
    FolderId(i32)
}
impl fmt::Display for FolderId {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FolderId::Root => write!(fmt, "0"),
            FolderId::FolderId(ref id) => write!(fmt, "{}", id)
        }
    }
}

/// Contains information of a folder
#[allow(dead_code)]
#[derive(Clone, Debug, RustcDecodable)]
pub struct FolderInfo {
    id: i32, // TODO: Use FolderId and manually implement Decodable
    pub name: String,
    pub size: String, // TODO: Floating point
    pub has_unwatched: String, // TODO: Boolean
    pub has_wildcards: String, // TODO: Boolean
    pub has_pin: String, // TODO: option<int>
    pub recordings_count: usize
}
/*
impl<E, D : Decoder<E>> Decodable<D, E> for FolderInfo {
    fn decode(d: &mut D) -> Result<Folder, E> {
        let size_str = json_value!("size", d).words().next();
        let size = Float::parse(size_str.as_ref());
        Ok(FolderInfo {
            id: json_value!("id", d),
            name: json_value!("name", d),
            size: size
        })
    }
}*/

impl FolderInfo {
    fn root(rec_count: usize) -> FolderInfo {
        FolderInfo {
            id: 0,
            name: "Root".into(),
            size: "0".into(),
            has_unwatched: "false".into(),
            has_wildcards: "false".into(),
            has_pin: "false".into(),
            recordings_count: rec_count
        }
    }
}
/// Represents an item returned by Folders iterator
pub struct FolderRef<'a> {
    session_headers: &'a Headers,
    folder_info: &'a FolderInfo,
}
impl<'a> FolderRef<'a> {
    pub fn from_folder(folder: &Folder) -> FolderRef {
        FolderRef {
            session_headers: &folder.session_headers,
            folder_info: &folder.info
        }
    }
    pub fn fetch_into(self) -> Option<Folder> {
        self.fetch()
    }
    #[cfg(not(test))]
    pub fn fetch(&self) -> Option<Folder> {
        // TODO: Use FolderId enum
        let url = match self.folder_info.id {
            0 => EVUrl::Folder(FolderId::Root),
            id => EVUrl::Folder(FolderId::FolderId(id))
        };
        let mut client = Client::new();
        let res = client.get(url).headers(self.session_headers.clone()).send();
        res.ok().and_then(|mut res| {
            let mut ok = String::new();
            if let Err(_) = res.read_to_string(&mut ok) {
                return None
            }
            json::decode(&ok).and_then(|mut f: Folder| {
                f.info = self.folder_info.clone();
                f.set_headers(self.session_headers);
                Ok(f)
            }).ok()
        })
    }
}
impl<'a> Deref for FolderRef<'a> {
    type Target = FolderInfo;
    fn deref<'b>(&'b self) -> &'b Self::Target {
        self.folder_info
    }
}

pub struct RecordingRef<'a> {
    session_headers: &'a Headers,
    recording_info: &'a RecordingInfo,
}
impl<'a> RecordingRef<'a> {
    #[cfg(not(test))]
    fn fetch(&self) -> Option<Recording> {
        None // NYI
    }
}
impl<'a> Deref for RecordingRef<'a> {
    type Target = RecordingInfo;
    fn deref<'b>(&'b self) -> &'b Self::Target {
        self.recording_info
    }
}

/// Folder in Elisa Viihde
#[allow(dead_code)]
#[derive(Debug)]
pub struct Folder {
    info: FolderInfo,
    folders: Vec<FolderInfo>,
    recordings: Vec<RecordingInfo>,
    session_headers: Headers
}

/// Folder's IntoIterator implementation iterates over all recordings
/// of all folders starting from and including the folder into_iter() is called to
impl IntoIterator for Folder {
    type Item = RecordingInfo;
    type IntoIter =
        Chain<
            FlatMap<
                Filter<
                    Map<
                        Zip<vec::IntoIter<FolderInfo>, Repeat<Headers>>,
                        fn((FolderInfo, Headers)) -> Option<Folder>
                    >,
                    fn(&Option<Folder>) -> bool
                >,
                vec::IntoIter<RecordingInfo>,
                fn(Option<Folder>) -> vec::IntoIter<RecordingInfo>
            >,
            vec::IntoIter<RecordingInfo>
        >;
    fn into_iter(self) -> Self::IntoIter {
        self.folders.into_iter()
            .zip(repeat(self.session_headers.clone()))
            .map(into_iter_folderref as fn((FolderInfo, Headers)) -> Option<Folder>)
            .filter(Option::<Folder>::is_some as fn(&Option<Folder>) -> bool)
            .flat_map(into_iter_unwrapper as fn(Option<Folder>) -> vec::IntoIter<RecordingInfo>)
            .chain(self.recordings.into_iter())
    }
}
fn into_iter_folderref(data: (FolderInfo, Headers)) -> Option<Folder> {
    FolderRef {
        folder_info: &data.0,
        session_headers: &data.1,
    }.fetch_into()
}
fn into_iter_unwrapper(f: Option<Folder>) -> vec::IntoIter<RecordingInfo> {
    f.unwrap().recordings.into_iter()
}

/// Iterator over folders in another folder
pub struct Folders<'a> {
    index: usize,
    folder: &'a Folder
}

/// Iterator over recordings in a folder
pub struct Recordings<'a> {
    index: usize,
    folder: &'a Folder
}

impl<'a> Folder {
    /// Returns Folders over this folder
    pub fn folders(&'a self) -> Folders<'a> {
        Folders { index: 0, folder: &self }
    }
    /// Returns Recordings over this folder
    pub fn recordings(&'a self) -> Recordings<'a> {
        Recordings { index: 0, folder: self }
    }
    /// TODO: Is this necessary to be public? (Sets http headers for subsequent calls using this folder)
    pub fn set_headers(&mut self, headers: &Headers) {
        self.session_headers = headers.clone();
    }
}

impl fmt::Display for Folder {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.info.name)
    }
}

impl<'a> Iterator for Folders<'a> {
    type Item = FolderRef<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        let items = self.folder.folders.len();
        if items!=0 && self.index < items-1 {
            self.index += 1;
            Some(FolderRef {
                session_headers: &self.folder.session_headers,
                folder_info: &self.folder.folders[self.index]
            })
        }
        else {
            None
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.folder.folders.len()))
    }
}

impl<'a> Iterator for Recordings<'a> {
    type Item = RecordingRef<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        let items = self.folder.recordings.len();
        if items!=0 && self.index < items-1 {
            self.index += 1;
            Some(RecordingRef {
                session_headers: &self.folder.session_headers,
                recording_info: &self.folder.recordings[self.index]
            })
        }
        else {
            return None
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.folder.recordings.len()))
    }
}

impl Folder {
    fn decode_folder<D : Decoder>(d: &mut D) -> Result<Folder, D::Error> {
        let recordings: Vec<RecordingInfo> = json_field!("recordings", d);
        Ok(Folder {
            info: FolderInfo::root(recordings.len()),
            folders: json_field!("folders", d),
            recordings: recordings,
            session_headers: Headers::new(),
        })
    }
}

impl Decodable for Folder {
    fn decode<D : Decoder>(d: &mut D) -> Result<Folder, D::Error> {
        d.read_struct("", 0, |d| {
            d.read_struct_field("ready_data", 0, |rd| {
                rd.read_seq(|rd, len| {
                    assert!(len==1);
                    rd.read_seq_elt(0, |rd| { Folder::decode_folder(rd) })
                })
            })
        })
    }
}

/// Id of a program in Elisa Viihde
pub enum ProgramId {
    ProgramId(i32)
}
impl fmt::Display for ProgramId {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ProgramId::ProgramId(ref id) => write!(fmt, "{}", id)
        }
    }
}

/// Recording in Elisa Viihde
#[allow(dead_code)]
#[derive(Debug)]
pub struct Recording {
    pub info: RecordingInfo,
    pub id: i32,
    pub name: String,
    pub channel: String,
    pub length: i32,
    pub start_time: String,
    pub end_time: String,
    pub url: Url,
    pub programviewid: i32,
    pub recordingid: i32
}

/// Contains information of a Recording
#[derive(Clone, Debug, RustcDecodable)]
#[allow(dead_code)]
pub struct RecordingInfo {
    pub id : i32,
    pub program_id : i32,
    pub folder_id : String, // TODO: Option<int>
    pub name: String,
    pub channel: String,
    pub start_time: String, // TODO
    pub timestamp: String, // TODO
    pub viewcount: i32,
    pub length: i32
}

impl Default for RecordingInfo {
    fn default() -> RecordingInfo {
        RecordingInfo {
            id: 0,
            program_id: 0,
            folder_id: "".to_string(),
            name: "".to_string(),
            channel: "".to_string(),
            start_time: "".to_string(),
            timestamp: "".to_string(),
            viewcount: 0,
            length: 0
        }
    }
}

impl Decodable for Recording {
    fn decode<D : Decoder>(d: &mut D) -> Result<Recording, D::Error> {
        d.read_struct("", 0, |d| {
            Ok(Recording {
                info: Default::default(),
                id: json_field!("id", d),
                name: {
                    let percent_encoded_str : String = json_field!("name", d);
                    String::from_utf8(percent_decode(percent_encoded_str.as_bytes())).unwrap()
                },
                channel: json_field!("channel", d),
                length: json_field!("length", d),
                start_time: json_field!("start_time", d),
                end_time: json_field!("end_time", d),
                url: json_field!("url", d),
                programviewid: json_field!("programviewid", d),
                recordingid: json_field!("recordingid", d)
            })
        })
    }
}

impl Recording {
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json;
    use std::io::BufReader;
    use super::{Recording, Folder};
    use std::fs::File;
    use std::io::Lines;
    use std::io::BufRead;

    macro_rules! setup_test(
        ($filename:expr, $code:expr) => {
            match BufReader::new(File::open($filename).unwrap()).lines().next().unwrap() {
                Ok(line) => {
                    println!("{}", line);
                    match json::decode(&line) {
                        Ok(res) => {
                            $code(res)
                        },
                        Err(err) => {
                            println!("{}", err);
                            assert!(false);
                        }
                    };
                },
                Err(err) => {
                    println!("{}", err);
                    assert!(false);
                }
            }
        }
    );

    impl<'a> super::FolderRef<'a> {
        #[cfg(test)]
        fn fetch(&self) -> Option<Folder> {
            use std::io::BufReader;
            let file = File::open(format!("testdata/folder_{}.json", self.folder_info.id)).unwrap();
            let line = BufReader::new(file).lines().next().unwrap().unwrap();
            let mut fldr: Folder = json::decode(&line).unwrap();
            fldr.info = self.folder_info.clone();
            Some(fldr)
        }
    }
    impl<'a> super::RecordingRef<'a> {
        #[cfg(test)]
        fn fetch(&self) -> Option<Recording> {
            use std::io::BufReader;
            let file = File::open(format!("testdata/recording_{}.json", self.recording_info.program_id)).unwrap();
            let line = BufReader::new(file).lines().next().unwrap().unwrap();
            let mut rec: Recording = json::decode(&line).unwrap();
            rec.info = self.recording_info.clone();
            Some(rec)
        }
    }

    #[test]
    fn able_to_parse_folder() {
        setup_test!("testdata/root_folder.json", |_ : Folder| {});
    }

    #[test]
    fn able_to_iterate_folders() {
        setup_test!("testdata/root_folder.json", |f : Folder| {
            assert!(f.folders().size_hint() == (0, Some(2)), "Folder iterator had invalid bounds");
            let mut has_items: bool = false;
            for fldr in f.folders() {
                has_items = true;
                match fldr.id {
                    1000001 | 1000002 => {},
                    _ => assert!(false, "Folder id was invalid")
                }
            }
            assert!(has_items, "Folder iterator should return some items but it returned none");
        });
    }

    #[test]
    fn able_to_iterate_recordings() {
        setup_test!("testdata/root_folder.json", |f : Folder| {
            //assert!(f.recordings().size_hint() == (0, Some(2)));
            let mut has_items = false;
            for rec in f.recordings() {
                has_items = true;
                match rec.program_id {
                    1000001 | 1000002 => {},
                    _ => assert!(false, "Program id was invalid")
                }
            }
            assert!(has_items, "Recording iterator should return some items but it returned none");
        });
    }

    #[test]
    fn able_to_parse_recording() -> () {
        setup_test!("testdata/recording_1000001.json", |r : Recording| {
            assert!(r.id == 1000001);
            assert!(r.name == "Tämä on testi"); // Finnish characters used on purpose
            assert!(r.channel == "MTV3");
            assert!(r.length == 5);
            // start_time
            // end_time
            assert!(r.url.to_string() == "http://google.fi/");
            assert!(r.programviewid == 123456789);
            assert!(r.recordingid == 987654321);
        });
    }
}

<commit_msg>CI fix #2<commit_after>/* vim: set et: */

use hyper::client::Client;
use hyper::header::Headers;
use std::default::Default;
use std::fmt;
use std::io::Read;
use std::ops::Deref;
use url::Url;
use url::percent_encoding::percent_decode;
use urls::EVUrl;
use std::vec;

use std::iter::{repeat,Chain,Filter,FlatMap,Repeat,Map,Zip};

#[allow(unused_imports)]
use rustc_serialize::{json,Decodable,Decoder};

macro_rules! json_field {
    ($name:expr, $decoder:expr) => {
        try!($decoder.read_struct_field($name, 0, |d| Decodable::decode(d)))
    }
}

/// Describes an id of an folder
pub enum FolderId {
    Root,
    FolderId(i32)
}
impl fmt::Display for FolderId {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FolderId::Root => write!(fmt, "0"),
            FolderId::FolderId(ref id) => write!(fmt, "{}", id)
        }
    }
}

/// Contains information of a folder
#[allow(dead_code)]
#[derive(Clone, Debug, RustcDecodable)]
pub struct FolderInfo {
    id: i32, // TODO: Use FolderId and manually implement Decodable
    pub name: String,
    pub size: String, // TODO: Floating point
    pub has_unwatched: String, // TODO: Boolean
    pub has_wildcards: String, // TODO: Boolean
    pub has_pin: String, // TODO: option<int>
    pub recordings_count: usize
}
/*
impl<E, D : Decoder<E>> Decodable<D, E> for FolderInfo {
    fn decode(d: &mut D) -> Result<Folder, E> {
        let size_str = json_value!("size", d).words().next();
        let size = Float::parse(size_str.as_ref());
        Ok(FolderInfo {
            id: json_value!("id", d),
            name: json_value!("name", d),
            size: size
        })
    }
}*/

impl FolderInfo {
    fn root(rec_count: usize) -> FolderInfo {
        FolderInfo {
            id: 0,
            name: "Root".into(),
            size: "0".into(),
            has_unwatched: "false".into(),
            has_wildcards: "false".into(),
            has_pin: "false".into(),
            recordings_count: rec_count
        }
    }
}
/// Represents an item returned by Folders iterator
pub struct FolderRef<'a> {
    session_headers: &'a Headers,
    folder_info: &'a FolderInfo,
}
impl<'a> FolderRef<'a> {
    pub fn from_folder(folder: &Folder) -> FolderRef {
        FolderRef {
            session_headers: &folder.session_headers,
            folder_info: &folder.info
        }
    }
    pub fn fetch_into(self) -> Option<Folder> {
        self.fetch()
    }
    #[cfg(not(test))]
    pub fn fetch(&self) -> Option<Folder> {
        // TODO: Use FolderId enum
        let url = match self.folder_info.id {
            0 => EVUrl::Folder(FolderId::Root),
            id => EVUrl::Folder(FolderId::FolderId(id))
        };
        let mut client = Client::new();
        let res = client.get(url).headers(self.session_headers.clone()).send();
        res.ok().and_then(|mut res| {
            let mut ok = String::new();
            if let Err(_) = res.read_to_string(&mut ok) {
                return None
            }
            json::decode(&ok).and_then(|mut f: Folder| {
                f.info = self.folder_info.clone();
                f.set_headers(self.session_headers);
                Ok(f)
            }).ok()
        })
    }
}
impl<'a> Deref for FolderRef<'a> {
    type Target = FolderInfo;
    fn deref<'b>(&'b self) -> &'b Self::Target {
        self.folder_info
    }
}

pub struct RecordingRef<'a> {
    session_headers: &'a Headers,
    recording_info: &'a RecordingInfo,
}
impl<'a> RecordingRef<'a> {
    #[cfg(not(test))]
    fn fetch(&self) -> Option<Recording> {
        None // NYI
    }
}
impl<'a> Deref for RecordingRef<'a> {
    type Target = RecordingInfo;
    fn deref<'b>(&'b self) -> &'b Self::Target {
        self.recording_info
    }
}

/// Folder in Elisa Viihde
#[allow(dead_code)]
#[derive(Debug)]
pub struct Folder {
    info: FolderInfo,
    folders: Vec<FolderInfo>,
    recordings: Vec<RecordingInfo>,
    session_headers: Headers
}

/// Folder's IntoIterator implementation iterates over all recordings
/// of all folders starting from and including the folder into_iter() is called to
impl IntoIterator for Folder {
    type Item = RecordingInfo;
    type IntoIter =
        Chain<
            FlatMap<
                Filter<
                    Map<
                        Zip<vec::IntoIter<FolderInfo>, Repeat<Headers>>,
                        fn((FolderInfo, Headers)) -> Option<Folder>
                    >,
                    fn(&Option<Folder>) -> bool
                >,
                vec::IntoIter<RecordingInfo>,
                fn(Option<Folder>) -> vec::IntoIter<RecordingInfo>
            >,
            vec::IntoIter<RecordingInfo>
        >;
    fn into_iter(self) -> Self::IntoIter {
        self.folders.into_iter()
            .zip(repeat(self.session_headers.clone()))
            .map(into_iter_folderref as fn((FolderInfo, Headers)) -> Option<Folder>)
            .filter(Option::<Folder>::is_some as fn(&Option<Folder>) -> bool)
            .flat_map(into_iter_unwrapper as fn(Option<Folder>) -> vec::IntoIter<RecordingInfo>)
            .chain(self.recordings.into_iter())
    }
}
fn into_iter_folderref(data: (FolderInfo, Headers)) -> Option<Folder> {
    FolderRef {
        folder_info: &data.0,
        session_headers: &data.1,
    }.fetch_into()
}
fn into_iter_unwrapper(f: Option<Folder>) -> vec::IntoIter<RecordingInfo> {
    f.unwrap().recordings.into_iter()
}

/// Iterator over folders in another folder
pub struct Folders<'a> {
    index: usize,
    folder: &'a Folder
}

/// Iterator over recordings in a folder
pub struct Recordings<'a> {
    index: usize,
    folder: &'a Folder
}

impl<'a> Folder {
    /// Returns Folders over this folder
    pub fn folders(&'a self) -> Folders<'a> {
        Folders { index: 0, folder: &self }
    }
    /// Returns Recordings over this folder
    pub fn recordings(&'a self) -> Recordings<'a> {
        Recordings { index: 0, folder: self }
    }
    /// TODO: Is this necessary to be public? (Sets http headers for subsequent calls using this folder)
    pub fn set_headers(&mut self, headers: &Headers) {
        self.session_headers = headers.clone();
    }
}

impl fmt::Display for Folder {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.info.name)
    }
}

impl<'a> Iterator for Folders<'a> {
    type Item = FolderRef<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        let items = self.folder.folders.len();
        if items!=0 && self.index < items-1 {
            self.index += 1;
            Some(FolderRef {
                session_headers: &self.folder.session_headers,
                folder_info: &self.folder.folders[self.index]
            })
        }
        else {
            None
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.folder.folders.len()))
    }
}

impl<'a> Iterator for Recordings<'a> {
    type Item = RecordingRef<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        let items = self.folder.recordings.len();
        if items!=0 && self.index < items-1 {
            self.index += 1;
            Some(RecordingRef {
                session_headers: &self.folder.session_headers,
                recording_info: &self.folder.recordings[self.index]
            })
        }
        else {
            return None
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, Some(self.folder.recordings.len()))
    }
}

impl Folder {
    fn decode_folder<D : Decoder>(d: &mut D) -> Result<Folder, D::Error> {
        let recordings: Vec<RecordingInfo> = json_field!("recordings", d);
        Ok(Folder {
            info: FolderInfo::root(recordings.len()),
            folders: json_field!("folders", d),
            recordings: recordings,
            session_headers: Headers::new(),
        })
    }
}

impl Decodable for Folder {
    fn decode<D : Decoder>(d: &mut D) -> Result<Folder, D::Error> {
        d.read_struct("", 0, |d| {
            d.read_struct_field("ready_data", 0, |rd| {
                rd.read_seq(|rd, len| {
                    assert!(len==1);
                    rd.read_seq_elt(0, |rd| { Folder::decode_folder(rd) })
                })
            })
        })
    }
}

/// Id of a program in Elisa Viihde
pub enum ProgramId {
    ProgramId(i32)
}
impl fmt::Display for ProgramId {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ProgramId::ProgramId(ref id) => write!(fmt, "{}", id)
        }
    }
}

/// Recording in Elisa Viihde
#[allow(dead_code)]
#[derive(Debug)]
pub struct Recording {
    pub info: RecordingInfo,
    pub id: i32,
    pub name: String,
    pub channel: String,
    pub length: i32,
    pub start_time: String,
    pub end_time: String,
    pub url: Url,
    pub programviewid: i32,
    pub recordingid: i32
}

/// Contains information of a Recording
#[derive(Clone, Debug, RustcDecodable)]
#[allow(dead_code)]
pub struct RecordingInfo {
    pub id : i32,
    pub program_id : i32,
    pub folder_id : String, // TODO: Option<int>
    pub name: String,
    pub channel: String,
    pub start_time: String, // TODO
    pub timestamp: String, // TODO
    pub viewcount: i32,
    pub length: i32
}

impl Default for RecordingInfo {
    fn default() -> RecordingInfo {
        RecordingInfo {
            id: 0,
            program_id: 0,
            folder_id: "".to_string(),
            name: "".to_string(),
            channel: "".to_string(),
            start_time: "".to_string(),
            timestamp: "".to_string(),
            viewcount: 0,
            length: 0
        }
    }
}

impl Decodable for Recording {
    fn decode<D : Decoder>(d: &mut D) -> Result<Recording, D::Error> {
        d.read_struct("", 0, |d| {
            Ok(Recording {
                info: Default::default(),
                id: json_field!("id", d),
                name: {
                    let percent_encoded_str : String = json_field!("name", d);
                    String::from_utf8(percent_decode(percent_encoded_str.as_bytes())).unwrap()
                },
                channel: json_field!("channel", d),
                length: json_field!("length", d),
                start_time: json_field!("start_time", d),
                end_time: json_field!("end_time", d),
                url: json_field!("url", d),
                programviewid: json_field!("programviewid", d),
                recordingid: json_field!("recordingid", d)
            })
        })
    }
}

impl Recording {
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json;
    use std::io::BufReader;
    use super::{Recording, Folder};
    use std::fs::File;
    use std::io::Lines;
    use std::io::BufRead;

    macro_rules! setup_test(
        ($filename:expr, $code:expr) => {
            match BufReader::new(File::open($filename).unwrap()).lines().next().unwrap() {
                Ok(line) => {
                    println!("{}", line);
                    match json::decode(&line) {
                        Ok(res) => {
                            $code(res)
                        },
                        Err(err) => {
                            println!("{}", err);
                            assert!(false);
                        }
                    };
                },
                Err(err) => {
                    println!("{}", err);
                    assert!(false);
                }
            }
        }
    );

    impl<'a> super::FolderRef<'a> {
        #[cfg(test)]
        pub fn fetch(&self) -> Option<Folder> {
            use std::io::BufReader;
            let file = File::open(format!("testdata/folder_{}.json", self.folder_info.id)).unwrap();
            let line = BufReader::new(file).lines().next().unwrap().unwrap();
            let mut fldr: Folder = json::decode(&line).unwrap();
            fldr.info = self.folder_info.clone();
            Some(fldr)
        }
    }
    impl<'a> super::RecordingRef<'a> {
        #[cfg(test)]
        pub fn fetch(&self) -> Option<Recording> {
            use std::io::BufReader;
            let file = File::open(format!("testdata/recording_{}.json", self.recording_info.program_id)).unwrap();
            let line = BufReader::new(file).lines().next().unwrap().unwrap();
            let mut rec: Recording = json::decode(&line).unwrap();
            rec.info = self.recording_info.clone();
            Some(rec)
        }
    }

    #[test]
    fn able_to_parse_folder() {
        setup_test!("testdata/root_folder.json", |_ : Folder| {});
    }

    #[test]
    fn able_to_iterate_folders() {
        setup_test!("testdata/root_folder.json", |f : Folder| {
            assert!(f.folders().size_hint() == (0, Some(2)), "Folder iterator had invalid bounds");
            let mut has_items: bool = false;
            for fldr in f.folders() {
                has_items = true;
                match fldr.id {
                    1000001 | 1000002 => {},
                    _ => assert!(false, "Folder id was invalid")
                }
            }
            assert!(has_items, "Folder iterator should return some items but it returned none");
        });
    }

    #[test]
    fn able_to_iterate_recordings() {
        setup_test!("testdata/root_folder.json", |f : Folder| {
            //assert!(f.recordings().size_hint() == (0, Some(2)));
            let mut has_items = false;
            for rec in f.recordings() {
                has_items = true;
                match rec.program_id {
                    1000001 | 1000002 => {},
                    _ => assert!(false, "Program id was invalid")
                }
            }
            assert!(has_items, "Recording iterator should return some items but it returned none");
        });
    }

    #[test]
    fn able_to_parse_recording() -> () {
        setup_test!("testdata/recording_1000001.json", |r : Recording| {
            assert!(r.id == 1000001);
            assert!(r.name == "Tämä on testi"); // Finnish characters used on purpose
            assert!(r.channel == "MTV3");
            assert!(r.length == 5);
            // start_time
            // end_time
            assert!(r.url.to_string() == "http://google.fi/");
            assert!(r.programviewid == 123456789);
            assert!(r.recordingid == 987654321);
        });
    }
}

<|endoftext|>


<commit_before>//! Functions for detecting edges in images.

use std::f32;
use image::{GenericImage, GrayImage, ImageBuffer, Luma};
use gradients::{vertical_sobel, horizontal_sobel};
use definitions::{HasWhite, HasBlack};
use filter::gaussian_blur_f32;

/// Runs the canny edge detection algorithm on the provided `ImageBuffer`.
///
/// # Params
///
/// - `low_threshold`: Low threshold for the hysteresis procedure.
/// Edges with a strength higher than the low threshold will appear
/// in the output image, if there are strong edges nearby.
/// - `high_threshold`: High threshold for the hysteresis procedure.
/// Edges with a strength higher than the high threshold will always
/// appear as edges in the output image.
///
/// Returns a binary image, where edge pixels have a value of 255 and non-edge pixels a value of 0.
pub fn canny(image: &GrayImage,
             low_threshold: f32,
             high_threshold: f32)
             -> GrayImage {
    assert!(high_threshold >= low_threshold);
    // Heavily based on the implementation proposed by wikipedia.
    // 1. Gaussian blur.
    const SIGMA: f32 = 1.4;
    let blurred = gaussian_blur_f32(image, SIGMA);

    // 2. Intensity of gradients.
    let gx = horizontal_sobel(&blurred);
    let gy = vertical_sobel(&blurred);
    let g: Vec<f32> = gx.iter()
                        .zip(gy.iter())
                        .map(|(h, v)| (*h as f32).hypot(*v as f32))
                        .collect::<Vec<f32>>();

    let g = ImageBuffer::from_raw(image.width(), image.height(), g).unwrap();

    // 3. Non-maximum-suppression (Make edges thinner)
    let thinned = non_maximum_suppression(&g, &gx, &gy);

    // 4. Hysteresis to filter out edges based on thresholds.
    hysteresis(&thinned, low_threshold, high_threshold)
}

/// Finds local maxima to make the edges thinner.
fn non_maximum_suppression(g: &ImageBuffer<Luma<f32>, Vec<f32>>,
                           gx: &ImageBuffer<Luma<i16>, Vec<i16>>,
                           gy: &ImageBuffer<Luma<i16>, Vec<i16>>)
                           -> ImageBuffer<Luma<f32>, Vec<f32>> {
    const RADIANS_TO_DEGREES: f32 = 180f32 / f32::consts::PI;
    let mut out = ImageBuffer::from_pixel(g.width(), g.height(), Luma { data: [0.0] });
    for y in 1..g.height() - 1 {
        for x in 1..g.width() - 1 {
            let x_gradient = gx[(x, y)][0] as f32;
            let y_gradient = gy[(x, y)][0] as f32;
            let mut angle = (y_gradient).atan2(x_gradient) * RADIANS_TO_DEGREES;
            if angle < 0.0 {
                angle += 180.0
            }
            // Clamp angle.
            let clamped_angle = if angle >= 157.5 || angle < 22.5 {
                0
            } else if angle >= 22.5 && angle < 67.5 {
                45
            } else if angle >= 67.5 && angle < 112.5 {
                90
            } else if angle >= 112.5 && angle < 157.5 {
                135
            } else {
                unreachable!()
            };

            // Get the two perpendicular neighbors.
            let (cmp1, cmp2) = unsafe {
                match clamped_angle {
                    0 => (g.unsafe_get_pixel(x - 1, y), g.unsafe_get_pixel(x + 1, y)),
                    45 => {
                        (g.unsafe_get_pixel(x + 1, y + 1),
                         g.unsafe_get_pixel(x - 1, y - 1))
                    }
                    90 => (g.unsafe_get_pixel(x, y - 1), g.unsafe_get_pixel(x, y + 1)),
                    135 => {
                        (g.unsafe_get_pixel(x - 1, y + 1),
                         g.unsafe_get_pixel(x + 1, y - 1))
                    }
                    _ => unreachable!(),
                }
            };
            let pixel = *g.get_pixel(x, y);
            // If the pixel is not a local maximum, suppress it.
            if pixel[0] < cmp1[0] || pixel[0] < cmp2[0] {
                out.put_pixel(x, y, Luma { data: [0.0] });
            } else {
                out.put_pixel(x, y, pixel);
            }
        }
    }
    out
}

/// Filter out edges with the thresholds.
/// Non-recursive breadth-first search.
fn hysteresis(input: &ImageBuffer<Luma<f32>, Vec<f32>>,
              low_thresh: f32,
              high_thresh: f32)
              -> ImageBuffer<Luma<u8>, Vec<u8>> {

    let max_brightness = Luma::white();
    let min_brightness = Luma::black();
    // Init output image as all black.
    let mut out = ImageBuffer::from_pixel(input.width(), input.height(), min_brightness);
    // Stack. Possible optimization: Use previously allocated memory, i.e. gx.
    let mut edges = Vec::with_capacity(((input.width() * input.height()) / 2) as usize);
    for y in 1..input.height() - 1 {
        for x in 1..input.width() - 1 {
            let inp_pix = *input.get_pixel(x, y);
            let out_pix = *out.get_pixel(x, y);
            // If the edge strength is higher than high_thresh, mark it as an edge.
            if inp_pix[0] >= high_thresh && out_pix[0] == 0 {
                out.put_pixel(x, y, max_brightness);
                edges.push((x, y));
                // Track neighbors until no neighbor is >= low_thresh.
                while !edges.is_empty() {
                    let (nx, ny) = edges.pop().unwrap();
                    let neighbor_indices = [(nx + 1, ny),
                                            (nx + 1, ny + 1),
                                            (nx, ny + 1),
                                            (nx - 1, ny - 1),
                                            (nx - 1, ny),
                                            (nx - 1, ny + 1)];

                    for neighbor_idx in &neighbor_indices {
                        let in_neighbor = *input.get_pixel(neighbor_idx.0, neighbor_idx.1);
                        let out_neighbor = *out.get_pixel(neighbor_idx.0, neighbor_idx.1);
                        if in_neighbor[0] >= low_thresh && out_neighbor[0] == 0 {
                            out.put_pixel(neighbor_idx.0, neighbor_idx.1, max_brightness);
                            edges.push((neighbor_idx.0, neighbor_idx.1));
                        }
                    }
                }
            }
        }
    }
    out
}

#[cfg(test)]
mod test {
    use super::canny;
    use drawing::{draw_filled_rect_mut};
    use rect::Rect;
    use image::{GrayImage, Luma};
    use test;

    fn edge_detect_bench_image(width: u32, height: u32) -> GrayImage {
        let mut image = GrayImage::new(width, height);
        let (w, h) = (width as i32, height as i32);
        let large = Rect::at(w / 4, h / 4).of_size(width / 2, height / 2);
        let small = Rect::at(9, 9).of_size(3, 3);

        draw_filled_rect_mut(&mut image, large, Luma([255]));
        draw_filled_rect_mut(&mut image, small, Luma([255]));

        image
    }

    #[bench]
    fn bench_canny(b: &mut test::Bencher) {
        let image = edge_detect_bench_image(250, 250);
        b.iter(|| {
            let output = canny(&image, 250.0, 300.0);
            test::black_box(output);
        });
    }
}
<commit_msg>Document range of sensible thresholds for canny function<commit_after>//! Functions for detecting edges in images.

use std::f32;
use image::{GenericImage, GrayImage, ImageBuffer, Luma};
use gradients::{vertical_sobel, horizontal_sobel};
use definitions::{HasWhite, HasBlack};
use filter::gaussian_blur_f32;

/// Runs the canny edge detection algorithm.
///
/// Returns a binary image where edge pixels have a value of 255
///  and non-edge pixels a value of 0.
///
/// # Params
///
/// - `low_threshold`: Low threshold for the hysteresis procedure.
/// Edges with a strength higher than the low threshold will appear
/// in the output image, if there are strong edges nearby.
/// - `high_threshold`: High threshold for the hysteresis procedure.
/// Edges with a strength higher than the high threshold will always
/// appear as edges in the output image.
///
/// The greatest possible edge strength (and so largest sensible threshold)
/// is`sqrt(5) * 2 * 255`, or approximately 1140.39.
///
/// This odd looking value is the result of using a standard
/// definition of edge strength: the strength of an edge at a point `p` is
/// defined to be `sqrt(dx^2 + dy^2)`, where `dx` and `dy` are the values
/// of the horizontal and vertical Sobel gradients at `p`.
pub fn canny(image: &GrayImage,
             low_threshold: f32,
             high_threshold: f32)
             -> GrayImage {
    assert!(high_threshold >= low_threshold);
    // Heavily based on the implementation proposed by wikipedia.
    // 1. Gaussian blur.
    const SIGMA: f32 = 1.4;
    let blurred = gaussian_blur_f32(image, SIGMA);

    // 2. Intensity of gradients.
    let gx = horizontal_sobel(&blurred);
    let gy = vertical_sobel(&blurred);
    let g: Vec<f32> = gx.iter()
                        .zip(gy.iter())
                        .map(|(h, v)| (*h as f32).hypot(*v as f32))
                        .collect::<Vec<f32>>();

    let g = ImageBuffer::from_raw(image.width(), image.height(), g).unwrap();

    // 3. Non-maximum-suppression (Make edges thinner)
    let thinned = non_maximum_suppression(&g, &gx, &gy);

    // 4. Hysteresis to filter out edges based on thresholds.
    hysteresis(&thinned, low_threshold, high_threshold)
}

/// Finds local maxima to make the edges thinner.
fn non_maximum_suppression(g: &ImageBuffer<Luma<f32>, Vec<f32>>,
                           gx: &ImageBuffer<Luma<i16>, Vec<i16>>,
                           gy: &ImageBuffer<Luma<i16>, Vec<i16>>)
                           -> ImageBuffer<Luma<f32>, Vec<f32>> {
    const RADIANS_TO_DEGREES: f32 = 180f32 / f32::consts::PI;
    let mut out = ImageBuffer::from_pixel(g.width(), g.height(), Luma { data: [0.0] });
    for y in 1..g.height() - 1 {
        for x in 1..g.width() - 1 {
            let x_gradient = gx[(x, y)][0] as f32;
            let y_gradient = gy[(x, y)][0] as f32;
            let mut angle = (y_gradient).atan2(x_gradient) * RADIANS_TO_DEGREES;
            if angle < 0.0 {
                angle += 180.0
            }
            // Clamp angle.
            let clamped_angle = if angle >= 157.5 || angle < 22.5 {
                0
            } else if angle >= 22.5 && angle < 67.5 {
                45
            } else if angle >= 67.5 && angle < 112.5 {
                90
            } else if angle >= 112.5 && angle < 157.5 {
                135
            } else {
                unreachable!()
            };

            // Get the two perpendicular neighbors.
            let (cmp1, cmp2) = unsafe {
                match clamped_angle {
                    0 => (g.unsafe_get_pixel(x - 1, y), g.unsafe_get_pixel(x + 1, y)),
                    45 => {
                        (g.unsafe_get_pixel(x + 1, y + 1),
                         g.unsafe_get_pixel(x - 1, y - 1))
                    }
                    90 => (g.unsafe_get_pixel(x, y - 1), g.unsafe_get_pixel(x, y + 1)),
                    135 => {
                        (g.unsafe_get_pixel(x - 1, y + 1),
                         g.unsafe_get_pixel(x + 1, y - 1))
                    }
                    _ => unreachable!(),
                }
            };
            let pixel = *g.get_pixel(x, y);
            // If the pixel is not a local maximum, suppress it.
            if pixel[0] < cmp1[0] || pixel[0] < cmp2[0] {
                out.put_pixel(x, y, Luma { data: [0.0] });
            } else {
                out.put_pixel(x, y, pixel);
            }
        }
    }
    out
}

/// Filter out edges with the thresholds.
/// Non-recursive breadth-first search.
fn hysteresis(input: &ImageBuffer<Luma<f32>, Vec<f32>>,
              low_thresh: f32,
              high_thresh: f32)
              -> ImageBuffer<Luma<u8>, Vec<u8>> {

    let max_brightness = Luma::white();
    let min_brightness = Luma::black();
    // Init output image as all black.
    let mut out = ImageBuffer::from_pixel(input.width(), input.height(), min_brightness);
    // Stack. Possible optimization: Use previously allocated memory, i.e. gx.
    let mut edges = Vec::with_capacity(((input.width() * input.height()) / 2) as usize);
    for y in 1..input.height() - 1 {
        for x in 1..input.width() - 1 {
            let inp_pix = *input.get_pixel(x, y);
            let out_pix = *out.get_pixel(x, y);
            // If the edge strength is higher than high_thresh, mark it as an edge.
            if inp_pix[0] >= high_thresh && out_pix[0] == 0 {
                out.put_pixel(x, y, max_brightness);
                edges.push((x, y));
                // Track neighbors until no neighbor is >= low_thresh.
                while !edges.is_empty() {
                    let (nx, ny) = edges.pop().unwrap();
                    let neighbor_indices = [(nx + 1, ny),
                                            (nx + 1, ny + 1),
                                            (nx, ny + 1),
                                            (nx - 1, ny - 1),
                                            (nx - 1, ny),
                                            (nx - 1, ny + 1)];

                    for neighbor_idx in &neighbor_indices {
                        let in_neighbor = *input.get_pixel(neighbor_idx.0, neighbor_idx.1);
                        let out_neighbor = *out.get_pixel(neighbor_idx.0, neighbor_idx.1);
                        if in_neighbor[0] >= low_thresh && out_neighbor[0] == 0 {
                            out.put_pixel(neighbor_idx.0, neighbor_idx.1, max_brightness);
                            edges.push((neighbor_idx.0, neighbor_idx.1));
                        }
                    }
                }
            }
        }
    }
    out
}

#[cfg(test)]
mod test {
    use super::canny;
    use drawing::{draw_filled_rect_mut};
    use rect::Rect;
    use image::{GrayImage, Luma};
    use test;

    fn edge_detect_bench_image(width: u32, height: u32) -> GrayImage {
        let mut image = GrayImage::new(width, height);
        let (w, h) = (width as i32, height as i32);
        let large = Rect::at(w / 4, h / 4).of_size(width / 2, height / 2);
        let small = Rect::at(9, 9).of_size(3, 3);

        draw_filled_rect_mut(&mut image, large, Luma([255]));
        draw_filled_rect_mut(&mut image, small, Luma([255]));

        image
    }

    #[bench]
    fn bench_canny(b: &mut test::Bencher) {
        let image = edge_detect_bench_image(250, 250);
        b.iter(|| {
            let output = canny(&image, 250.0, 300.0);
            test::black_box(output);
        });
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

extern crate mentat;
extern crate mentat_core;
extern crate mentat_tolstoy;

use std::collections::BTreeMap;

use mentat::conn::Conn;

use mentat::new_connection;
use mentat_tolstoy::tx_processor::{
    Processor,
    TxReceiver,
    TxPart,
};
use mentat_tolstoy::errors::Result;
use mentat_core::{
    Entid,
    TypedValue,
    ValueType,
};

struct TxCountingReceiver {
    pub tx_count: usize,
    pub is_done: bool,
}

impl TxCountingReceiver {
    fn new() -> TxCountingReceiver {
        TxCountingReceiver {
            tx_count: 0,
            is_done: false,
        }
    }
}

impl TxReceiver for TxCountingReceiver {
    fn tx<T>(&mut self, _tx_id: Entid, _d: &mut T) -> Result<()>
        where T: Iterator<Item=TxPart> {
        self.tx_count = self.tx_count + 1;
        Ok(())
    }

    fn done(&mut self) -> Result<()> {
        self.is_done = true;
        Ok(())
    }
}

#[derive(Debug)]
struct TestingReceiver {
    pub txes: BTreeMap<Entid, Vec<TxPart>>,
    pub is_done: bool,
}

impl TestingReceiver {
    fn new() -> TestingReceiver {
        TestingReceiver {
            txes: BTreeMap::new(),
            is_done: false,
        }
    }
}

impl TxReceiver for TestingReceiver {
    fn tx<T>(&mut self, tx_id: Entid, d: &mut T) -> Result<()>
        where T: Iterator<Item=TxPart> {
        let datoms = self.txes.entry(tx_id).or_insert(vec![]);
        datoms.extend(d);
        Ok(())
    }

    fn done(&mut self) -> Result<()> {
        self.is_done = true;
        Ok(())
    }
}

fn assert_tx_datoms_count(receiver: &TestingReceiver, tx_num: usize, expected_datoms: usize) {
    let tx = receiver.txes.keys().nth(tx_num).expect("first tx");
    let datoms = receiver.txes.get(tx).expect("datoms");
    assert_eq!(expected_datoms, datoms.len());
}

#[test]
fn test_reader() {
    let mut c = new_connection("").expect("Couldn't open conn.");
    let mut conn = Conn::connect(&mut c).expect("Couldn't open DB.");
    {
        let db_tx = c.transaction().expect("db tx");
        // Don't inspect the bootstrap transaction, but we'd like to see it's there.
        let mut receiver = TxCountingReceiver::new();
        assert_eq!(false, receiver.is_done);
        Processor::process(&db_tx, None, &mut receiver).expect("processor");
        assert_eq!(true, receiver.is_done);
        assert_eq!(1, receiver.tx_count);
    }

    let ids = conn.transact(&mut c, r#"[
        [:db/add "s" :db/ident :foo/numba]
        [:db/add "s" :db/valueType :db.type/long]
        [:db/add "s" :db/cardinality :db.cardinality/one]
    ]"#).expect("successful transaction").tempids;
    let numba_entity_id = ids.get("s").unwrap();

    let mut bootstrap_tx = None;
    {
        let db_tx = c.transaction().expect("db tx");
        // Expect to see one more transaction of four parts (one for tx datom itself).
        let mut receiver = TestingReceiver::new();
        Processor::process(&db_tx, None, &mut receiver).expect("processor");

        println!("{:#?}", receiver);

        assert_eq!(2, receiver.txes.keys().count());
        assert_tx_datoms_count(&receiver, 1, 4);

        bootstrap_tx = Some(*receiver.txes.keys().nth(0).expect("bootstrap tx"));
    }

    let ids = conn.transact(&mut c, r#"[
        [:db/add "b" :foo/numba 123]
    ]"#).expect("successful transaction").tempids;
    let asserted_e = ids.get("b").unwrap();

    {
        let db_tx = c.transaction().expect("db tx");

        // Expect to see a single two part transaction
        let mut receiver = TestingReceiver::new();

        // Note that we're asking for the bootstrap tx to be skipped by the processor.
        Processor::process(&db_tx, bootstrap_tx, &mut receiver).expect("processor");

        assert_eq!(2, receiver.txes.keys().count());
        assert_tx_datoms_count(&receiver, 1, 2);

        // Inspect the transaction part.
        let tx_id = receiver.txes.keys().nth(1).expect("tx");
        let datoms = receiver.txes.get(tx_id).expect("datoms");
        let part = &datoms[0];

        assert_eq!(asserted_e, &part.e);
        assert_eq!(numba_entity_id, &part.a);
        assert!(part.v.matches_type(ValueType::Long));
        assert_eq!(TypedValue::Long(123), part.v);
        assert_eq!(true, part.added);
    }
}
<commit_msg>Silence a warning in Tolstoy.<commit_after>// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

extern crate mentat;
extern crate mentat_core;
extern crate mentat_tolstoy;

use std::collections::BTreeMap;

use mentat::conn::Conn;

use mentat::new_connection;
use mentat_tolstoy::tx_processor::{
    Processor,
    TxReceiver,
    TxPart,
};
use mentat_tolstoy::errors::Result;
use mentat_core::{
    Entid,
    TypedValue,
    ValueType,
};

struct TxCountingReceiver {
    pub tx_count: usize,
    pub is_done: bool,
}

impl TxCountingReceiver {
    fn new() -> TxCountingReceiver {
        TxCountingReceiver {
            tx_count: 0,
            is_done: false,
        }
    }
}

impl TxReceiver for TxCountingReceiver {
    fn tx<T>(&mut self, _tx_id: Entid, _d: &mut T) -> Result<()>
        where T: Iterator<Item=TxPart> {
        self.tx_count = self.tx_count + 1;
        Ok(())
    }

    fn done(&mut self) -> Result<()> {
        self.is_done = true;
        Ok(())
    }
}

#[derive(Debug)]
struct TestingReceiver {
    pub txes: BTreeMap<Entid, Vec<TxPart>>,
    pub is_done: bool,
}

impl TestingReceiver {
    fn new() -> TestingReceiver {
        TestingReceiver {
            txes: BTreeMap::new(),
            is_done: false,
        }
    }
}

impl TxReceiver for TestingReceiver {
    fn tx<T>(&mut self, tx_id: Entid, d: &mut T) -> Result<()>
        where T: Iterator<Item=TxPart> {
        let datoms = self.txes.entry(tx_id).or_insert(vec![]);
        datoms.extend(d);
        Ok(())
    }

    fn done(&mut self) -> Result<()> {
        self.is_done = true;
        Ok(())
    }
}

fn assert_tx_datoms_count(receiver: &TestingReceiver, tx_num: usize, expected_datoms: usize) {
    let tx = receiver.txes.keys().nth(tx_num).expect("first tx");
    let datoms = receiver.txes.get(tx).expect("datoms");
    assert_eq!(expected_datoms, datoms.len());
}

#[test]
fn test_reader() {
    let mut c = new_connection("").expect("Couldn't open conn.");
    let mut conn = Conn::connect(&mut c).expect("Couldn't open DB.");
    {
        let db_tx = c.transaction().expect("db tx");
        // Don't inspect the bootstrap transaction, but we'd like to see it's there.
        let mut receiver = TxCountingReceiver::new();
        assert_eq!(false, receiver.is_done);
        Processor::process(&db_tx, None, &mut receiver).expect("processor");
        assert_eq!(true, receiver.is_done);
        assert_eq!(1, receiver.tx_count);
    }

    let ids = conn.transact(&mut c, r#"[
        [:db/add "s" :db/ident :foo/numba]
        [:db/add "s" :db/valueType :db.type/long]
        [:db/add "s" :db/cardinality :db.cardinality/one]
    ]"#).expect("successful transaction").tempids;
    let numba_entity_id = ids.get("s").unwrap();

    let bootstrap_tx;
    {
        let db_tx = c.transaction().expect("db tx");
        // Expect to see one more transaction of four parts (one for tx datom itself).
        let mut receiver = TestingReceiver::new();
        Processor::process(&db_tx, None, &mut receiver).expect("processor");

        println!("{:#?}", receiver);

        assert_eq!(2, receiver.txes.keys().count());
        assert_tx_datoms_count(&receiver, 1, 4);

        bootstrap_tx = Some(*receiver.txes.keys().nth(0).expect("bootstrap tx"));
    }

    let ids = conn.transact(&mut c, r#"[
        [:db/add "b" :foo/numba 123]
    ]"#).expect("successful transaction").tempids;
    let asserted_e = ids.get("b").unwrap();

    {
        let db_tx = c.transaction().expect("db tx");

        // Expect to see a single two part transaction
        let mut receiver = TestingReceiver::new();

        // Note that we're asking for the bootstrap tx to be skipped by the processor.
        Processor::process(&db_tx, bootstrap_tx, &mut receiver).expect("processor");

        assert_eq!(2, receiver.txes.keys().count());
        assert_tx_datoms_count(&receiver, 1, 2);

        // Inspect the transaction part.
        let tx_id = receiver.txes.keys().nth(1).expect("tx");
        let datoms = receiver.txes.get(tx_id).expect("datoms");
        let part = &datoms[0];

        assert_eq!(asserted_e, &part.e);
        assert_eq!(numba_entity_id, &part.a);
        assert!(part.v.matches_type(ValueType::Long));
        assert_eq!(TypedValue::Long(123), part.v);
        assert_eq!(true, part.added);
    }
}
<|endoftext|>