<commit_before>#![feature(test)]
#![cfg_attr(feature = "i128_support", feature(i128_type, i128))]

extern crate test;
extern crate rand;

const RAND_BENCH_N: u64 = 1000;

use std::mem::size_of;
use test::{black_box, Bencher};

use rand::{Rng, NewRng, XorShiftRng};
use rand::distributions::*;

macro_rules! distr_int {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = XorShiftRng::new();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0 as $ty;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum = accum.wrapping_add(x);
                }
                black_box(accum);
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr_float {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = XorShiftRng::new();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0.0;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum = accum + x;
                }
                black_box(accum);
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = XorShiftRng::new();
            let distr = $distr;

            b.iter(|| {
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    black_box(x);
                }
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

// range
distr_int!(distr_range_i8, i8, Range::new(20i8, 100));
distr_int!(distr_range_i16, i16, Range::new(-500i16, 2000));
distr_int!(distr_range_i32, i32, Range::new(-200_000_000i32, 800_000_000));
distr_int!(distr_range_i64, i64, Range::new(3i64, 12345678901234));
#[cfg(feature = "i128_support")]
distr_int!(distr_range_i128, i128, Range::new(-12345678901234i128, 12345678901234567890));

distr_float!(distr_range_f32, f32, Range::new(2.26f32, 2.319));
distr_float!(distr_range_f64, f64, Range::new(2.26f64, 2.319));

// uniform
distr_int!(distr_uniform_i8, i8, Uniform);
distr_int!(distr_uniform_i16, i16, Uniform);
distr_int!(distr_uniform_i32, i32, Uniform);
distr_int!(distr_uniform_i64, i64, Uniform);
#[cfg(feature = "i128_support")]
distr_int!(distr_uniform_i128, i128, Uniform);

distr!(distr_uniform_bool, bool, Uniform);
distr!(distr_uniform_alphanumeric, char, Alphanumeric);
distr!(distr_uniform_codepoint, char, Uniform);

distr_float!(distr_uniform_f32, f32, Uniform);
distr_float!(distr_uniform_f64, f64, Uniform);

// distributions
distr_float!(distr_exp, f64, Exp::new(2.71828 * 3.14159));
distr_float!(distr_normal, f64, Normal::new(-2.71828, 3.14159));
distr_float!(distr_log_normal, f64, LogNormal::new(-2.71828, 3.14159));
distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0));
distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0));
distr_int!(distr_binomial, u64, Binomial::new(20, 0.7));
distr_int!(distr_poisson, u64, Poisson::new(4.0));

// construct and sample from a range
macro_rules! gen_range_int {
    ($fnn:ident, $ty:ty, $low:expr, $high:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = XorShiftRng::new();
            let mut high = $high;
            let fake_increment = 0;

            b.iter(|| {
                let mut accum: $ty = 0;
                for _ in 0..::RAND_BENCH_N {
                    accum = accum.wrapping_add(rng.gen_range($low, high));
                    high += fake_increment;
                }
                black_box(accum);
                black_box(fake_increment);
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

gen_range_int!(gen_range_i8, i8, 20i8, 100);
gen_range_int!(gen_range_i16, i16, -500i16, 2000);
gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000);
gen_range_int!(gen_range_i64, i64, 3i64, 12345678901234);
#[cfg(feature = "i128_support")]
gen_range_int!(gen_range_i128, i128, -12345678901234i128, 12345678901234567890);
<commit_msg>Distribution benchmarks: further tweaks; improve range bench perf<commit_after>#![feature(test)]
#![cfg_attr(feature = "i128_support", feature(i128_type, i128))]

extern crate test;
extern crate rand;

const RAND_BENCH_N: u64 = 1000;

use std::mem::size_of;
use test::{black_box, Bencher};

use rand::{Rng, NewRng, XorShiftRng};
use rand::distributions::*;

macro_rules! distr_int {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = XorShiftRng::new();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0 as $ty;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum = accum.wrapping_add(x);
                }
                black_box(accum);
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr_float {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = XorShiftRng::new();
            let distr = $distr;

            b.iter(|| {
                let mut accum = 0.0;
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    accum = accum + x;
                }
                black_box(accum);
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

macro_rules! distr {
    ($fnn:ident, $ty:ty, $distr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = XorShiftRng::new();
            let distr = $distr;

            b.iter(|| {
                for _ in 0..::RAND_BENCH_N {
                    let x: $ty = distr.sample(&mut rng);
                    black_box(x);
                }
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

// range
distr_int!(distr_range_i8, i8, Range::new(20i8, 100));
distr_int!(distr_range_i16, i16, Range::new(-500i16, 2000));
distr_int!(distr_range_i32, i32, Range::new(-200_000_000i32, 800_000_000));
distr_int!(distr_range_i64, i64, Range::new(3i64, 12345678901234));
#[cfg(feature = "i128_support")]
distr_int!(distr_range_i128, i128, Range::new(-12345678901234i128, 12345678901234567890));

distr_float!(distr_range_f32, f32, Range::new(2.26f32, 2.319));
distr_float!(distr_range_f64, f64, Range::new(2.26f64, 2.319));

// uniform
distr_int!(distr_uniform_i8, i8, Uniform);
distr_int!(distr_uniform_i16, i16, Uniform);
distr_int!(distr_uniform_i32, i32, Uniform);
distr_int!(distr_uniform_i64, i64, Uniform);
#[cfg(feature = "i128_support")]
distr_int!(distr_uniform_i128, i128, Uniform);

distr!(distr_uniform_bool, bool, Uniform);
distr!(distr_uniform_alphanumeric, char, Alphanumeric);
distr!(distr_uniform_codepoint, char, Uniform);

distr_float!(distr_uniform_f32, f32, Uniform);
distr_float!(distr_uniform_f64, f64, Uniform);

// distributions
distr_float!(distr_exp, f64, Exp::new(2.71828 * 3.14159));
distr_float!(distr_normal, f64, Normal::new(-2.71828, 3.14159));
distr_float!(distr_log_normal, f64, LogNormal::new(-2.71828, 3.14159));
distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0));
distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0));
distr_int!(distr_binomial, u64, Binomial::new(20, 0.7));
distr_int!(distr_poisson, u64, Poisson::new(4.0));

// construct and sample from a range
macro_rules! gen_range_int {
    ($fnn:ident, $ty:ty, $low:expr, $high:expr, $incr:expr) => {
        #[bench]
        fn $fnn(b: &mut Bencher) {
            let mut rng = XorShiftRng::new();

            b.iter(|| {
                let mut high = $high;
                let mut accum: $ty = 0;
                for _ in 0..::RAND_BENCH_N {
                    accum = accum.wrapping_add(rng.gen_range($low, high));
                    high += $incr;  // force recalculation of range each time
                }
                black_box(accum);
            });
            b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
        }
    }
}

gen_range_int!(gen_range_i8, i8, 20i8, 100, 0);
gen_range_int!(gen_range_i16, i16, -500i16, 2000, 1);
gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000, 3);
gen_range_int!(gen_range_i64, i64, 3i64, 12345678901234, 3);
#[cfg(feature = "i128_support")]
gen_range_int!(gen_range_i128, i128, -12345678901234i128, 12345678901234567890, 3);
<|endoftext|>


<commit_before>extern crate libc;
extern crate rand;
use rand::Rng;
use rand::StdRng;
use rand::SeedableRng;
use std::ffi::{CString};

#[link(name = "ncurses")]
#[allow(dead_code)]
extern "C" {
    fn getpid() -> i32;
    fn initscr() -> *mut i8;
    fn noecho() -> i32;
    fn curs_set(c: i8) -> i32;
    fn halfdelay(tenths: i8) -> i32;
    #[link_name = "box"]
    fn box_(window: *mut i8, verch: i8, horch: i8);
    fn mvprintw(y: i16, x: i16, s: *const libc::c_char);
    fn getch() -> i8;
    fn endwin() -> libc::c_int;

    fn newwin(nlines: i16, ncols: i16, begin_y: i8, begin_x: i8) -> *mut i8;
    fn wclear(window: *mut i8) -> i8;
    fn wrefresh(window: *mut i8) -> i8;
    fn mvwprintw(window: *mut i8, y: i16, x: i16, s: *const libc::c_char);
    fn wgetch(window: *mut i8) -> i8;
    fn delwin(window: *mut i8) -> i8;
}

fn main() {
    unsafe {
        initscr();
        noecho();
        curs_set(0);
        halfdelay(3);

        let mut game = Game {
            width: 20,
            height: 10,
            snake: Snake {
                cells: vec![Cell { x: 4, y: 0 }, Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
                direction: Direction::Right,
            }
        };
        let window = newwin(game.height + 2, game.width + 2, 0, 0);

        let mut c = 0;
        while char::from(c as u8) != 'q' {

            game.draw(window);

            c = wgetch(window);
            let direction = match char::from(c as u8) {
                'i' => Some(Direction::Up),
                'j' => Some(Direction::Left),
                'k' => Some(Direction::Down),
                'l' => Some(Direction::Right),
                _ => Option::None
            };

            game = game.update(direction);
        }

        delwin(window);
        endwin();
    }
}

impl Game {
    fn draw(&self, window: *mut i8) {
        unsafe {
            wclear(window);
            box_(window, 0, 0);

            self.snake.tail().iter().for_each(|cell|
                mvwprintw(window, cell.y + 1, cell.x + 1, "o".to_c_str().as_ptr())
            );
            mvwprintw(window, self.snake.head().y + 1, self.snake.head().x + 1, "Q".to_c_str().as_ptr());

            if self.is_over() {
                mvwprintw(window, 0, 4, "Game is Over".to_c_str().as_ptr());
                mvwprintw(window, 1, 3, format!("Your score is {}", self.score()).as_str().to_c_str().as_ptr());
            }

            wrefresh(window);
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
struct Game {
    width: i16,
    height: i16,
    snake: Snake,
}

impl Game {
    fn is_over(&self) -> bool {
        self.snake.cells.iter().any(|&it| it.x < 0 || it.x >= self.width || it.y < 0 || it.y >= self.height) ||
        self.snake.tail().contains(self.snake.head())
    }

    fn score(&self) -> u8 {
        self.snake.cells.len() as u8
    }

    fn update(&self, direction: Option<Direction>) -> Game {
        if self.is_over() {
            return self.clone();
        }

        let new_snake;
        if direction.is_some() {
            new_snake = self.snake.turn_in(direction.unwrap()).slide();
        } else {
            new_snake = self.snake.slide();
        }
        return Game {
            width: self.width,
            height: self.height,
            snake: new_snake,
        };
    }
}

#[derive(Debug, PartialEq, Clone)]
struct Snake {
    cells: Vec<Cell>,
    direction: Direction,
}

impl Snake {
    fn head(&self) -> &Cell {
        &self.cells[0]
    }

    fn tail(&self) -> Vec<Cell> {
        self.cells[1..self.cells.len()].to_owned()
    }

    fn turn_in(&self, new_direction: Direction) -> Snake {
        if are_opposite(new_direction, self.direction) {
            self.clone()
        } else {
            Snake { cells: self.cells.clone(), direction: new_direction }
        }
    }

    fn slide(&self) -> Snake {
        let mut vec: Vec<Cell> = vec![self.cells.first().unwrap().move_in(&self.direction)];

        let mut new_cells = self.cells.clone();
        new_cells.pop();
        vec.append(&mut new_cells);

        Snake { cells: vec, direction: self.direction }
    }
}

#[derive(Debug, PartialEq, Clone)]
struct Apples {
    field_width: i16,
    field_height: i16,
    cells: Vec<Cell>,
    growth_speed: i16,
    rng: StdRng
}

impl Apples {
    fn grow(&self) -> Apples {

        return self.clone()
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
struct Cell {
    x: i16,
    y: i16,
}

impl Cell {
    fn move_in(&self, direction: &Direction) -> Cell {
        let dx = match direction {
            Direction::Up => 0,
            Direction::Down => 0,
            Direction::Left => -1,
            Direction::Right => 1,
        };
        let dy = match direction {
            Direction::Up => -1,
            Direction::Down => 1,
            Direction::Left => 0,
            Direction::Right => 0,
        };
        return Cell { x: self.x + dx, y: self.y + dy };
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn are_opposite(d1: Direction, d2: Direction) -> bool {
    if d1 == Direction::Up && d2 == Direction::Down { return true; }
    if d2 == Direction::Up && d1 == Direction::Down { return true; }
    if d1 == Direction::Left && d2 == Direction::Right { return true; }
    if d2 == Direction::Left && d1 == Direction::Right { return true; }
    false
}

trait ToCStr {
    fn to_c_str(&self) -> CString;
}

impl<'a> ToCStr for &'a str {
    fn to_c_str(&self) -> CString {
        CString::new(*self).unwrap()
    }
}

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

    #[test]
    fn snake_moves_right() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };

        assert_eq!(
            snake.slide(),
            Snake {
                cells: vec![Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Right,
            }
        )
    }

    #[test]
    fn snake_can_change_direction() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };

        assert_eq!(
            snake.turn_in(Direction::Down).slide(),
            Snake {
                cells: vec![Cell { x: 2, y: 1 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Down,
            }
        );
        assert_eq!(
            snake.turn_in(Direction::Left).slide(),
            Snake {
                cells: vec![Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Right,
            }
        );
    }

    #[test]
    fn game_is_over_when_snake_hits_border() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };
        let game = Game { width: 3, height: 1, snake };

        assert_eq!(game.is_over(), false);
        assert_eq!(game.update(None).is_over(), true);
        assert_eq!(game.update(Some(Direction::Down)).is_over(), true);
    }

    #[test]
    fn game_is_over_when_snake_bites_itself() {
        let snake = Snake {
            cells: vec![Cell { x: 0, y: 0 }, Cell { x: 0, y: 1 }, Cell { x: 1, y: 1 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };
        let game = Game { width: 100, height: 100, snake };

        assert_eq!(game.is_over(), true);
    }

    #[test]
    fn apples_grow_at_random_locations() {
        let seed = [
            1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5,
            1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2
        ];
        let rng: StdRng = StdRng::from_seed(seed);
        let apples = Apples {
            field_width: 20,
            field_height: 10,
            cells: vec![],
            growth_speed: 3,
            rng
        };

        assert_eq!(
            apples.grow().grow().grow().cells,
            vec![]
        );
    }
}<commit_msg>growing apples<commit_after>extern crate libc;
extern crate rand;
use rand::Rng;
use rand::ChaChaRng;
use rand::SeedableRng;
use std::ffi::{CString};

#[link(name = "ncurses")]
#[allow(dead_code)]
extern "C" {
    fn getpid() -> i32;
    fn initscr() -> *mut i8;
    fn noecho() -> i32;
    fn curs_set(c: i8) -> i32;
    fn halfdelay(tenths: i8) -> i32;
    #[link_name = "box"]
    fn box_(window: *mut i8, verch: i8, horch: i8);
    fn mvprintw(y: i16, x: i16, s: *const libc::c_char);
    fn getch() -> i8;
    fn endwin() -> libc::c_int;

    fn newwin(nlines: i16, ncols: i16, begin_y: i8, begin_x: i8) -> *mut i8;
    fn wclear(window: *mut i8) -> i8;
    fn wrefresh(window: *mut i8) -> i8;
    fn mvwprintw(window: *mut i8, y: i16, x: i16, s: *const libc::c_char);
    fn wgetch(window: *mut i8) -> i8;
    fn delwin(window: *mut i8) -> i8;
}

fn main() {
    unsafe {
        initscr();
        noecho();
        curs_set(0);
        halfdelay(3);

        let width = 20;
        let height = 10;
        let mut game = Game {
            width,
            height,
            snake: Snake {
                cells: vec![Cell { x: 4, y: 0 }, Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
                direction: Direction::Right,
            },
            apples: Apples::create(width, height)
        };
        let window = newwin(game.height + 2, game.width + 2, 0, 0);

        let mut c = 0;
        while char::from(c as u8) != 'q' {

            game.draw(window);

            c = wgetch(window);
            let direction = match char::from(c as u8) {
                'i' => Some(Direction::Up),
                'j' => Some(Direction::Left),
                'k' => Some(Direction::Down),
                'l' => Some(Direction::Right),
                _ => Option::None
            };

            game = game.update(direction);
        }

        delwin(window);
        endwin();
    }
}

impl Game {
    fn draw(&self, window: *mut i8) {
        unsafe {
            wclear(window);
            box_(window, 0, 0);

            self.apples.cells.iter().for_each(|cell|
                mvwprintw(window, cell.y + 1, cell.x + 1, ".".to_c_str().as_ptr())
            );
            self.snake.tail().iter().for_each(|cell|
                mvwprintw(window, cell.y + 1, cell.x + 1, "o".to_c_str().as_ptr())
            );
            mvwprintw(window, self.snake.head().y + 1, self.snake.head().x + 1, "Q".to_c_str().as_ptr());

            if self.is_over() {
                mvwprintw(window, 0, 4, "Game is Over".to_c_str().as_ptr());
                mvwprintw(window, 1, 3, format!("Your score is {}", self.score()).as_str().to_c_str().as_ptr());
            }

            wrefresh(window);
        }
    }
}

#[derive(Debug, Clone)]
struct Game {
    width: i16,
    height: i16,
    snake: Snake,
    apples: Apples
}

impl Game {
    fn is_over(&self) -> bool {
        self.snake.cells.iter().any(|&it| it.x < 0 || it.x >= self.width || it.y < 0 || it.y >= self.height) ||
        self.snake.tail().contains(self.snake.head())
    }

    fn score(&self) -> u8 {
        self.snake.cells.len() as u8
    }

    fn update(&self, direction: Option<Direction>) -> Game {
        if self.is_over() {
            return self.clone();
        }

        let new_snake;
        if direction.is_some() {
            new_snake = self.snake.turn_in(direction.unwrap()).slide();
        } else {
            new_snake = self.snake.slide();
        }

        let new_apples = self.apples.clone().grow().clone(); // TODO

        return Game {
            width: self.width,
            height: self.height,
            snake: new_snake,
            apples: new_apples
        };
    }
}

#[derive(Debug, PartialEq, Clone)]
struct Snake {
    cells: Vec<Cell>,
    direction: Direction,
}

impl Snake {
    fn head(&self) -> &Cell {
        &self.cells[0]
    }

    fn tail(&self) -> Vec<Cell> {
        self.cells[1..self.cells.len()].to_owned()
    }

    fn turn_in(&self, new_direction: Direction) -> Snake {
        if are_opposite(new_direction, self.direction) {
            self.clone()
        } else {
            Snake { cells: self.cells.clone(), direction: new_direction }
        }
    }

    fn slide(&self) -> Snake {
        let mut vec: Vec<Cell> = vec![self.cells.first().unwrap().move_in(&self.direction)];

        let mut new_cells = self.cells.clone();
        new_cells.pop();
        vec.append(&mut new_cells);

        Snake { cells: vec, direction: self.direction }
    }
}

#[derive(Debug, Clone)]
struct Apples {
    field_width: i16,
    field_height: i16,
    cells: Vec<Cell>,
    growth_speed: i16,
    rng: ChaChaRng
}

impl Apples {
    fn create(field_width: i16, field_height: i16) -> Apples {
        let apples = Apples {
            field_width,
            field_height,
            cells: vec![],
            growth_speed: 3,
            rng: ChaChaRng::new_unseeded()
        };
        return apples;
    }

    fn grow(&mut self) -> &mut Apples {
        let n = self.rng.gen_range(0, self.growth_speed);
        if n != 0 {
            return self
        }
        let cell = Cell {
            x: self.rng.gen_range(0, self.field_width),
            y: self.rng.gen_range(0, self.field_height)
        };
        self.cells.push(cell);

        return self;
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
struct Cell {
    x: i16,
    y: i16,
}

impl Cell {
    fn move_in(&self, direction: &Direction) -> Cell {
        let dx = match direction {
            Direction::Up => 0,
            Direction::Down => 0,
            Direction::Left => -1,
            Direction::Right => 1,
        };
        let dy = match direction {
            Direction::Up => -1,
            Direction::Down => 1,
            Direction::Left => 0,
            Direction::Right => 0,
        };
        return Cell { x: self.x + dx, y: self.y + dy };
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn are_opposite(d1: Direction, d2: Direction) -> bool {
    if d1 == Direction::Up && d2 == Direction::Down { return true; }
    if d2 == Direction::Up && d1 == Direction::Down { return true; }
    if d1 == Direction::Left && d2 == Direction::Right { return true; }
    if d2 == Direction::Left && d1 == Direction::Right { return true; }
    false
}

trait ToCStr {
    fn to_c_str(&self) -> CString;
}

impl<'a> ToCStr for &'a str {
    fn to_c_str(&self) -> CString {
        CString::new(*self).unwrap()
    }
}

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

    #[test]
    fn snake_moves_right() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };

        assert_eq!(
            snake.slide(),
            Snake {
                cells: vec![Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Right,
            }
        )
    }

    #[test]
    fn snake_can_change_direction() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };

        assert_eq!(
            snake.turn_in(Direction::Down).slide(),
            Snake {
                cells: vec![Cell { x: 2, y: 1 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Down,
            }
        );
        assert_eq!(
            snake.turn_in(Direction::Left).slide(),
            Snake {
                cells: vec![Cell { x: 3, y: 0 }, Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }],
                direction: Direction::Right,
            }
        );
    }

    #[test]
    fn game_is_over_when_snake_hits_border() {
        let snake = Snake {
            cells: vec![Cell { x: 2, y: 0 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };
        let game = Game { snake, width: 3, height: 1, apples: Apples::create(3, 1) };

        assert_eq!(game.is_over(), false);
        assert_eq!(game.update(None).is_over(), true);
        assert_eq!(game.update(Some(Direction::Down)).is_over(), true);
    }

    #[test]
    fn game_is_over_when_snake_bites_itself() {
        let snake = Snake {
            cells: vec![Cell { x: 0, y: 0 }, Cell { x: 0, y: 1 }, Cell { x: 1, y: 1 }, Cell { x: 1, y: 0 }, Cell { x: 0, y: 0 }],
            direction: Direction::Right,
        };
        let game = Game { snake, width: 100, height: 100, apples: Apples::create(3, 1) };

        assert_eq!(game.is_over(), true);
    }

    #[test]
    fn apples_grow_at_random_locations() {
        let seed = [
            1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5,
            1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2
        ];
        let rng = ChaChaRng::from_seed(seed);
        let mut apples = Apples {
            field_width: 20,
            field_height: 10,
            cells: vec![],
            growth_speed: 3,
            rng
        };

        assert_eq!(
            apples.grow().grow().grow().cells,
            vec![Cell { x: 7, y: 0 }]
        );
    }
}<|endoftext|>


<commit_before>//! Tools to define Rust components compatible with the COM protocol.
//!
//! Intercom provides attributes to automatically derive `extern` compatible
//! functions for Rust methods. These functions are compatible with COM binary
//! interface standard, which allows them to be used from any language that
//! supports COM.
//!
//! # Examples
//!
//! A basic example of a calculator type exposed as a COM object.
//!
//! ```
//! use intercom::{com_library, com_class, com_interface, com_impl, ComResult};
//!
//! // Define COM classes to expose from this library.
//! com_library!(Calculator);
//!
//! // Define the COM class and the interfaces it implements.
//! #[com_class(Calculator)]
//! struct Calculator;
//!
//! // Define the implementation for the class. The COM interface is defined
//! // implicitly by the `impl`.
//! #[com_interface]
//! #[com_impl]
//! impl Calculator {
//!
//!     // Intercom requires a `new` method with no parameters for all classes.
//! #   // TODO: This should be replaced with Default::default implementation.
//!     fn new() -> Calculator { Calculator }
//!
//!     fn add(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a + b) }
//!     fn sub(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a - b) }
//! }
//! # fn main() {}
//! ```
//!
//! The above library can be used for example from C# in the following manner.
//!
//! ```csharp
//! void Main()
//! {
//!     var calculator = new CalculatorLib.Calculator();
//!     Console.WriteLine( calculator.Add( 1, 2 ) );
//! }
//! ```

#![crate_type="dylib"]
#![feature(try_from, specialization, non_exhaustive, integer_atomics)]
#![allow(clippy::match_bool)]

#[cfg(not(windows))]
extern crate libc;

// The crate doesn't really need the macros. However Rust will complain that
// the import does nothing if we don't define #[macro_use]. Once we define
// #[macro_use] to get rid of that warning, Rust will complain that the
// #[macro_use] does nothing. Fortunately THAT warning comes with a named
// warning option so we can allow that explicitly.
//
// Unfortunately clippy disagrees on the macro_use being unused and claims that
// the unused_imports attribute is useless. So now we also need to tell clippy
// to ignore useless attributes in this scenario! \:D/
#[allow(clippy::useless_attribute)]
#[allow(unused_imports)]
extern crate intercom_attributes;
/// Foo
pub use intercom_attributes::*;

#[allow(clippy::useless_attribute)]
#[allow(unused_imports)]
#[macro_use] extern crate failure;

mod classfactory; pub use classfactory::*;
mod combox; pub use combox::*;
mod comrc; pub use comrc::*;
mod comitf; pub use comitf::*;
mod strings; pub use strings::*;
mod guid; pub use guid::GUID;
pub mod error; pub use error::{ComError, store_error, load_error, ErrorValue};
mod interfaces;
pub mod runtime;
pub mod alloc;
mod variant; pub use variant::{Variant, VariantError};

// intercom_attributes use "intercom::" to qualify things in this crate.
// Declare such module here and import everything we have in it to make those
// references valid.
mod intercom {
    pub use ::*;
}

/// The `ComInterface` trait defines the COM interface details for a COM
/// interface trait.
pub trait ComInterface {

    /// IID of the COM interface.
    fn iid( ts : TypeSystem ) -> Option< &'static IID >;

    /// Dereferences a `ComItf<T>` into a `&T`.
    ///
    /// While in most cases the user crate will implement `T` for `ComItf<T>`,
    /// this impl exists only in the user crate and cannot be used in generic
    /// contexts. For generic `ComItf<T>` use, Intercom ipmls `Deref<Target=T>`
    /// for `ComItf<T>` which requires this method.
    fn deref( com_itf : &ComItf<Self> ) -> &Self;
}

/// Raw COM pointer type.
pub type RawComPtr = *mut std::os::raw::c_void;

/// Interface ID GUID.
pub type IID = GUID;

/// A reference to an interface ID.
pub type REFIID = *const IID;

/// Class ID GUID.
pub type CLSID = GUID;

/// A reference to a class ID.
pub type REFCLSID = *const IID;

pub mod raw {
    pub type InBSTR = *const u16;
    pub type OutBSTR = *mut u16;

    pub type InCStr = *const ::std::os::raw::c_char;
    pub type OutCStr = *mut ::std::os::raw::c_char;

    pub use variant::raw::*;
    pub use error::raw::*;

    #[repr(C)]
    #[derive(PartialEq, Eq)]
    pub struct InterfacePtr<I: ?Sized> {
        pub ptr : super::RawComPtr,
        phantom : ::std::marker::PhantomData<I>,
    }

    impl<I: ?Sized> Clone for InterfacePtr<I>
    {
        fn clone( &self ) -> Self {
            InterfacePtr::new( self.ptr )
        }
    }

    impl<I: ?Sized> Copy for InterfacePtr<I> {}

    impl<I: ?Sized> std::fmt::Debug for InterfacePtr<I> {
        fn fmt( &self, f : &mut std::fmt::Formatter ) -> std::fmt::Result {
            write!( f, "InterfacePtr({:?})", self.ptr )
        }
    }

    impl<I: ?Sized> InterfacePtr<I> {
        pub fn new( ptr : super::RawComPtr ) -> InterfacePtr<I> {
            InterfacePtr { ptr, phantom: ::std::marker::PhantomData }
        }

        pub fn null() -> Self {
            Self::new( std::ptr::null_mut() )
        }

        pub fn is_null( self ) -> bool {
            self.ptr.is_null()
        }
    }

    impl<I: ::ComInterface + ?Sized> InterfacePtr<I> {
        pub fn as_unknown( self ) -> InterfacePtr<dyn (::IUnknown)> {
            InterfacePtr { ptr : self.ptr, phantom: ::std::marker::PhantomData }
        }
    }
}

/// `IClassFactory` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IClassFactory : GUID = GUID {
    data1: 0x0000_0001, data2: 0x0000, data3: 0x0000,
    data4: [ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 ]
};

/// `IErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IErrorInfo : GUID = GUID {
    data1: 0x1CF2_B120, data2: 0x547D, data3: 0x101B,
    data4: [ 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19 ]
};

pub use interfaces::__IUnknown_AutomationVtbl as IUnknownVtbl;
pub use interfaces::IID_IUnknown_Automation as IID_IUnknown;
pub use interfaces::IUnknown;

pub use interfaces::__ISupportErrorInfo_AutomationVtbl as ISupportErrorInfoVtbl;
pub use interfaces::IID_ISupportErrorInfo_Automation as IID_ISupportErrorInfo;
pub use interfaces::ISupportErrorInfo;

// Do we need this? Would rather not export this through an extern crate
// for another dll.
//
// com_library should have dllmain!() macro or similar that implements this
// together with the COM registration.
#[no_mangle]
#[allow(non_camel_case_types)]
#[deprecated]
#[doc(hidden)]
pub extern "stdcall" fn DllMain(
    _dll_instance : *mut std::os::raw::c_void,
    _reason : u32,
    _reserved : *mut std::os::raw::c_void ) -> bool
{
    true
}

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type ComResult<A> = Result<A, ComError>;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type RawComResult<A> = Result<A, raw::HRESULT>;

<commit_msg>try_from has been stabilized<commit_after>//! Tools to define Rust components compatible with the COM protocol.
//!
//! Intercom provides attributes to automatically derive `extern` compatible
//! functions for Rust methods. These functions are compatible with COM binary
//! interface standard, which allows them to be used from any language that
//! supports COM.
//!
//! # Examples
//!
//! A basic example of a calculator type exposed as a COM object.
//!
//! ```
//! use intercom::{com_library, com_class, com_interface, com_impl, ComResult};
//!
//! // Define COM classes to expose from this library.
//! com_library!(Calculator);
//!
//! // Define the COM class and the interfaces it implements.
//! #[com_class(Calculator)]
//! struct Calculator;
//!
//! // Define the implementation for the class. The COM interface is defined
//! // implicitly by the `impl`.
//! #[com_interface]
//! #[com_impl]
//! impl Calculator {
//!
//!     // Intercom requires a `new` method with no parameters for all classes.
//! #   // TODO: This should be replaced with Default::default implementation.
//!     fn new() -> Calculator { Calculator }
//!
//!     fn add(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a + b) }
//!     fn sub(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a - b) }
//! }
//! # fn main() {}
//! ```
//!
//! The above library can be used for example from C# in the following manner.
//!
//! ```csharp
//! void Main()
//! {
//!     var calculator = new CalculatorLib.Calculator();
//!     Console.WriteLine( calculator.Add( 1, 2 ) );
//! }
//! ```

#![crate_type="dylib"]
#![feature(specialization, non_exhaustive, integer_atomics)]
#![allow(clippy::match_bool)]

#[cfg(not(windows))]
extern crate libc;

// The crate doesn't really need the macros. However Rust will complain that
// the import does nothing if we don't define #[macro_use]. Once we define
// #[macro_use] to get rid of that warning, Rust will complain that the
// #[macro_use] does nothing. Fortunately THAT warning comes with a named
// warning option so we can allow that explicitly.
//
// Unfortunately clippy disagrees on the macro_use being unused and claims that
// the unused_imports attribute is useless. So now we also need to tell clippy
// to ignore useless attributes in this scenario! \:D/
#[allow(clippy::useless_attribute)]
#[allow(unused_imports)]
extern crate intercom_attributes;
/// Foo
pub use intercom_attributes::*;

#[allow(clippy::useless_attribute)]
#[allow(unused_imports)]
#[macro_use] extern crate failure;

mod classfactory; pub use classfactory::*;
mod combox; pub use combox::*;
mod comrc; pub use comrc::*;
mod comitf; pub use comitf::*;
mod strings; pub use strings::*;
mod guid; pub use guid::GUID;
pub mod error; pub use error::{ComError, store_error, load_error, ErrorValue};
mod interfaces;
pub mod runtime;
pub mod alloc;
mod variant; pub use variant::{Variant, VariantError};

// intercom_attributes use "intercom::" to qualify things in this crate.
// Declare such module here and import everything we have in it to make those
// references valid.
mod intercom {
    pub use ::*;
}

/// The `ComInterface` trait defines the COM interface details for a COM
/// interface trait.
pub trait ComInterface {

    /// IID of the COM interface.
    fn iid( ts : TypeSystem ) -> Option< &'static IID >;

    /// Dereferences a `ComItf<T>` into a `&T`.
    ///
    /// While in most cases the user crate will implement `T` for `ComItf<T>`,
    /// this impl exists only in the user crate and cannot be used in generic
    /// contexts. For generic `ComItf<T>` use, Intercom ipmls `Deref<Target=T>`
    /// for `ComItf<T>` which requires this method.
    fn deref( com_itf : &ComItf<Self> ) -> &Self;
}

/// Raw COM pointer type.
pub type RawComPtr = *mut std::os::raw::c_void;

/// Interface ID GUID.
pub type IID = GUID;

/// A reference to an interface ID.
pub type REFIID = *const IID;

/// Class ID GUID.
pub type CLSID = GUID;

/// A reference to a class ID.
pub type REFCLSID = *const IID;

pub mod raw {
    pub type InBSTR = *const u16;
    pub type OutBSTR = *mut u16;

    pub type InCStr = *const ::std::os::raw::c_char;
    pub type OutCStr = *mut ::std::os::raw::c_char;

    pub use variant::raw::*;
    pub use error::raw::*;

    #[repr(C)]
    #[derive(PartialEq, Eq)]
    pub struct InterfacePtr<I: ?Sized> {
        pub ptr : super::RawComPtr,
        phantom : ::std::marker::PhantomData<I>,
    }

    impl<I: ?Sized> Clone for InterfacePtr<I>
    {
        fn clone( &self ) -> Self {
            InterfacePtr::new( self.ptr )
        }
    }

    impl<I: ?Sized> Copy for InterfacePtr<I> {}

    impl<I: ?Sized> std::fmt::Debug for InterfacePtr<I> {
        fn fmt( &self, f : &mut std::fmt::Formatter ) -> std::fmt::Result {
            write!( f, "InterfacePtr({:?})", self.ptr )
        }
    }

    impl<I: ?Sized> InterfacePtr<I> {
        pub fn new( ptr : super::RawComPtr ) -> InterfacePtr<I> {
            InterfacePtr { ptr, phantom: ::std::marker::PhantomData }
        }

        pub fn null() -> Self {
            Self::new( std::ptr::null_mut() )
        }

        pub fn is_null( self ) -> bool {
            self.ptr.is_null()
        }
    }

    impl<I: ::ComInterface + ?Sized> InterfacePtr<I> {
        pub fn as_unknown( self ) -> InterfacePtr<dyn (::IUnknown)> {
            InterfacePtr { ptr : self.ptr, phantom: ::std::marker::PhantomData }
        }
    }
}

/// `IClassFactory` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IClassFactory : GUID = GUID {
    data1: 0x0000_0001, data2: 0x0000, data3: 0x0000,
    data4: [ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 ]
};

/// `IErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IErrorInfo : GUID = GUID {
    data1: 0x1CF2_B120, data2: 0x547D, data3: 0x101B,
    data4: [ 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19 ]
};

pub use interfaces::__IUnknown_AutomationVtbl as IUnknownVtbl;
pub use interfaces::IID_IUnknown_Automation as IID_IUnknown;
pub use interfaces::IUnknown;

pub use interfaces::__ISupportErrorInfo_AutomationVtbl as ISupportErrorInfoVtbl;
pub use interfaces::IID_ISupportErrorInfo_Automation as IID_ISupportErrorInfo;
pub use interfaces::ISupportErrorInfo;

// Do we need this? Would rather not export this through an extern crate
// for another dll.
//
// com_library should have dllmain!() macro or similar that implements this
// together with the COM registration.
#[no_mangle]
#[allow(non_camel_case_types)]
#[deprecated]
#[doc(hidden)]
pub extern "stdcall" fn DllMain(
    _dll_instance : *mut std::os::raw::c_void,
    _reason : u32,
    _reserved : *mut std::os::raw::c_void ) -> bool
{
    true
}

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type ComResult<A> = Result<A, ComError>;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type RawComResult<A> = Result<A, raw::HRESULT>;

<|endoftext|>


<commit_before>mod ident;
mod variable;
mod operator;
mod item;

use std::ops;

pub use ast::ident::*;
pub use ast::variable::*;
pub use ast::operator::*;
pub use ast::item::{Item, Value};

pub type Index = usize;

#[derive(Debug, PartialEq)]
pub struct Node {
    pub start: usize,
    pub end: usize,
    pub item: Item,
    pub next: Option<Index>,
}

pub struct Store(Vec<Node>);

pub struct List<'store> {
    next: Option<Index>,
    store: &'store Store,
}

pub struct Program<'src> {
    pub source: &'src str,
    pub root: Option<Index>,
    pub items: Store,
}

impl Node {
    #[inline]
    pub fn new(start: usize, end: usize, item: Item) -> Self {
        Node {
            start: start,
            end: end,
            item: item,
            next: None
        }
    }
}

impl Store {
    #[inline]
    pub fn new() -> Self {
        Store(Vec::new())
    }

    #[inline]
    pub fn insert(&mut self, node: Node) -> usize {
        let index = self.len();
        self.0.push(node);
        index
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.0.len()
    }

    #[inline]
    pub fn list(&self, from: Index) -> List {
        List {
            store: &self,
            next: if self.len() > from { Some(from) } else { None },
        }
    }
}

impl<'store, 'src: 'store> Program<'src> {
    #[inline]
    pub fn statements(&'src self) -> List<'store> {
        List {
            store: &self.items,
            next: self.root,
        }
    }
}

impl ops::Index<usize> for Store {
    type Output = Node;

    #[inline]
    fn index(&self, index: usize) -> &Node {
        &self.0[index]
    }
}

impl ops::IndexMut<usize> for Store {
    #[inline]
    fn index_mut(&mut self, index: usize) -> &mut Node {
        &mut self.0[index]
    }
}

impl<'store> Iterator for List<'store> {
    type Item = &'store Item;

    #[inline]
    fn next(&mut self) -> Option<&'store Item> {
        let next = self.next;

        next.map(|id| {
            let node = &self.store[id];
            self.next = node.next;
            &node.item
        })
    }
}
<commit_msg>no allocation<commit_after>mod ident;
mod variable;
mod operator;
mod item;

use std::ops;

pub use ast::ident::*;
pub use ast::variable::*;
pub use ast::operator::*;
pub use ast::item::{Item, Value};

pub type Index = usize;

#[derive(Debug, PartialEq)]
pub struct Node {
    pub start: usize,
    pub end: usize,
    pub item: Item,
    pub next: Option<Index>,
}

pub struct Store(Vec<Node>);

pub struct List<'store> {
    next: Option<Index>,
    store: &'store Store,
}

pub struct Program<'src> {
    pub source: &'src str,
    pub root: Option<Index>,
    pub items: Store,
}

impl Node {
    #[inline]
    pub fn new(start: usize, end: usize, item: Item) -> Self {
        Node {
            start: start,
            end: end,
            item: item,
            next: None
        }
    }
}

impl Store {
    #[inline]
    pub fn new() -> Self {
        Store(Vec::with_capacity(128))
    }

    #[inline]
    pub fn insert(&mut self, node: Node) -> usize {
        let index = self.len();
        self.0.push(node);
        index
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.0.len()
    }

    #[inline]
    pub fn list(&self, from: Index) -> List {
        List {
            store: &self,
            next: if self.len() > from { Some(from) } else { None },
        }
    }
}

impl<'store, 'src: 'store> Program<'src> {
    #[inline]
    pub fn statements(&'src self) -> List<'store> {
        List {
            store: &self.items,
            next: self.root,
        }
    }
}

impl ops::Index<usize> for Store {
    type Output = Node;

    #[inline]
    fn index(&self, index: usize) -> &Node {
        &self.0[index]
    }
}

impl ops::IndexMut<usize> for Store {
    #[inline]
    fn index_mut(&mut self, index: usize) -> &mut Node {
        &mut self.0[index]
    }
}

impl<'store> Iterator for List<'store> {
    type Item = &'store Item;

    #[inline]
    fn next(&mut self) -> Option<&'store Item> {
        let next = self.next;

        next.map(|id| {
            let node = &self.store[id];
            self.next = node.next;
            &node.item
        })
    }
}
<|endoftext|>


<commit_before>extern crate crypto;

use crypto::md5::Md5;
use crypto::digest::Digest;

// Coordinates and current path
type State = (u8, u8, String);
const INPUT: &'static str = "hhhxzeay";

fn main() {
    let mut hasher = Md5::new();
    let mut md5 = |text: &str| {
        hasher.reset();
        hasher.input_str(&format!("{}{}", INPUT, text));
        hasher.result_str()
    };

    let open = |chr: char| chr.is_alphabetic() && chr != 'a';

    let mut open_doors = |path: &str| {
        let hash = md5(path);
        let doors = hash.chars().take(4).collect::<Vec<_>>();
        (open(doors[0]), open(doors[1]), open(doors[2]), open(doors[3]))
    };

    let start: State = (0, 0, "".into());

    let mut states = vec![start];

    loop {
        let mut new_states = Vec::new();
        for (x, y, path) in states {
            let (up, down, left, right) = open_doors(&path);
            if up && y != 0 {
                let mut p = path.clone();
                p.push('U');
                let s = (x, y - 1, p);
                new_states.push(s);
            }
            if down && y != 3 {
                let mut p = path.clone();
                p.push('D');
                let s = (x, y + 1, p);
                new_states.push(s);
            }
            if left && x != 0 {
                let mut p = path.clone();
                p.push('L');
                let s = (x - 1, y, p);
                new_states.push(s);
            }
            if right && x != 3 {
                let mut p = path.clone();
                p.push('R');
                let s = (x + 1, y, p);
                new_states.push(s);
            }
        }
        for &(x, y, ref p) in &new_states {
            if  x == 3 && y == 3 {
                println!("part 1: {}", p);
                return;
            }
        }
        states = new_states;
    }
}
<commit_msg>rust day17 part2<commit_after>extern crate crypto;

use crypto::md5::Md5;
use crypto::digest::Digest;

// Coordinates and current path
type State = (u8, u8, String);
const INPUT: &'static str = "hhhxzeay";

fn main() {
    let mut hasher = Md5::new();
    let mut md5 = |text: &str| {
        hasher.reset();
        hasher.input_str(&format!("{}{}", INPUT, text));
        hasher.result_str()
    };

    let open = |chr: char| chr.is_alphabetic() && chr != 'a';

    let mut open_doors = |path: &str| {
        let hash = md5(path);
        let doors = hash.chars().take(4).collect::<Vec<_>>();
        (open(doors[0]), open(doors[1]), open(doors[2]), open(doors[3]))
    };

    let start: State = (0, 0, "".into());

    let mut states = vec![start];
    let mut wins = Vec::<String>::new();

    loop {
        let mut new_states = Vec::new();
        for (x, y, path) in states {
            let (up, down, left, right) = open_doors(&path);
            if up && y != 0 {
                let mut p = path.clone();
                p.push('U');
                let s = (x, y - 1, p);
                new_states.push(s);
            }
            if down && y != 3 {
                let mut p = path.clone();
                p.push('D');
                let s = (x, y + 1, p);
                new_states.push(s);
            }
            if left && x != 0 {
                let mut p = path.clone();
                p.push('L');
                let s = (x - 1, y, p);
                new_states.push(s);
            }
            if right && x != 3 {
                let mut p = path.clone();
                p.push('R');
                let s = (x + 1, y, p);
                new_states.push(s);
            }
        }
        for &(x, y, ref p) in &new_states {
            if  x == 3 && y == 3 {
                wins.push(p.clone());
            }
        }
        states = new_states.into_iter().filter(|&(x, y, _)| !(x == 3 && y == 3)).collect();
        if states.is_empty() {
            break;
        }
    }

    println!("part 1: {}", wins[0]);
    println!("part 2: {}", wins.iter().max_by_key(|p| p.len()).unwrap().len());
}
<|endoftext|>


<commit_before>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String)
}

enum Opcode {
    Text = 0x1
}

struct Message {
    payload: Payload,
    opcode: Opcode
}

impl Message {
    fn from_str (msg: &[u8]) {

    }
}

fn get_header_by_name (header: &[u8], headers: Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.into_iter() {
        if h.key.as_bytes() == header {
            // XXX: maybe we shouldn't own headers and should .clone() here
            result = h.value;
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    println!("key: {}, value: {}", lhs.trim(), rhs.trim());

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    println!("{} {}", sha.result_str(), out.to_base64(STANDARD));

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {
    println!("running ws_handshake");

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes().as_slice()).unwrap();
    stream.write(b"\r\n");

    stream.write_u8(0b1000_0000 | Opcode::Text as u8).unwrap();
    stream.write_u8(0b0000_0001).unwrap();
    stream.write(b"h");
}

fn main () {

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            println!("{}", cur_line);
            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("../html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("../html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.into_bytes().as_slice()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.into_bytes().as_slice()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<commit_msg>add message send to function<commit_after>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String)
}

enum Opcode {
    Text = 0x1
}

struct Message {
    payload: Payload,
    opcode: Opcode
}

impl Message {
    fn from_str (msg: &[u8]) {

    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            // XXX: maybe we shouldn't own headers and should .clone() here
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    println!("key: {}, value: {}", lhs.trim(), rhs.trim());

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    println!("{} {}", sha.result_str(), out.to_base64(STANDARD));

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {
    println!("running ws_handshake");

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes().as_slice()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             headers: Vec<ClientHeader>) {
    stream.write_u8(0b1000_0000 | Opcode::Text as u8).unwrap();
    stream.write_u8(0b0000_0001).unwrap();
    stream.write(b"h");
}

fn main () {

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            println!("{}", cur_line);
            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("../html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("../html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.into_bytes().as_slice()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.into_bytes().as_slice()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<|endoftext|>


<commit_before>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;
use std::vec::Vec;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Binary(Vec<u8>),
    Empty
}

#[deriving(FromPrimitive)]
enum Opcode {
    EmptyOp = 0x0,
    TextOp = 0x1,
    BinaryOp = 0x2,
    CloseOp = 0x8,
}

struct Message {
    payload: Payload,
    opcode: Opcode,
    fin: u8
 }

impl Message {

    fn from_payload (payload: Payload, fin: u8) -> Message {
        let opcode: Opcode = match payload {
            Payload::Text(_) => Opcode::TextOp,
            Payload::Binary(_) => Opcode::BinaryOp,
            Payload::Empty => Opcode::EmptyOp
        };
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn continue_from_payload (payload: Payload) -> Message {
        let opcode = Opcode::EmptyOp;
        let fin = 0x0;
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn send (&self,
            mut stream: &mut BufferedStream<TcpStream>) {
        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Binary(ref s) => s.as_slice(),
            Payload::Empty => "".as_bytes(),
        };

        let length = msg.len() as u8;

        println!("fin: {}, msg: {}, opcode: {}", self.fin, msg, self.opcode as u8);

        stream.write_u8(self.fin | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();
        stream.flush();
    }

    fn from_stream(mut stream: &mut BufferedStream<TcpStream>) -> Message {
        let cur_byte: u8 = stream.read_byte().unwrap();

        let fin = cur_byte & 0b1000_0000;
        let rsv = cur_byte & 0b0111_0000;
        let opc = cur_byte & 0b0000_1111;
        let msk = cur_byte & 0b0000_0001;

        let cur_byte: u8 = stream.read_byte().unwrap();
        let len = (cur_byte & 0b0111_1111) as uint;

        let mskkey = stream.read_exact(4).unwrap();

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let cur_byte: u8 = stream.read_byte().unwrap();
            let ch = mskkey[ii % 4] ^ cur_byte;
            msg.push(ch);
        }

        /*
        let utf8_msg = match String::from_utf8(msg) {
            Ok(ref m) => m,
            Err(_) => panic!("I don't know how to ut8 that")
        };
         */

        let opcode: Opcode = FromPrimitive::from_u8(opc).expect("unknown opcode");

        let payload = match opcode {
            Opcode::TextOp => Payload::Text(String::from_utf8(msg).unwrap()),
            Opcode::BinaryOp => Payload::Binary(msg),
            _ => panic!("unknown payload")
        };

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}",
            fin, rsv, msk, opc, len, mskkey);

        return Message::from_payload(payload, fin);
    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    // from rfc6455 [page 6]
    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             mut headers: Vec<ClientHeader>) {

    let payload = Payload::Text("text ".to_string());
    let msg = Message::from_payload(payload, 0b0000_0000);
    msg.send(&mut stream);

    let payload = Payload::Text("here".to_string());
    let msg = Message::continue_from_payload(payload);
    msg.send(&mut stream);

    let payload = Payload::Empty;
    let msg = Message::from_payload(payload, 0b1000_0000);
    msg.send(&mut stream);

    println!("done sending");

    Message::from_stream(&mut stream);

    let echo_msg = Message::from_stream(&mut stream);

    echo_msg.send(&mut stream);
    echo_msg.send(&mut stream);

    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);

    let echo_msg = Message::from_stream(&mut stream);
    echo_msg.send(&mut stream);

}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("./html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("./html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.as_bytes()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.as_bytes()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<commit_msg>make payload fmt::Show::fmt<commit_after>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;
use std::vec::Vec;
use std::fmt;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Binary(Vec<u8>),
    Empty
}

#[deriving(FromPrimitive)]
enum Opcode {
    EmptyOp = 0x0,
    TextOp = 0x1,
    BinaryOp = 0x2,
    CloseOp = 0x8,
}

struct Message {
    payload: Payload,
    opcode: Opcode,
    fin: u8
 }

impl fmt::Show for Payload {

     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let msg = match self {
             &Payload::Text(ref s) => s.as_bytes(),
             &Payload::Binary(ref s) => s.as_slice(),
             &Payload::Empty => "".as_bytes(),
         };
         write!(f, "{}", msg)
     }
}

impl Message {

    fn from_payload (payload: Payload, fin: u8) -> Message {
        let opcode: Opcode = match payload {
            Payload::Text(_) => Opcode::TextOp,
            Payload::Binary(_) => Opcode::BinaryOp,
            Payload::Empty => Opcode::EmptyOp
        };
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn continue_from_payload (payload: Payload) -> Message {
        let opcode = Opcode::EmptyOp;
        let fin = 0x0;
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn send (&self,
            mut stream: &mut BufferedStream<TcpStream>) {
        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Binary(ref s) => s.as_slice(),
            Payload::Empty => "".as_bytes(),
        };

        let length = msg.len() as u8;

        println!("fin: {}, msg: {}, opcode: {}", self.fin, msg, self.opcode as u8);

        stream.write_u8(self.fin | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();
        stream.flush();
    }

    fn from_stream(mut stream: &mut BufferedStream<TcpStream>) -> Message {
        let cur_byte: u8 = stream.read_byte().unwrap();

        let fin = cur_byte & 0b1000_0000;
        let rsv = cur_byte & 0b0111_0000;
        let opc = cur_byte & 0b0000_1111;
        let msk = cur_byte & 0b0000_0001;

        let cur_byte: u8 = stream.read_byte().unwrap();
        let len = (cur_byte & 0b0111_1111) as uint;

        let mskkey = stream.read_exact(4).unwrap();

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let cur_byte: u8 = stream.read_byte().unwrap();
            let ch = mskkey[ii % 4] ^ cur_byte;
            msg.push(ch);
        }

        /*
        let utf8_msg = match String::from_utf8(msg) {
            Ok(ref m) => m,
            Err(_) => panic!("I don't know how to ut8 that")
        };
         */

        let opcode: Opcode = FromPrimitive::from_u8(opc).expect("unknown opcode");

        let payload = match opcode {
            Opcode::TextOp => Payload::Text(String::from_utf8(msg).unwrap()),
            Opcode::BinaryOp => Payload::Binary(msg),
            _ => panic!("unknown payload")
        };

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, payload {}",
            fin, rsv, msk, opc, len, mskkey, payload);

        return Message::from_payload(payload, fin);
    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    // from rfc6455 [page 6]
    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             mut headers: Vec<ClientHeader>) {

    let payload = Payload::Text("text ".to_string());
    let msg = Message::from_payload(payload, 0b0000_0000);
    msg.send(&mut stream);

    let payload = Payload::Text("here".to_string());
    let msg = Message::continue_from_payload(payload);
    msg.send(&mut stream);

    let payload = Payload::Empty;
    let msg = Message::from_payload(payload, 0b1000_0000);
    msg.send(&mut stream);

    println!("done sending");

    Message::from_stream(&mut stream);

    let echo_msg = Message::from_stream(&mut stream);

    echo_msg.send(&mut stream);
    echo_msg.send(&mut stream);

    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);

    let echo_msg = Message::from_stream(&mut stream);
    echo_msg.send(&mut stream);

}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("./html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("./html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.as_bytes()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.as_bytes()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<|endoftext|>


<commit_before>//! The SMTP transport sends emails using the SMTP protocol.
//!
//! This SMTP client follows [RFC
//! 5321](https://tools.ietf.org/html/rfc5321), and is designed to efficiently send emails from an
//! application to a relay email server, as it relies as much as possible on the relay server
//! for sanity and RFC compliance checks.
//!
//! It implements the following extensions:
//!
//! * 8BITMIME ([RFC 6152](https://tools.ietf.org/html/rfc6152))
//! * AUTH ([RFC 4954](https://tools.ietf.org/html/rfc4954)) with PLAIN, LOGIN and XOAUTH2 mechanisms
//! * STARTTLS ([RFC 2487](https://tools.ietf.org/html/rfc2487))
//!
//! #### SMTP Transport
//!
//! This transport uses the SMTP protocol to send emails over the network (locally or remotely).
//!
//! It is designed to be:
//!
//! * Secured: emails are encrypted by default
//! * Modern: unicode support for email contents and sender/recipient addresses when compatible
//! * Fast: supports connection reuse and pooling
//!
//! This client is designed to send emails to a relay server, and should *not* be used to send
//! emails directly to the destination server.
//!
//! The relay server can be the local email server, a specific host or a third-party service.
//!
//! #### Simple example
//!
//! This is the most basic example of usage:
//!
//! ```rust,no_run
//! # #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
//! # {
//! use lettre::{Message, Transport, SmtpTransport};
//!
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse().unwrap())
//!     .reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
//!     .to("Hei <hei@domain.tld>".parse().unwrap())
//!     .subject("Happy new year")
//!     .body("Be happy!")
//!     .unwrap();
//!
//! // Create TLS transport on port 465
//! let sender = SmtpTransport::relay("smtp.example.com")
//!     .expect("relay valid")
//!     .build();
//! // Send the email via remote relay
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! # }
//! ```

use std::time::Duration;

#[cfg(feature = "tokio02")]
pub use self::async_transport::{
    AsyncSmtpConnector, AsyncSmtpTransport, AsyncSmtpTransportBuilder, Tokio02Connector,
};
pub(crate) use self::transport::SmtpClient;
pub use self::transport::{SmtpTransport, SmtpTransportBuilder};
#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
use crate::transport::smtp::client::TlsParameters;
use crate::transport::smtp::{
    authentication::{Credentials, Mechanism, DEFAULT_MECHANISMS},
    client::SmtpConnection,
    extension::ClientId,
    response::Response,
};
use client::Tls;

#[cfg(feature = "tokio02")]
mod async_transport;
pub mod authentication;
pub mod client;
pub mod commands;
mod error;
pub mod extension;
#[cfg(feature = "r2d2")]
pub mod pool;
pub mod response;
mod transport;
pub mod util;

// Registered port numbers:
// https://www.iana.
// org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml

/// Default smtp port
pub const SMTP_PORT: u16 = 25;
/// Default submission port
pub const SUBMISSION_PORT: u16 = 587;
/// Default submission over TLS port
///
/// https://tools.ietf.org/html/rfc8314
pub const SUBMISSIONS_PORT: u16 = 465;

/// Default timeout
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);

#[allow(missing_debug_implementations)]
#[derive(Clone)]
struct SmtpInfo {
    /// Name sent during EHLO
    hello_name: ClientId,
    /// Server we are connecting to
    server: String,
    /// Port to connect to
    port: u16,
    /// TLS security configuration
    tls: Tls,
    /// Optional enforced authentication mechanism
    authentication: Vec<Mechanism>,
    /// Credentials
    credentials: Option<Credentials>,
    /// Define network timeout
    /// It can be changed later for specific needs (like a different timeout for each SMTP command)
    timeout: Option<Duration>,
}

impl Default for SmtpInfo {
    fn default() -> Self {
        Self {
            server: "localhost".to_string(),
            port: SMTP_PORT,
            hello_name: ClientId::default(),
            credentials: None,
            authentication: DEFAULT_MECHANISMS.into(),
            timeout: Some(DEFAULT_TIMEOUT),
            tls: Tls::None,
        }
    }
}
<commit_msg>Improve documentation<commit_after>//! The SMTP transport sends emails using the SMTP protocol.
//!
//! This SMTP client follows [RFC
//! 5321](https://tools.ietf.org/html/rfc5321), and is designed to efficiently send emails from an
//! application to a relay email server, as it relies as much as possible on the relay server
//! for sanity and RFC compliance checks.
//!
//! It implements the following extensions:
//!
//! * 8BITMIME ([RFC 6152](https://tools.ietf.org/html/rfc6152))
//! * AUTH ([RFC 4954](https://tools.ietf.org/html/rfc4954)) with PLAIN, LOGIN and XOAUTH2 mechanisms
//! * STARTTLS ([RFC 2487](https://tools.ietf.org/html/rfc2487))
//!
//! #### SMTP Transport
//!
//! This transport uses the SMTP protocol to send emails over the network (locally or remotely).
//!
//! It is designed to be:
//!
//! * Secured: connections are encrypted by default
//! * Modern: unicode support for email contents and sender/recipient addresses when compatible
//! * Fast: supports connection reuse and pooling
//!
//! This client is designed to send emails to a relay server, and should *not* be used to send
//! emails directly to the destination server.
//!
//! The relay server can be the local email server, a specific host or a third-party service.
//!
//! #### Simple example
//!
//! This is the most basic example of usage:
//!
//! ```rust,no_run
//! # #[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
//! # {
//! use lettre::{Message, Transport, SmtpTransport};
//!
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse().unwrap())
//!     .reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
//!     .to("Hei <hei@domain.tld>".parse().unwrap())
//!     .subject("Happy new year")
//!     .body("Be happy!")
//!     .unwrap();
//!
//! // Create TLS transport on port 465
//! let sender = SmtpTransport::relay("smtp.example.com")
//!     .expect("relay valid")
//!     .build();
//! // Send the email via remote relay
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! # }
//! ```

use std::time::Duration;

#[cfg(feature = "tokio02")]
pub use self::async_transport::{
    AsyncSmtpConnector, AsyncSmtpTransport, AsyncSmtpTransportBuilder, Tokio02Connector,
};
pub(crate) use self::transport::SmtpClient;
pub use self::transport::{SmtpTransport, SmtpTransportBuilder};
#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]
use crate::transport::smtp::client::TlsParameters;
use crate::transport::smtp::{
    authentication::{Credentials, Mechanism, DEFAULT_MECHANISMS},
    client::SmtpConnection,
    extension::ClientId,
    response::Response,
};
use client::Tls;

#[cfg(feature = "tokio02")]
mod async_transport;
pub mod authentication;
pub mod client;
pub mod commands;
mod error;
pub mod extension;
#[cfg(feature = "r2d2")]
pub mod pool;
pub mod response;
mod transport;
pub mod util;

// Registered port numbers:
// https://www.iana.
// org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml

/// Default smtp port
pub const SMTP_PORT: u16 = 25;
/// Default submission port
pub const SUBMISSION_PORT: u16 = 587;
/// Default submission over TLS port
///
/// https://tools.ietf.org/html/rfc8314
pub const SUBMISSIONS_PORT: u16 = 465;

/// Default timeout
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);

#[allow(missing_debug_implementations)]
#[derive(Clone)]
struct SmtpInfo {
    /// Name sent during EHLO
    hello_name: ClientId,
    /// Server we are connecting to
    server: String,
    /// Port to connect to
    port: u16,
    /// TLS security configuration
    tls: Tls,
    /// Optional enforced authentication mechanism
    authentication: Vec<Mechanism>,
    /// Credentials
    credentials: Option<Credentials>,
    /// Define network timeout
    /// It can be changed later for specific needs (like a different timeout for each SMTP command)
    timeout: Option<Duration>,
}

impl Default for SmtpInfo {
    fn default() -> Self {
        Self {
            server: "localhost".to_string(),
            port: SMTP_PORT,
            hello_name: ClientId::default(),
            credentials: None,
            authentication: DEFAULT_MECHANISMS.into(),
            timeout: Some(DEFAULT_TIMEOUT),
            tls: Tls::None,
        }
    }
}
<|endoftext|>